/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "common/bitarray.h"
#include "common/events.h"
#include "common/savefile.h"
#include "hypno/hypno.h"
#include "engines/metaengine.h"
#include "engines/savestate.h"
namespace Hypno {
static const char *failedDetectionError = \
"Failed to load any files from missions.lib.\
Please review https://wiki.scummvm.org/index.php?title=Wetlands\
and re-add the game.";
static const chapterEntry rawChapterTable[] = {
{11, {44, 172}, {218, 172}, {0, 0}, {127, 172}, 0, kHypnoColorRed}, // c11
{10, {19, 3}, {246, 3}, {246, 11}, {2, 2}, 0, kHypnoNoColor}, // c10
{21, {70, 160}, {180, 160}, {220, 185}, {44, 162}, 215, kHypnoColorYellow}, // c21
{22, {70, 160}, {180, 160}, {220, 185}, {44, 162}, 215, kHypnoColorGreen}, // c22
{23, {70, 160}, {180, 160}, {220, 185}, {44, 162}, 215, kHypnoColorCyan}, // c23
{20, {128, 150}, {238, 150},{0, 0}, {209, 146}, 0, kHypnoColorCyan}, // c20
{31, {70, 160}, {180, 160}, {220, 185}, {44, 164}, 215, kHypnoColorGreen}, // c31
{32, {70, 160}, {180, 160}, {220, 185}, {44, 164}, 215, kHypnoColorRed}, // c32
{33, {70, 160}, {180, 160}, {220, 185}, {44, 162}, 215, kHypnoColorRed}, // c33
{30, {19, 3}, {246, 3}, {246, 11}, {2, 2}, 0, kHypnoColorRed}, // c30
{41, {70, 160}, {180, 160}, {220, 185}, {44, 162}, 215, kHypnoColorRed}, // c41
{42, {70, 160}, {180, 160}, {220, 185}, {44, 162}, 215, kHypnoColorRed}, // c42
{43, {70, 160}, {180, 160}, {220, 185}, {44, 162}, 215, kHypnoColorRed}, // c43
{44, {70, 160}, {180, 160}, {220, 185}, {44, 162}, 215, kHypnoColorRed}, // c44
{40, {19, 3}, {246, 3}, {246, 11}, {2, 2}, 0, kHypnoColorRed}, // c40
{51, {60, 167}, {190, 167}, {135, 187}, {136, 163}, 36, kHypnoColorRed}, // c51
{52, {60, 167}, {190, 167}, {135, 187}, {136, 165}, 36, kHypnoColorCyan}, // c52
{50, {19, 3}, {246, 3}, {246, 11}, {2, 2}, 0, kHypnoColorRed}, // c50 (fixed)
{61, {63, 167}, {187, 167}, {192, 188}, {152, 185}, 0, kHypnoColorCyan}, // c61
{60, {63, 167}, {187, 167}, {192, 188}, {152, 185}, 0, kHypnoColorCyan}, // c60
{0, {0, 0}, {0, 0}, {0, 0}, {0, 0}, 0, kHypnoColorRed} // NULL
};
static const chapterEntry rawChapterTableEarlyDemo[] = {
{31, {48, 15}, {205, 15}, {0, 0}, {0, 0}, 0, kHypnoColorRed}, // c31
{41, {48, 15}, {205, 15}, {0, 0}, {0, 0}, 0, kHypnoColorRed}, // c41
{0, {0, 0}, {0, 0}, {0, 0}, {0, 0}, 0, kHypnoColorRed} // NULL
};
WetEngine::WetEngine(OSystem *syst, const ADGameDescription *gd) : HypnoEngine(syst, gd) {
_screenW = 320;
_screenH = 200;
_lives = 2;
_lastLevel = 0;
_c33UseMouse = true;
_c40SegmentIdx = -1;
_c40lastTurn = -1;
_c50LeftTurns = 0;
_c50RigthTurns = 0;
_rButtonUp = false;
const chapterEntry *entry = rawChapterTable;
while (entry->id) {
_ids.push_back(entry->id);
_chapterTable[entry->id] = entry;
entry++;
}
_healthString = getLocalizedString("health");
_scoreString = getLocalizedString("score");
_objString = getLocalizedString("objectives");
_targetString = getLocalizedString("target");
_directionString = getLocalizedString("direction");
_enterNameString = getLocalizedString("name");
}
WetEngine::~WetEngine() {
}
void WetEngine::loadAssets() {
if (!isDemo()) {
_difficulty = "1"; // Medium difficulty by default
loadAssetsFullGame();
return;
}
_difficulty = ""; // No difficulty selection in demo
if (_variant == "Demo" || _variant == "DemoHebrew" || _variant == "M&MCD")
loadAssetsDemoDisc();
else if (_variant == "EarlyDemo")
loadAssetsEarlyDemo();
else if (_variant == "Gen4")
loadAssetsGen4();
else if (_variant == "PCWDemo")
loadAssetsPCW();
else if (_variant == "PCGDemo")
loadAssetsPCG();
else if (_variant == "NonInteractive" || _variant == "NonInteractiveJoystick")
loadAssetsNI();
else
error("Invalid demo version: \"%s\"", _variant.c_str());
}
void WetEngine::loadAssetsDemoDisc() {
bool encrypted = _variant == "Demo" || _variant == "M&MCD" ? true : false;
LibFile *missions = loadLib("", "wetlands/c_misc/missions.lib", encrypted);
Common::ArchiveMemberList files;
if (missions->listMembers(files) == 0)
error("%s", failedDetectionError);
Hotspot h(MakeMenu);
Hotspots hs;
Ambient *a = new Ambient("movie/selector.smk", Common::Point(0, 0), "/LOOP");
a->fullscreen = true;
h.actions.push_back(a);
hs.push_back(h);
h.type = MakeHotspot;
h.rect = Common::Rect(0, 177, 116, 192);
h.actions.clear();
h.smenu = nullptr;
ChangeLevel *cl = new ChangeLevel("");
h.actions.push_back(cl);
hs.push_back(h);
h.rect = Common::Rect(121, 177, 250, 200);
cl = new ChangeLevel("");
h.actions.clear();
h.actions.push_back(cl);
hs.push_back(h);
h.rect = Common::Rect(252, 177, 318, 200);
Quit *q = new Quit();
h.actions.clear();
h.actions.push_back(q);
hs.push_back(h);
Scene *start = new Scene();
start->resolution = "320x200";
start->hots = hs;
_levels[""] = start;
Transition *intro;
if (_variant == "Demo" || _variant == "M&MCD")
intro = new Transition("c31");
else if (_variant == "DemoHebrew")
intro = new Transition("c31.mis");
else
error("Unsupported language");
if (_variant == "M&MCD") {
intro->intros.push_back("wetlands/c_misc/nw_logo.smk");
intro->intros.push_back("wetlands/c_misc/h.s");
intro->intros.push_back("wetlands/c_misc/w.s");
intro->frameImage = "wetlands/c_misc/c.s";
intro->frameNumber = 0;
} else {
intro->intros.push_back("movie/nw_logo.smk");
intro->intros.push_back("movie/hypnotix.smk");
intro->intros.push_back("movie/wetlogo.smk");
intro->frameImage = "wetlands/c_misc/c.s";
intro->frameNumber = 0;
}
_levels[""] = intro;
if (_variant == "M&MCD") // This variant has no selector
_levels[""] = intro;
Transition *movies = new Transition("");
movies->intros.push_back("movie/nw_logo.smk");
movies->intros.push_back("movie/hypnotix.smk");
movies->intros.push_back("movie/wetlogo.smk");
movies->intros.push_back("movie/c42e1s.smk");
movies->intros.push_back("movie/c23e1s.smk");
movies->intros.push_back("movie/c20o1s.smk");
movies->intros.push_back("movie/c23d1s.smk");
movies->intros.push_back("movie/c40o1s.smk");
movies->intros.push_back("movie/c31d1s.smk");
movies->intros.push_back("movie/c42d1s.smk");
movies->intros.push_back("movie/c44d1s.smk");
movies->intros.push_back("movie/c44e1s.smk");
movies->intros.push_back("movie/c32d1s.smk");
movies->intros.push_back("movie/c22e1s.smk");
movies->intros.push_back("movie/c31e1s.smk");
movies->intros.push_back("movie/gameover.smk");
movies->frameImage = "";
movies->frameNumber = 0;
_levels[""] = movies;
ArcadeShooting *arc;
if (_variant == "Demo" || _variant == "M&MCD") {
loadArcadeLevel("c31.mi_", "c52", "c52", "wetlands");
if (_restoredContentEnabled) {
arc = (ArcadeShooting*) _levels["c31.mi_"];
arc->segments[0].size = 1354;
arc->objKillsRequired[0] = 2;
}
loadArcadeLevel("c52.mi_", "", "", "wetlands");
if (_restoredContentEnabled) {
arc = (ArcadeShooting*) _levels["c52.mi_"];
arc->segments[0].size = 2383;
arc->objKillsRequired[0] = 2;
arc->objKillsRequired[1] = 13;
}
} else if (_variant == "DemoHebrew") {
loadArcadeLevel("c31.mis", "c52.mis", "c52.mis", "wetlands");
if (_restoredContentEnabled) {
arc = (ArcadeShooting*) _levels["c31.mis"];
arc->segments[0].size = 1354;
arc->objKillsRequired[0] = 2;
}
loadArcadeLevel("c52.mis", "", "", "wetlands");
if (_restoredContentEnabled) {
arc = (ArcadeShooting*) _levels["c52.mis"];
arc->segments[0].size = 2383;
arc->objKillsRequired[0] = 2;
arc->objKillsRequired[1] = 13;
}
} else {
error("Unsupported variant");
}
Transition *over = new Transition("");
over->intros.push_back("movie/gameover.smk");
_levels[""] = over;
loadLib("", "wetlands/c_misc/fonts.lib", true);
loadFonts();
loadLib("wetlands/sound/", "wetlands/c_misc/sound.lib", true);
_nextLevel = "";
}
void WetEngine::loadAssetsEarlyDemo() {
Transition *intro;
intro = new Transition("c_misc/c31.mis");
intro->prefix = "c_misc/";
intro->intros.push_back("nw_logo.smk");
intro->intros.push_back("h.s");
intro->intros.push_back("w.s");
intro->frameImage = "c.s";
intro->frameNumber = 0;
_levels[""] = intro;
loadArcadeLevel("c_misc/c31.mis", "c_misc/c41.mis", "c_misc/c41.mis", "");
loadArcadeLevel("c_misc/c41.mis", "c_misc/c61.mis", "c_misc/c61.mis", "");
loadArcadeLevel("c_misc/c61.mis", "", "", "");
Transition *over = new Transition("");
over->intros.push_back("g.s");
_levels[""] = over;
loadFonts("c_misc/");
const chapterEntry *entry = rawChapterTableEarlyDemo;
while (entry->id) {
_chapterTable[entry->id] = entry;
entry++;
}
_nextLevel = "";
}
void WetEngine::loadAssetsGen4() {
bool encrypted = false;
LibFile *missions = loadLib("", "c_misc/missions.lib", encrypted);
Common::ArchiveMemberList files;
if (missions->listMembers(files) == 0)
error("%s", failedDetectionError);
Transition *intro;
intro = new Transition("c31.mis");
intro->intros.push_back("c_misc/nw_logo.smk");
intro->intros.push_back("c_misc/h.s");
intro->intros.push_back("c_misc/w.s");
intro->frameImage = "c_misc/c.s";
intro->frameNumber = 0;
_levels[""] = intro;
loadArcadeLevel("c31.mis", "c52.mis", "c52.mis", "");
ArcadeShooting *arc;
if (_restoredContentEnabled) {
arc = (ArcadeShooting*) _levels["c31.mis"];
arc->segments[0].size = 1354;
arc->objKillsRequired[0] = 2;
}
loadArcadeLevel("c52.mis", "", "", "");
if (_restoredContentEnabled) {
arc = (ArcadeShooting*) _levels["c52.mis"];
arc->segments[0].size = 2383;
arc->objKillsRequired[0] = 2;
arc->objKillsRequired[1] = 13;
}
Transition *over = new Transition("");
over->intros.push_back("c_misc/g.s");
_levels[""] = over;
loadLib("", "c_misc/fonts.lib", true);
loadFonts();
loadLib("sound/", "c_misc/sound.lib", true);
_nextLevel = "";
}
void WetEngine::loadAssetsNI() {
Common::String musicFile = _variant == "NonInteractive" ? "wetmusic.81m" : "c44_22k.raw";
int musicRate = _variant == "NonInteractive" ? 11025 : 22050;
Transition *movies = new Transition("");
movies->music = musicFile;
movies->musicRate = musicRate;
movies->playMusicDuringIntro = true;
movies->intros.push_back("demo/nw_logo.smk");
movies->intros.push_back("demo/hypnotix.smk");
movies->intros.push_back("demo/wetlogo.smk");
movies->intros.push_back("demo/c31c1.smk");
movies->intros.push_back("demo/demo31.smk");
movies->intros.push_back("demo/c31c2.smk");
movies->intros.push_back("demo/c31e1.smk");
movies->intros.push_back("demo/logo_w.smk");
movies->intros.push_back("demo/bar01b.smk");
movies->intros.push_back("demo/gun_320.smk");
movies->intros.push_back("demo/logo_e.smk");
movies->intros.push_back("demo/c30peek.smk");
movies->intros.push_back("demo/demo30.smk");
movies->intros.push_back("demo/c30knife.smk");
movies->intros.push_back("demo/logo_t.smk");
movies->intros.push_back("demo/c51teez.smk");
movies->intros.push_back("demo/demo21.smk");
movies->intros.push_back("demo/c51kill.smk");
movies->intros.push_back("demo/logo_l.smk");
movies->intros.push_back("demo/run_320.smk");
movies->intros.push_back("demo/logo_a.smk");
movies->intros.push_back("demo/demo50.smk");
movies->intros.push_back("demo/c50gate.smk");
movies->intros.push_back("demo/logo_n.smk");
movies->intros.push_back("demo/c22end.smk");
movies->intros.push_back("demo/logo_d.smk");
movies->intros.push_back("demo/demo44.smk");
movies->intros.push_back("demo/c44boom.smk");
movies->intros.push_back("demo/logo_s.smk");
movies->intros.push_back("demo/xi.smk");
movies->intros.push_back("demo/wetlogo.smk");
movies->intros.push_back("demo/c30shoot.smk");
movies->frameImage = "";
movies->frameNumber = 0;
_levels[""] = movies;
_nextLevel = "";
}
void WetEngine::loadAssetsPCW() {
LibFile *missions = loadLib("", "c_misc/missions.lib", false);
Common::ArchiveMemberList files;
if (missions->listMembers(files) == 0)
error("%s", failedDetectionError);
Transition *intro = new Transition("c11.mis");
intro->intros.push_back("c_misc/nw_logo.smk");
intro->intros.push_back("c_misc/h.s");
intro->intros.push_back("c_misc/wet.smk");
_levels[""] = intro;
loadArcadeLevel("c11.mis", "", "", "");
ArcadeShooting *arc;
if (_restoredContentEnabled) {
arc = (ArcadeShooting*) _levels["c11.mis"];
arc->segments[0].size = 2002;
arc->objKillsRequired[0] = 1;
arc->transitions.push_back(ArcadeTransition("", "c11/c11p2.col", "", 0, 1501));
// These videos were not included in the demo, so we replace them
arc->defeatMissBossVideo = "c11\\c11d1.smk";
arc->defeatNoEnergySecondVideo = "c11\\c11d1.smk";
}
Transition *over = new Transition("");
_levels[""] = over;
loadLib("sound/", "c_misc/sound.lib", false);
loadLib("", "c_misc/fonts.lib", true);
loadFonts();
_nextLevel = "";
}
void WetEngine::loadAssetsPCG() {
LibFile *missions = loadLib("", "missions.lib", false);
Common::ArchiveMemberList files;
if (missions->listMembers(files) == 0)
error("%s", failedDetectionError);
Transition *intro = new Transition("c31.mis");
intro->intros.push_back("nw_logo.smk");
intro->intros.push_back("h.s");
intro->intros.push_back("wet.smk");
intro->frameImage = "c.s";
intro->frameNumber = 0;
_levels[""] = intro;
loadArcadeLevel("c31.mis", "", "", "");
ArcadeShooting *arc;
if (_restoredContentEnabled) {
arc = (ArcadeShooting*) _levels["c31.mis"];
arc->segments[0].size = 1354;
arc->objKillsRequired[0] = 2;
// These videos were not included in the demo, so we replace or remove them
arc->hitBoss1Video = "";
arc->hitBoss2Video = "";
arc->missBoss1Video = "";
arc->missBoss2Video = "";
arc->defeatMissBossVideo = "c31\\c31d1s.smk";
}
Transition *over = new Transition("");
over->intros.push_back("g.s");
_levels[""] = over;
loadLib("sound/", "sound.lib", false);
loadLib("", "fonts.lib", true);
loadFonts();
_nextLevel = "";
}
void WetEngine::loadAssetsFullGame() {
LibFile *missions = loadLib("", "c_misc/missions.lib", true);
Common::ArchiveMemberList files;
if (missions == nullptr || missions->listMembers(files) == 0)
error("%s", failedDetectionError);
Transition *logos = new Transition("");
logos->intros.push_back("c_misc/logo.smk");
logos->intros.push_back("c_misc/nw_logo.smk");
logos->intros.push_back("c_misc/hypnotix.smk");
logos->intros.push_back("c_misc/wetlogo.smk");
_levels[""] = logos;
Code *menu = new Code("");
_levels[""] = menu;
_levels[""]->levelIfWin = "";
Code *level_menu = new Code("");
_levels[""] = level_menu;
_levels[""]->levelIfWin = "?";
Transition *over = new Transition("");
over->intros.push_back("c_misc/gameover.smk");
_levels[""] = over;
Transition *intros = new Transition("");
intros->intros.push_back("c_misc/stardate.smk");
intros->intros.push_back("c_misc/intros.smk");
intros->intros.push_back("c_misc/confs.smk");
_levels[""] = intros;
Code *check_lives = new Code("");
_levels[""] = check_lives;
Code *end_credits = new Code("");
_levels[""] = end_credits;
ArcadeShooting *arc;
loadArcadeLevel("c110.mi_", "c10", "", "");
loadArcadeLevel("c111.mi_", "c10", "", "");
loadArcadeLevel("c112.mi_", "c10", "", "");
loadArcadeLevel("c100.mi_", "c21", "", "");
loadArcadeLevel("c101.mi_", "c21", "", "");
loadArcadeLevel("c102.mi_", "c21", "", "");
loadArcadeLevel("c210.mi_", "c22", "", "");
loadArcadeLevel("c211.mi_", "c22", "", "");
loadArcadeLevel("c212.mi_", "c22", "", "");
loadArcadeLevel("c220.mi_", "c23", "", "");
loadArcadeLevel("c221.mi_", "c23", "", "");
loadArcadeLevel("c222.mi_", "c23", "", "");
loadArcadeLevel("c230.mi_", "c20", "", "");
loadArcadeLevel("c231.mi_", "c20", "", "");
loadArcadeLevel("c232.mi_", "c20", "", "");
loadArcadeLevel("c200.mi_", "c31", "", "");
loadArcadeLevel("c201.mi_", "c31", "", "");
loadArcadeLevel("c202.mi_", "c31", "", "");
arc = (ArcadeShooting*) _levels["c200.mi_"];
arc->mouseBox.right = 320;
arc->mouseBox.bottom = 135;
arc = (ArcadeShooting*) _levels["c201.mi_"];
arc->mouseBox.right = 320;
arc->mouseBox.bottom = 135;
arc = (ArcadeShooting*) _levels["c202.mi_"];
arc->mouseBox.right = 320;
arc->mouseBox.bottom = 135;
loadArcadeLevel("c310.mi_", "c32", "", "");
loadArcadeLevel("c311.mi_", "c32", "", "");
loadArcadeLevel("c312.mi_", "c32", "", "");
loadArcadeLevel("c320.mi_", "c33", "", "");
loadArcadeLevel("c321.mi_", "c33", "", "");
loadArcadeLevel("c322.mi_", "c33", "", "");
loadArcadeLevel("c330.mi_", "c30", "", "");
loadArcadeLevel("c331.mi_", "c30", "", "");
loadArcadeLevel("c332.mi_", "c30", "", "");
loadArcadeLevel("c300.mi_", "c41", "", "");
arc = (ArcadeShooting*) _levels["c300.mi_"];
arc->id = 30; // Fixed from the original (3)
loadArcadeLevel("c301.mi_", "c41", "", "");
arc = (ArcadeShooting*) _levels["c301.mi_"];
arc->id = 30; // Fixed from the original (3)
loadArcadeLevel("c302.mi_", "c41", "", "");
arc = (ArcadeShooting*) _levels["c302.mi_"];
arc->id = 30; // Fixed from the original (3)
loadArcadeLevel("c410.mi_", "c42", "", "");
loadArcadeLevel("c411.mi_", "c42", "", "");
loadArcadeLevel("c412.mi_", "c42", "", "");
loadArcadeLevel("c420.mi_", "c43", "", "");
loadArcadeLevel("c421.mi_", "c43", "", "");
loadArcadeLevel("c422.mi_", "c43", "", "");
loadArcadeLevel("c430.mi_", "c44", "", "");
loadArcadeLevel("c431.mi_", "c44", "", "");
loadArcadeLevel("c432.mi_", "c44", "", "");
loadArcadeLevel("c440.mi_", "c40", "", "");
loadArcadeLevel("c441.mi_", "c40", "", "");
loadArcadeLevel("c442.mi_", "c40", "", "");
loadArcadeLevel("c400.mi_", "c51", "", "");
arc = (ArcadeShooting*) _levels["c400.mi_"];
arc->id = 40; // Fixed from the original (4)
loadArcadeLevel("c401.mi_", "c51", "", "");
arc = (ArcadeShooting*) _levels["c401.mi_"];
arc->id = 40; // Fixed from the original (4)
loadArcadeLevel("c402.mi_", "c51", "", "");
arc = (ArcadeShooting*) _levels["c402.mi_"];
arc->id = 40; // Fixed from the original (4)
loadArcadeLevel("c510.mi_", "c52", "", "");
loadArcadeLevel("c511.mi_", "c52", "", "");
loadArcadeLevel("c512.mi_", "c52", "", "");
loadArcadeLevel("c520.mi_", "c50", "", "");
loadArcadeLevel("c521.mi_", "c50", "", "");
loadArcadeLevel("c522.mi_", "c50", "", "");
loadArcadeLevel("c500.mi_", "c61", "", "");
arc = (ArcadeShooting*) _levels["c500.mi_"];
arc->id = 50; // Fixed from the original (5)
loadArcadeLevel("c501.mi_", "c61", "", "");
arc = (ArcadeShooting*) _levels["c501.mi_"];
arc->id = 50; // Fixed from the original (5)
loadArcadeLevel("c502.mi_", "c61", "", "");
arc = (ArcadeShooting*) _levels["c502.mi_"];
arc->id = 50; // Fixed from the original (5)
loadArcadeLevel("c610.mi_", "c60", "", "");
loadArcadeLevel("c611.mi_", "c60", "", "");
loadArcadeLevel("c612.mi_", "c60", "", "");
loadArcadeLevel("c600.mi_", "", "", "");
loadArcadeLevel("c601.mi_", "", "", "");
loadArcadeLevel("c602.mi_", "", "", "");
loadLib("", "c_misc/fonts.lib", true);
loadFonts();
loadLib("sound/", "c_misc/sound.lib", true);
restoreScoreMilestones(0);
_nextLevel = "";
}
void WetEngine::showCredits() {
if (!isDemo() || ((_variant == "Demo" || _variant == "M&MCD") && _language == Common::EN_USA)) {
MVideo video("c_misc/credits.smk", Common::Point(0, 0), false, true, false);
runIntro(video);
}
}
void WetEngine::loadFonts(const Common::String &prefix) {
HypnoEngine::loadFonts(prefix);
if (_language == Common::KO_KOR) {
Common::File file;
if (!file.open("C_MISC/G9A.SYF"))
error("Cannot open Korean font");
byte *font = (byte *)malloc(file.size());
file.read(font, file.size());
_fontg9a.set_size(file.size()*8);
_fontg9a.set_bits((byte *)font);
free(font);
}
}
uint16 WetEngine::getNextChar(const Common::String &str, uint32 &c) {
if (c >= str.size())
return 0;
if (_language == Common::KO_KOR && (str[c] & 0x80) && c + 1 < str.size()) {
uint16 r = (str[c] << 8) | (str[c+1] & 0xff);
c += 2;
return r;
}
return str[c++];
}
void WetEngine::drawGlyph(const Common::BitArray &font, int x, int y, int bitoffset, int width, int height, int pitch, uint32 color, bool invert) {
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
if (font.get(bitoffset + j * pitch + i) == invert)
_compositeSurface->setPixel(x + (width - i - 1), y + j, color);
}
}
}
void WetEngine::drawKoreanChar(uint16 chr, int &curx, int y, uint32 color) {
// TODO: What do the first 13 bytes and a byte before ASCII char mean?
if (chr < 0x100) {
if (chr < 0x20 || chr >= 0x80) {
return;
}
drawGlyph(_fontg9a, curx, y, 104 + 19 * 8 * (chr - 0x20), 9, 9, 16, color, true);
curx += 9;
return;
}
int initial = (chr >> 10) & 0x1f;
int mid = (chr >> 5) & 0x1f;
int fin = chr & 0x1f;
int initidx = initial - 1;
static const int mididxlut[0x20] = {
-1, -1, 0, 1, 2, 3, 4, 5, -1, -1, 6, 7, 8, 9,
10, 11, -1, -1, 12, 13, 14, 15, 16, 17, -1, -1,
18, 19, 20, 21, -1, -1};
int mididx = mididxlut[mid];
int finidx = fin >= 0x12 ? fin - 2 : fin - 1;
if (initidx < 0 || initidx > 19 || mididx < 0 || mididx > 21 || finidx < 0 || finidx >= 27)
return;
const int mid_to_init_lut[32] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 1, 3, 3,
0, 0, 3, 1, 2, 4, 4, 4,
0, 0, 2, 1, 3, 0, 0, 0,
};
const int mid_to_fin_lut[32] = {
0, 0, 0, 0, 2, 0, 2, 1,
0, 0, 2, 1, 2, 3, 0, 2,
0, 0, 1, 3, 3, 1, 2, 1,
0, 0, 3, 3, 1, 1, 0, 0,
};
int initialvariant = 2 * mid_to_init_lut[mid] + (fin == 1 ? 0 : 1);
int midvariant = (fin == 1 ? 0 : 1) + (initial == 1 || initial == 2 || initial == 17 ? 0 : 2);
int finvariant = mid_to_fin_lut[mid];
int initialglyph = initidx == 0 ? 0 : initidx * 10 + initialvariant - 9;
int midglyph = mididx == 0 ? 0 : 4 * mididx + midvariant - 3;
int finglyph = finidx == 0 ? 0 : 4 * finidx + finvariant - 3;
drawGlyph(_fontg9a, curx, y, 1836 * 8 + 16 * 9 * initialglyph, 9, 9, 16, color, true);
drawGlyph(_fontg9a, curx, y, 1836 * 8 + 16 * 9 * 191 + 16 * 9 * midglyph, 9, 9, 16, color, true);
drawGlyph(_fontg9a, curx, y, 1836 * 8 + 16 * 9 * 276 + 16 * 9 * finglyph, 9, 9, 16, color, true);
curx += 9;
}
void WetEngine::drawString(const Common::String &font, const Common::String &str, int x, int y, int w, uint32 color) {
int offset = 0;
int curx = x;
if (font == "g9a.syf" && _language == Common::KO_KOR) {
for (uint32 c = 0; c < str.size(); ) {
uint16 chr = getNextChar(str, c);
drawKoreanChar(chr, curx, y, color);
}
} else if (font == "block05.fgx") {
for (uint32 c = 0; c < str.size(); ) {
uint16 chr = getNextChar(str, c);
if (chr >= 0x100 && _language == Common::KO_KOR) {
drawKoreanChar(chr, curx, y, color);
continue;
}
offset = 0;
if (chr == ':')
offset = 1;
else if (chr == '.')
offset = 4;
drawGlyph(_font05, curx + 1, offset + y, 275 + 40*chr, 5, 5, 8, color, _variant == "EarlyDemo");
curx += 6;
}
} else if (font == "scifi08.fgx") {
for (uint32 c = 0; c < str.size();) {
uint16 chr = getNextChar(str, c);
if (chr >= 0x100 && _language == Common::KO_KOR) {
drawKoreanChar(chr, curx, y, color);
continue;
}
if (chr == 0)
continue;
assert(chr >= 32);
offset = 0;
if (chr == 't')
offset = 0;
else if (chr == 'i' || chr == '%')
offset = 1;
else if (Common::isLower(chr) || chr == ':')
offset = 2;
drawGlyph(_font08, curx + 1, offset + y, 1554 + 72*(chr-32), 6, 8, 8, color, _variant == "EarlyDemo");
curx += 7;
}
} else
error("Invalid font: '%s'", font.c_str());
}
void WetEngine::saveProfile(const Common::String &name, int levelId) {
SaveStateList saves = getMetaEngine()->listSaves(_targetName.c_str());
// Find the correct level index to before saving
for (uint32 i = 0; i < _ids.size(); i++) {
if (levelId == _ids[i]) {
if (_lastLevel < int(i))
_lastLevel = int(i);
break;
}
}
uint32 slot = 0;
for (SaveStateList::iterator save = saves.begin(); save != saves.end(); ++save) {
if (save->getDescription() == name)
break;
slot++;
}
saveGameState(slot, name, false);
}
bool WetEngine::loadProfile(const Common::String &name) {
SaveStateList saves = getMetaEngine()->listSaves(_targetName.c_str());
uint32 slot = 0;
for (SaveStateList::iterator save = saves.begin(); save != saves.end(); ++save) {
if (save->getDescription() == name)
break;
slot++;
}
if (slot == saves.size()) {
debugC(1, kHypnoDebugMedia, "Failed to load %s", name.c_str());
return false;
}
loadGameState(slot);
return true;
}
Common::Error WetEngine::saveGameStream(Common::WriteStream *stream, bool isAutosave) {
if (isAutosave)
return Common::kNoError;
if (_lastLevel < 0 || _lastLevel >= 20)
error("Invalid last level!");
stream->writeString(_name);
stream->writeByte(0);
stream->writeString(_difficulty);
stream->writeByte(0);
stream->writeUint32LE(_lives);
stream->writeUint32LE(_score);
stream->writeUint32LE(_lastLevel);
return Common::kNoError;
}
Common::Error WetEngine::loadGameStream(Common::SeekableReadStream *stream) {
_name = stream->readString();
_difficulty = stream->readString();
_lives = stream->readUint32LE();
_score = stream->readUint32LE();
_lastLevel = stream->readUint32LE();
if (_lastLevel == 0)
_nextLevel = Common::String::format("c%d", _ids[0]);
else
_nextLevel = "";
restoreScoreMilestones(_score);
return Common::kNoError;
}
Common::String WetEngine::findNextLevel(const Transition *trans) {
if (trans->nextLevel.empty())
error("Invalid transition!");
return trans->nextLevel;
}
Common::String WetEngine::findNextLevel(const Common::String &level) {
Common::String nextLevel;
if (Common::matchString(level.c_str(), "c#") || Common::matchString(level.c_str(), "c##"))
nextLevel = level + _difficulty + ".mi_";
else {
nextLevel = level;
}
return nextLevel;
}
} // End of namespace Hypno