/* 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