From 259654a7bf3e04f64efee97ea6e14a41ce94399f Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Thu, 2 Feb 2023 21:49:12 -0800 Subject: [PATCH 001/412] MM: MM1: Fix to checking monster spell action --- engines/mm/mm1/game/combat.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/engines/mm/mm1/game/combat.cpp b/engines/mm/mm1/game/combat.cpp index 9195e7c55fac..04a4f259b3b5 100644 --- a/engines/mm/mm1/game/combat.cpp +++ b/engines/mm/mm1/game/combat.cpp @@ -621,8 +621,8 @@ void Combat::monsterAction() { removeMonster(); setMode(MONSTER_FLEES); } else { - // Otherwise, move on to checking if monster casts spells - checkMonsterSpells(); + // Otherwise, move on to checking monster actions + checkMonsterActions(); } } @@ -655,7 +655,7 @@ bool Combat::checkMonsterSpells() { void Combat::checkMonsterActions() { if (checkMonsterSpells()) - // Monster wandered or cast spell, so things are taken care of + // Monster cast spell, so things are taken care of return; _destCharCtr = 0; From b2b8d328144eb21f5b8a041a130055ccdeab90c1 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Fri, 3 Feb 2023 20:45:27 -0800 Subject: [PATCH 002/412] MM: MM1: Fix initial combat rendering if monster attacks first --- engines/mm/mm1/game/combat.cpp | 2 ++ engines/mm/mm1/views/combat.cpp | 9 +++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/engines/mm/mm1/game/combat.cpp b/engines/mm/mm1/game/combat.cpp index 04a4f259b3b5..473aa646f734 100644 --- a/engines/mm/mm1/game/combat.cpp +++ b/engines/mm/mm1/game/combat.cpp @@ -619,6 +619,8 @@ void Combat::monsterAction() { _monsterP->_hp = 0; _monsterP->_status = MONFLAG_DEAD; removeMonster(); + + _activeMonsterNum = -1; setMode(MONSTER_FLEES); } else { // Otherwise, move on to checking monster actions diff --git a/engines/mm/mm1/views/combat.cpp b/engines/mm/mm1/views/combat.cpp index fd7cf956fe3f..75ca7b9a5c68 100644 --- a/engines/mm/mm1/views/combat.cpp +++ b/engines/mm/mm1/views/combat.cpp @@ -118,10 +118,6 @@ void Combat::draw() { writeMonsterSpell(); delaySeconds(2); return; - case MONSTER_ATTACK: - writeMonsterAttack(); - delaySeconds(4); - return; case INFILTRATION: writeInfiltration(); delaySeconds(3); @@ -167,6 +163,11 @@ void Combat::draw() { delaySeconds(_spellResult._delaySeconds); break; + case MONSTER_ATTACK: + writeMonsterAttack(); + delaySeconds(2); + break; + case MONSTER_FLEES: case MONSTER_WANDERS: writeMonsterAction(_mode == MONSTER_FLEES); From 156336583c197562d2e073d92dd4cc9668a72044 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Fri, 3 Feb 2023 20:58:30 -0800 Subject: [PATCH 003/412] MM: MM1: Fix setting up _attackersCount --- engines/mm/mm1/game/combat.cpp | 8 ++++---- engines/mm/mm1/game/combat.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/engines/mm/mm1/game/combat.cpp b/engines/mm/mm1/game/combat.cpp index 473aa646f734..34b28c6b0028 100644 --- a/engines/mm/mm1/game/combat.cpp +++ b/engines/mm/mm1/game/combat.cpp @@ -165,7 +165,7 @@ void Combat::setupCanAttacks() { g_globals->_combatParty[5]->_canAttack = true; } - setupAttackerVal(); + setupAttackersCount(); return; } } @@ -176,17 +176,17 @@ void Combat::setupCanAttacks() { for (uint i = 0; i < g_globals->_combatParty.size(); ++i) g_globals->_combatParty[i]->_canAttack = true; - setupAttackerVal(); + setupAttackersCount(); } -void Combat::setupAttackerVal() { +void Combat::setupAttackersCount() { _attackersCount = 0; for (uint i = 0; i < g_globals->_combatParty.size(); ++i) { if (g_globals->_combatParty[i]->_canAttack) ++_attackersCount; } - _attackersCount = getRandomNumber(_attackersCount + 1) - 1; + _attackersCount += getRandomNumber(_attackersCount + 1) - 1; } void Combat::checkLeftWall() { diff --git a/engines/mm/mm1/game/combat.h b/engines/mm/mm1/game/combat.h index c9075d4318c4..c077f5219e45 100644 --- a/engines/mm/mm1/game/combat.h +++ b/engines/mm/mm1/game/combat.h @@ -131,7 +131,7 @@ class Combat : public MonsterTouch { /** * Chooses the starting character to */ - void setupAttackerVal(); + void setupAttackersCount(); /** * Checks whether the third party member From 2a3da91ab09db0fa0cdc9640d93cd92919da1c09 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Fri, 3 Feb 2023 21:46:37 -0800 Subject: [PATCH 004/412] MM: MM1: Fix display of monster attacking results --- engines/mm/mm1/views/combat.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/engines/mm/mm1/views/combat.cpp b/engines/mm/mm1/views/combat.cpp index 75ca7b9a5c68..d3b34e9d82ae 100644 --- a/engines/mm/mm1/views/combat.cpp +++ b/engines/mm/mm1/views/combat.cpp @@ -645,9 +645,10 @@ void Combat::writeMonsterAttack() { Common::String line = Common::String::format("%s %s %s", monsterName.c_str(), attackStyle.c_str(), - getAttackString().c_str() + c._name ); writeString(0, 20, line); + writeString(0, 21, getAttackString()); // It's not ideal, but we have to do some final minor damage // adjustment here after we've written the basic damage the @@ -667,18 +668,19 @@ void Combat::writeMonsterAttack() { // This returns a text line to display, and can also // adjust the damage amount. Another reason why we // can't actually apply damage until here + int yp = 22; if (monsterTouch(line)) - writeString(0, 21, line); + writeString(0, yp++, line); // TODO: Maybe refactor subtractDamage to not use // the _lines/add methods, which would make it cleaner // to call it from here _lines.clear(); - _lines.push_back(Line(0, 2, "")); + _lines.push_back(Line(0, 3, "")); subtractDamage(); if (!_lines.back()._text.empty()) - writeString(0, 22, _lines.back()._text); + writeString(0, yp, _lines.back()._text); } } From 355175534e60dabf5c777c4e6dc07f2cd2361deb Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Fri, 3 Feb 2023 21:51:32 -0800 Subject: [PATCH 005/412] MM: MM1: Fix check for party being incapacitated --- engines/mm/mm1/data/party.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/engines/mm/mm1/data/party.cpp b/engines/mm/mm1/data/party.cpp index ad7ffde5657f..e2cb78484e33 100644 --- a/engines/mm/mm1/data/party.cpp +++ b/engines/mm/mm1/data/party.cpp @@ -131,10 +131,10 @@ bool Party::checkPartyIncapacitated() const { } if (isActive) { + return false; + } else { g_events->replaceView("Dead", true); return true; - } else { - return false; } } From 872c667b2e6b3101b2ae4b0f45db7cfec32792d1 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Fri, 3 Feb 2023 21:58:04 -0800 Subject: [PATCH 006/412] MM: MM1: Remove some deprecated checks for | character Originally I was going use this to wrap character names, for formatting them in the enhanced version. However, I've since changed all text to be lowercase by default, and simply uppercased for the original displays --- engines/mm/mm1/messages.cpp | 8 +------- engines/mm/mm1/views/combat.cpp | 12 +++--------- engines/mm/mm1/views/text_view.cpp | 3 +-- 3 files changed, 5 insertions(+), 18 deletions(-) diff --git a/engines/mm/mm1/messages.cpp b/engines/mm/mm1/messages.cpp index 2ab8d9d872c7..f646f571b57d 100644 --- a/engines/mm/mm1/messages.cpp +++ b/engines/mm/mm1/messages.cpp @@ -100,13 +100,7 @@ InfoMessage &InfoMessage::operator=(const InfoMessage &src) { } size_t Line::size() const { - size_t total = 0; - for (uint i = 0; i < _text.size(); ++i) { - if (_text[i] != '|') - ++total; - } - - return total; + return _text.size(); } } // namespace MM1 diff --git a/engines/mm/mm1/views/combat.cpp b/engines/mm/mm1/views/combat.cpp index d3b34e9d82ae..19c46403da98 100644 --- a/engines/mm/mm1/views/combat.cpp +++ b/engines/mm/mm1/views/combat.cpp @@ -681,6 +681,7 @@ void Combat::writeMonsterAttack() { if (!_lines.back()._text.empty()) writeString(0, yp, _lines.back()._text); + _lines.clear(); } } @@ -757,16 +758,9 @@ void Combat::shoot() { } void Combat::writeMessage() { - size_t idx; - resetBottom(); - for (const auto &line : _message) { - Common::String text = line._text; - while ((idx = text.findFirstOf('|')) != Common::String::npos) - text.deleteChar(idx); - - writeString(line.x, line.y, text); - } + for (const auto &line : _message) + writeString(line.x, line.y, line._text); } void Combat::writeCharAttackDamage() { diff --git a/engines/mm/mm1/views/text_view.cpp b/engines/mm/mm1/views/text_view.cpp index ceccaf7c2d17..3954be21c23e 100644 --- a/engines/mm/mm1/views/text_view.cpp +++ b/engines/mm/mm1/views/text_view.cpp @@ -60,8 +60,7 @@ void TextView::writeChar(int x, int y, unsigned char c) { void TextView::writeString(const Common::String &str) { for (const unsigned char *s = (const unsigned char *)str.c_str(); *s; ++s) { - if (*s != '|') - writeChar(*s); + writeChar(*s); if (*s >= ' ' && _textPos.x == 0 && (*(s + 1) == '\r' || *(s + 1) == '\n')) // Ignore carraige returns right after line wraps. The original didn't From 08ad9d9ff73034dfefc8cc3ec7cf49384ea002d7 Mon Sep 17 00:00:00 2001 From: Walter Agazzi Date: Thu, 2 Feb 2023 22:20:55 +0100 Subject: [PATCH 007/412] HUGO: Use slot 99 as the fallback save Use slot 99 as fallback instead of slot 0, which is normally used for autosaves --- engines/hugo/hugo.cpp | 2 +- engines/hugo/parser.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/engines/hugo/hugo.cpp b/engines/hugo/hugo.cpp index cd425194acef..b158d4927e64 100644 --- a/engines/hugo/hugo.cpp +++ b/engines/hugo/hugo.cpp @@ -298,7 +298,7 @@ Common::Error HugoEngine::run() { _status._skipIntroFl = true; _file->restoreGame(loadSlot); } else { - _file->saveGame(0, "New Game"); + _file->saveGame(99, "New Game [reserved]"); } } diff --git a/engines/hugo/parser.cpp b/engines/hugo/parser.cpp index 375b1f50c983..c7e096dae3d8 100644 --- a/engines/hugo/parser.cpp +++ b/engines/hugo/parser.cpp @@ -290,7 +290,7 @@ void Parser::keyHandler(Common::Event event) { break; case Common::KEYCODE_n: if (Utils::yesNoBox("Are you sure you want to start a new game?")) - _vm->_file->restoreGame(0); + _vm->_file->restoreGame(99); break; case Common::KEYCODE_s: if (gameStatus._viewState == kViewPlay) { From 96298d759074d089553eb963056d5ee5ab7c0698 Mon Sep 17 00:00:00 2001 From: Walter Agazzi Date: Fri, 3 Feb 2023 01:11:58 +0100 Subject: [PATCH 008/412] HUGO: Disable overwriting slot 99 --- engines/hugo/metaengine.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/engines/hugo/metaengine.cpp b/engines/hugo/metaengine.cpp index 4bbcee9eb63e..d7169aa8dfdd 100644 --- a/engines/hugo/metaengine.cpp +++ b/engines/hugo/metaengine.cpp @@ -147,6 +147,12 @@ SaveStateDescriptor HugoMetaEngine::querySaveMetaInfos(const char *target, int s SaveStateDescriptor desc(this, slot, saveName); + // Protect slot 99 (used for 'restart game') + if (slot == 99) { + desc.setDeletableFlag(false); + desc.setWriteProtectedFlag(true); + } + Graphics::Surface *thumbnail; if (!Graphics::loadThumbnail(*file, thumbnail)) { warning("Missing or broken savegame thumbnail"); @@ -172,7 +178,13 @@ SaveStateDescriptor HugoMetaEngine::querySaveMetaInfos(const char *target, int s delete file; return desc; } - return SaveStateDescriptor(); + + SaveStateDescriptor desc(this, slot, Common::String()); + // Protect slot 99 (used for 'restart game') + if (slot == 99) + desc.setWriteProtectedFlag(true); + + return desc; } void HugoMetaEngine::removeSaveState(const char *target, int slot) const { From 366c1e505dc174bdd88558431c6612ced665354e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Einar=20Johan=20Tr=C3=B8an=20S=C3=B8ma=CC=8Aen?= Date: Thu, 26 Jan 2023 00:03:59 +0100 Subject: [PATCH 009/412] TINSEL: Handle DW2 saves that had Noir-sized SysVars With this change we now once again can read pre 2.6 savegames. Similarly savegames created after this fix will be readable by ScummVM < 2.6.0. We will also be able to load savegames created by ScummVM 2.6.x. The only limitation is that since we now create the same kind of savegames as older versions again, ScummVM 2.6.x will be unable to load savegames created after this. This fixes bug #13897 --- engines/tinsel/saveload.cpp | 58 +++++++++++++++++++++++++++---------- engines/tinsel/savescn.h | 2 +- engines/tinsel/sysvar.cpp | 4 +-- engines/tinsel/sysvar.h | 5 +++- 4 files changed, 50 insertions(+), 19 deletions(-) diff --git a/engines/tinsel/saveload.cpp b/engines/tinsel/saveload.cpp index fbab7cea7e96..dd31e6f67f61 100644 --- a/engines/tinsel/saveload.cpp +++ b/engines/tinsel/saveload.cpp @@ -287,7 +287,7 @@ static void syncSoundReel(Common::Serializer &s, SOUNDREELS &sr) { s.syncAsSint32LE(sr.actorCol); } -static void syncSavedData(Common::Serializer &s, SAVED_DATA &sd, int numInterp) { +static void syncSavedData(Common::Serializer &s, SAVED_DATA &sd, int numInterp, int numSystemVars) { s.syncAsUint32LE(sd.SavedSceneHandle); s.syncAsUint32LE(sd.SavedBgroundHandle); for (int i = 0; i < MAX_MOVERS; ++i) @@ -335,7 +335,7 @@ static void syncSavedData(Common::Serializer &s, SAVED_DATA &sd, int numInterp) s.syncAsUint32LE(sd.SavedTune[i]); s.syncAsByte(sd.bTinselDim); s.syncAsSint32LE(sd.SavedScrollFocus); - for (int i = 0; i < SV_TOPVALID; ++i) + for (int i = 0; i < numSystemVars; ++i) s.syncAsSint32LE(sd.SavedSystemVars[i]); for (int i = 0; i < MAX_SOUNDREELS; ++i) syncSoundReel(s, sd.SavedSoundReels[i]); @@ -447,7 +447,7 @@ char *ListEntry(int i, letype which) { return NULL; } -static bool DoSync(Common::Serializer &s, int numInterp) { +static bool DoSync(Common::Serializer &s, int numInterp, int numSystemVars) { int sg = 0; if (TinselVersion >= 2) { @@ -459,8 +459,7 @@ static bool DoSync(Common::Serializer &s, int numInterp) { _vm->_dialogs->holdItem(INV_NOICON); } - - syncSavedData(s, *g_srsd, numInterp); + syncSavedData(s, *g_srsd, numInterp, numSystemVars); syncGlobInfo(s); // Glitter globals _vm->_dialogs->syncInvInfo(s); // Inventory data @@ -489,7 +488,7 @@ static bool DoSync(Common::Serializer &s, int numInterp) { if (*g_SaveSceneSsCount != 0) { SAVED_DATA *sdPtr = g_SaveSceneSsData; for (int i = 0; i < *g_SaveSceneSsCount; ++i, ++sdPtr) - syncSavedData(s, *sdPtr, numInterp); + syncSavedData(s, *sdPtr, numInterp, numSystemVars); // Flag that there is a saved scene to return to. Note that in this context 'saved scene' // is a stored scene to return to from another scene, such as from the Summoning Book close-up @@ -529,23 +528,52 @@ static bool DoRestore() { // for pre 1.5 savegames, and if that fails, a second time for 1.5 savegames int numInterpreters = hdr.numInterpreters; int32 currentPos = f->pos(); - for (int tryNumber = 0; tryNumber < ((hdr.ver >= 2) ? 1 : 2); ++tryNumber) { - // If it's the second loop iteration, try with the 1.5 savegame number of interpreter contexts + int numberOfTries = ((hdr.ver >= 2) ? 1 : 2); + int numSystemVars = SV_TOPVALID; // Appropriate for both Noir and DW2 + for (int tryNumber = 0; tryNumber < numberOfTries; ++tryNumber) { if (tryNumber == 1) { f->seek(currentPos); - numInterpreters = 80; + // If it's the second loop iteration, try with the 1.5 savegame number of interpreter contexts + if (hdr.ver < 2) { + numInterpreters = 80; + } } // Load the savegame data - if (DoSync(s, numInterpreters)) + bool successfullSync = DoSync(s, numInterpreters, numSystemVars); + + uint32 id = f->readSint32LE(); + + int remaining = f->size() - f->pos(); + // BUG #13897: Older savegames won't run on ScummVM 2.6.x + // The reason being that the system vars for Noir were added increasing the SV_TOPVALID value, + // which also affected DW2 unintentionally, creating some v3 savegames that had additional data + // stored there. To properly load these savegames, we'll have to try again, with the knowledge + // that we have to skip this data. + if (hdr.id == DW2_SAVEGAME_ID && hdr.ver == 3 && remaining != 0) { + if (tryNumber == 0) { + numberOfTries++; + // Make the second attempt read the Noir amount of sys-vars, so that the problematic + // savegames can be loaded. + numSystemVars = SV_TOPVALID_T3; + } + continue; + } + + if (successfullSync) { + if (id != (uint32)0xFEEDFACE) { + error("Incompatible saved game"); + } + // Data load was successful (or likely), so break out of loop break; + } } - uint32 id = f->readSint32LE(); - if (id != (uint32)0xFEEDFACE) - error("Incompatible saved game"); - + int remainingBytes = f->size() - f->pos(); + if (remainingBytes != 0) { + error("%d bytes of savegame not read", remainingBytes); + } bool failed = (f->eos() || f->err()); delete f; @@ -628,7 +656,7 @@ static void DoSave() { return; } - DoSync(s, hdr.numInterpreters); + DoSync(s, hdr.numInterpreters, SV_TOPVALID); // Write out the special Id for Discworld savegames f->writeUint32LE(0xFEEDFACE); diff --git a/engines/tinsel/savescn.h b/engines/tinsel/savescn.h index b8abe61f78ae..66030e22ee48 100644 --- a/engines/tinsel/savescn.h +++ b/engines/tinsel/savescn.h @@ -59,7 +59,7 @@ struct SAVED_DATA { uint32 SavedTune[3]; // Music bool bTinselDim; int SavedScrollFocus; - int SavedSystemVars[SV_TOPVALID]; + int SavedSystemVars[SV_TOPVALID_T3]; SOUNDREELS SavedSoundReels[MAX_SOUNDREELS]; }; diff --git a/engines/tinsel/sysvar.cpp b/engines/tinsel/sysvar.cpp index fe707386751f..2041e644ea5c 100644 --- a/engines/tinsel/sysvar.cpp +++ b/engines/tinsel/sysvar.cpp @@ -42,7 +42,7 @@ extern int NewestSavedGame(); // These vars are reset upon engine destruction -static int g_systemVars[SV_TOPVALID]; +static int g_systemVars[SV_TOPVALID_T3]; static SCNHANDLE g_systemStrings[SS_MAX_VALID]; //----------------- FUNCTIONS -------------------------------- @@ -57,7 +57,7 @@ void ResetVarsSysVar() { */ void InitSysVars() { - int initialSystemVars[SV_TOPVALID] = { + int initialSystemVars[SV_TOPVALID_T3] = { INV_1, // Default inventory 10, // Y-offset of Conversation(TOP) diff --git a/engines/tinsel/sysvar.h b/engines/tinsel/sysvar.h index efcbfa54ed6d..0c99bfadffc7 100644 --- a/engines/tinsel/sysvar.h +++ b/engines/tinsel/sysvar.h @@ -83,6 +83,8 @@ typedef enum { SV_DEFAULT_INV, ISV_GHOST_BASE_T2 = 0x2B, ISV_GHOST_COLOR_T2 = 0x2C, + SV_TOPVALID_T2 = 0x2D, + SV_SPRITER_SCENE_ID = 0x2F, // Noir, loaded scene ISV_DIVERT_ACTOR_T3 = 0x32, ISV_NO_BLOCKING_T3 = 0x33, @@ -92,13 +94,14 @@ typedef enum { SV_DEFAULT_INV, SV_SPRITER_SCALE = 0x37, // Noir, scale used for 3D rendering SV_SPRITER_OVERLAY = 0x38, // Noir, if additional model is loaded - SV_TOPVALID } SYSVARS; + SV_TOPVALID_T3 } SYSVARS; #define ISV_DIVERT_ACTOR ((TinselVersion == 3) ? ISV_DIVERT_ACTOR_T3 : ISV_DIVERT_ACTOR_T2) #define ISV_NO_BLOCKING ((TinselVersion == 3) ? ISV_NO_BLOCKING_T3 : ISV_NO_BLOCKING_T2) #define ISV_GHOST_ACTOR ((TinselVersion == 3) ? ISV_GHOST_ACTOR_T3 : ISV_GHOST_ACTOR_T2) #define ISV_GHOST_BASE ((TinselVersion == 3) ? ISV_GHOST_BASE_T3 : ISV_GHOST_BASE_T2) #define ISV_GHOST_COLOR ((TinselVersion == 3) ? ISV_GHOST_COLOR_T3 : ISV_GHOST_COLOR_T2) +#define SV_TOPVALID ((TinselVersion == 3) ? SV_TOPVALID_T3 : SV_TOPVALID_T2) typedef enum { From 45d7978b6158cefec15d7afdcbade3274edae0ce Mon Sep 17 00:00:00 2001 From: Walter Agazzi Date: Sat, 4 Feb 2023 11:57:12 +0100 Subject: [PATCH 010/412] AGS: Check sound stream isn't null before playing --- engines/ags/engine/media/audio/sound_clip.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/engines/ags/engine/media/audio/sound_clip.cpp b/engines/ags/engine/media/audio/sound_clip.cpp index e14604a75d50..9b72896ce47c 100644 --- a/engines/ags/engine/media/audio/sound_clip.cpp +++ b/engines/ags/engine/media/audio/sound_clip.cpp @@ -147,11 +147,15 @@ void SoundClipWaveBase::poll() { int SoundClipWaveBase::play() { if (_soundType != Audio::Mixer::kPlainSoundType) { + if (!_stream) { + warning("Sound stream is null"); + return 0; + } if (_stream->getRate() < 131072) // maximum accepted value in audio/rate.cpp _mixer->playStream(_soundType, &_soundHandle, _stream, -1, _vol255, 0, DisposeAfterUse::NO); else - warning("Invalid sound clip sample ratio: %d! Skipping", _stream->getRate()); + warning("Invalid sound clip sample rate: %d! Skipping", _stream->getRate()); } else { _waitingToPlay = true; } From 007d94963b8f1d8656a175a18c2cac91dc0a4b9f Mon Sep 17 00:00:00 2001 From: Eugene Sandulenko Date: Sat, 4 Feb 2023 14:33:11 +0100 Subject: [PATCH 011/412] DIRECTOR: Truly fix repl in debugger --- engines/director/debugger.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/engines/director/debugger.cpp b/engines/director/debugger.cpp index 78d34eec5173..c7d5ba20b29d 100644 --- a/engines/director/debugger.cpp +++ b/engines/director/debugger.cpp @@ -871,7 +871,11 @@ bool Debugger::lingoCommandProcessor(const char *inputOrig) { _lingoReplMode = false; return true; } - return lingoEval(inputOrig); + bool ret = lingoEval(inputOrig); + + debugPrintf(PROMPT); + + return ret; } bool Debugger::lingoEval(const char *inputOrig) { @@ -879,9 +883,9 @@ bool Debugger::lingoEval(const char *inputOrig) { inputSan.trim(); if (inputSan.empty()) return true; - Common::String expr = Common::String::format("return %s", inputSan.c_str()); + // Compile the code to an anonymous function and call it - ScriptContext *sc = g_lingo->_compiler->compileAnonymous(expr); + ScriptContext *sc = g_lingo->_compiler->compileAnonymous(inputSan); if (!sc) { debugPrintf("Failed to parse expression!\n%s", _lingoReplMode ? PROMPT : ""); return true; @@ -889,9 +893,10 @@ bool Debugger::lingoEval(const char *inputOrig) { Symbol sym = sc->_eventHandlers[kEventGeneric]; _lingoEval = true; LC::call(sym, 0, true); - _finish = true; - _finishCounter = 1; - return cmdExit(0, nullptr); + g_lingo->execute(); + + debugPrintf("\n"); + return true; } void Debugger::stepHook() { From b97b2b0fe323f2fc77e051cfe60af3a5f605c817 Mon Sep 17 00:00:00 2001 From: Eugene Sandulenko Date: Sat, 4 Feb 2023 14:58:54 +0100 Subject: [PATCH 012/412] GUI: Add possibility to specify Debugger prompt --- gui/console.cpp | 14 ++++++++++++-- gui/console.h | 5 +++++ gui/debugger.cpp | 12 ++++++++++++ gui/debugger.h | 3 +++ 4 files changed, 32 insertions(+), 2 deletions(-) diff --git a/gui/console.cpp b/gui/console.cpp index b03a2a7d93bb..61f0d1b8471c 100644 --- a/gui/console.cpp +++ b/gui/console.cpp @@ -121,6 +121,16 @@ void ConsoleDialog::init() { _pageWidth = (_w - scrollBarWidth - 2 - _leftPadding - _topPadding - scrollBarWidth) / kConsoleCharWidth; _linesPerPage = (_h - 2 - _topPadding - _bottomPadding) / kConsoleLineHeight; _linesInBuffer = kBufferSize / kCharsPerLine; + + resetPrompt(); +} + +void ConsoleDialog::setPrompt(Common::String prompt) { + _prompt = prompt; +} + +void ConsoleDialog::resetPrompt() { + _prompt = PROMPT; } void ConsoleDialog::slideUpAndClose() { @@ -159,7 +169,7 @@ void ConsoleDialog::open() { if ((_promptStartPos == -1) || (_currentPos > _promptEndPos)) { // we print a prompt, if this is the first time we are called or if the // engine wrote onto us since the last call - print(PROMPT); + print(_prompt.c_str()); _promptStartPos = _promptEndPos = _currentPos; } @@ -283,7 +293,7 @@ void ConsoleDialog::handleKeyDown(Common::KeyState state) { keepRunning = (*_callbackProc)(this, userInput.c_str(), _callbackRefCon); } - print(PROMPT); + print(_prompt.c_str()); _promptStartPos = _promptEndPos = _currentPos; g_gui.scheduleTopDialogRedraw(); diff --git a/gui/console.h b/gui/console.h index 01effcfe5e5a..97b5ca62271e 100644 --- a/gui/console.h +++ b/gui/console.h @@ -129,6 +129,8 @@ class ConsoleDialog : public Dialog { void slideUpAndClose(); + Common::String _prompt; + public: ConsoleDialog(float widthPercent, float heightPercent); virtual ~ConsoleDialog(); @@ -161,6 +163,9 @@ class ConsoleDialog : public Dialog { return _pageWidth; } + void setPrompt(Common::String prompt); + void resetPrompt(); + protected: inline char &buffer(int idx) { return _buffer[idx % kBufferSize]; diff --git a/gui/debugger.cpp b/gui/debugger.cpp index 24d1176e84aa..0a89c950ca24 100644 --- a/gui/debugger.cpp +++ b/gui/debugger.cpp @@ -92,6 +92,18 @@ void Debugger::clearVars() { } +void Debugger::setPrompt(Common::String prompt) { +#ifndef USE_TEXT_CONSOLE_FOR_DEBUGGER + _debuggerDialog->setPrompt(prompt); +#endif +} + +void Debugger::resetPrompt() { +#ifndef USE_TEXT_CONSOLE_FOR_DEBUGGER + _debuggerDialog->resetPrompt(); +#endif +} + // Initialisation Functions int Debugger::getCharsPerLine() { #ifndef USE_TEXT_CONSOLE_FOR_DEBUGGER diff --git a/gui/debugger.h b/gui/debugger.h index d06eaf5cea03..24fb705c93ca 100644 --- a/gui/debugger.h +++ b/gui/debugger.h @@ -168,6 +168,9 @@ class Debugger { */ void clearVars(); + void setPrompt(Common::String prompt); + void resetPrompt(); + private: /** * The frame countdown specifies a number of frames that must pass From d008f85d3c88678b82848b3174e8c7fbc38bda22 Mon Sep 17 00:00:00 2001 From: Eugene Sandulenko Date: Sat, 4 Feb 2023 14:59:31 +0100 Subject: [PATCH 013/412] DIRECTOR: Override debugger prompt in repl mode --- engines/director/debugger.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/engines/director/debugger.cpp b/engines/director/debugger.cpp index c7d5ba20b29d..e219f30dfa0c 100644 --- a/engines/director/debugger.cpp +++ b/engines/director/debugger.cpp @@ -37,7 +37,7 @@ namespace Director { -#define PROMPT "lingo" +#define PROMPT "lingo) " Debugger *g_debugger; @@ -312,7 +312,7 @@ bool Debugger::cmdRepl(int argc, const char **argv) { debugPrintf("Switching to Lingo REPL mode, type 'lingo off' to return to the debug console.\n"); registerDefaultCmd(WRAP_DEFAULTCOMMAND(Debugger, lingoCommandProcessor)); _lingoReplMode = true; - debugPrintf(PROMPT); + setPrompt(PROMPT); return true; } @@ -869,12 +869,11 @@ bool Debugger::lingoCommandProcessor(const char *inputOrig) { if (!strcmp(inputOrig, "lingo off")) { registerDefaultCmd(nullptr); _lingoReplMode = false; + resetPrompt(); return true; } bool ret = lingoEval(inputOrig); - debugPrintf(PROMPT); - return ret; } @@ -887,7 +886,7 @@ bool Debugger::lingoEval(const char *inputOrig) { // Compile the code to an anonymous function and call it ScriptContext *sc = g_lingo->_compiler->compileAnonymous(inputSan); if (!sc) { - debugPrintf("Failed to parse expression!\n%s", _lingoReplMode ? PROMPT : ""); + debugPrintf("Failed to parse expression!\n"); return true; } Symbol sym = sc->_eventHandlers[kEventGeneric]; @@ -916,7 +915,7 @@ void Debugger::stepHook() { if (_lingoEval) { _lingoEval = false; Datum result = g_lingo->pop(); - debugPrintf("%s\n\n%s", result.asString(true).c_str(), _lingoReplMode ? PROMPT : ""); + debugPrintf("%s\n\n", result.asString(true).c_str()); } else { cmdScriptFrame(0, nullptr); } From bacbdf6b69e5484518a46a2e7a3d951d9f74e564 Mon Sep 17 00:00:00 2001 From: Walter Agazzi Date: Sat, 4 Feb 2023 15:17:09 +0100 Subject: [PATCH 014/412] AGS: Add detection for new games * Maniac Mansion Mania 101 * The Devil's Teeth * Super Star Trek 25th --- engines/ags/detection_tables.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/engines/ags/detection_tables.h b/engines/ags/detection_tables.h index 8c5083e65e6f..b7b9d84617ce 100644 --- a/engines/ags/detection_tables.h +++ b/engines/ags/detection_tables.h @@ -1859,6 +1859,7 @@ const PlainGameDescriptor GAME_NAMES[] = { { "mmm98", "Maniac Mansion Mania Ep. 098: Maniac Apartment" }, { "mmm99", "Maniac Mansion Mania Ep. 099: Die Premiere" }, { "mmm100", "Maniac Mansion Mania Ep. 100: Money Mansion" }, + { "mmm101", "Maniac Mansion Mania Ep. 101: Mit anderen Augen" }, { "mmmatman", "Maniac Mansion Mania: @-Man - The Dork Knight" }, { "mmmd1", "Maniac Dungeon Raum 01: The great Escape from Maniac Dungeon" }, { "mmmd2", "Maniac Dungeon Raum 02: Der Bunker" }, @@ -2611,6 +2612,7 @@ const PlainGameDescriptor GAME_NAMES[] = { { "sqvn", "Space Quest Visual Novel" }, { "sqvsb", "Space Quest: Vohaul Strikes Back" }, { "sram2", "SRAM 2 - Cinomeh's Revenge" }, + { "sstrek25", "Super Star Trek 25th" }, { "stablepeteandthejoust", "Stable Pete and the Joust" }, { "stairquest", "Stair Quest" }, { "stanamespiepisode1", "Stan Ames, Private Eye - Episode 1: Murder Incorporated" }, @@ -2765,6 +2767,7 @@ const PlainGameDescriptor GAME_NAMES[] = { { "thedevilsshroudpart2", "The Devil's Shroud - Part II" }, { "thedevilsshroudpart3", "The Devil's Shroud - Part III" }, { "thedevilsshroudpart4", "The Devil's Shroud - Part IV" }, + { "thedevilsteeth", "The Devil's Teeth" }, { "thedigitalspell", "The Digital Spell" }, { "thedisgracedprince", "The disgraced prince" }, { "thedollhousech1", "The Dollhouse - Chapter 1: Plaything" }, @@ -6104,6 +6107,7 @@ const AGSGameDescription GAME_DESCRIPTIONS[] = { GAME_ENTRY_LANG("mmm99", "die_premiere.exe", "3e9c6691d4b9fd70aa47c5bfd68c5c3a", 8312345, Common::DE_DEU), GAME_ENTRY_LANG("mmm100", "money.exe", "93a18fcee8c601539cc99a2bf87f06aa", 51747173, Common::DE_DEU), GAME_ENTRY("mmm100", "money.exe", "91b1d125f9c818b8d2f376d24774377e", 52085746), // En-De + GAME_ENTRY_LANG("mmm101", "MMM_MiAu.exe", "bc40ee6a0cf03a983f9fcaca906d12b8", 7696543, Common::DE_DEU), GAME_ENTRY_LANG("mmmd1", "Starter.exe", "6cddccb3744ec5c6af7c398fb7b3b11c", 5174259, Common::DE_DEU), GAME_ENTRY_LANG("mmmd2", "002.exe", "6cddccb3744ec5c6af7c398fb7b3b11c", 5104718, Common::DE_DEU), GAME_ENTRY_LANG("mmmd3", "003.exe", "6cddccb3744ec5c6af7c398fb7b3b11c", 5275394, Common::DE_DEU), @@ -6950,6 +6954,8 @@ const AGSGameDescription GAME_DESCRIPTIONS[] = { GAME_ENTRY_EN("sqvn", "ENG.exe", "615e73fc1874e92d60a1996c2330ea36", 13629884), GAME_ENTRY_EN("sqvsb", "vsb.exe", "9fc9b41b494ec4a1072e7485ee6113fc", 5632323), GAME_ENTRY_EN("sqvsb", "vsb.exe", "9fc9b41b494ec4a1072e7485ee6113fc", 5631438), + GAME_ENTRY_EN("sstrek25", "startrek.exe", "5cffd228bbf2286b3ea57aaa21087c88", 11737899), // v1.03 Win + GAME_ENTRY_EN("sstrek25", "startrek.ags", "5009a13b7ce87da0dbedc5a171abc22f", 8572183), // v1.03 Mac GAME_ENTRY_EN("stairquest", "Stair Quest.exe", "e0aeab6a2c479fde167c4c43c3abb8ca", 4550699), // v1.0.1 GAME_ENTRY_EN_PLATFORM("stairquest", "stair-quest.exe", "75494269745a5282be12278166cf662c", 33778514, "Special Edition"), // v2.0 itch.io Windows GAME_ENTRY_EN_PLATFORM("stairquest", "ac2game.dat", "75494269745a5282be12278166cf662c", 33778514, "Special Edition"), // v2.0 itch.io Mac @@ -7154,6 +7160,7 @@ const AGSGameDescription GAME_DESCRIPTIONS[] = { GAME_ENTRY_EN("thedevilsshroudpart2", "DevilLyon.exe", "3b7cceb3e4bdb031dc5d8f290936e94b", 23850386), GAME_ENTRY_EN("thedevilsshroudpart3", "DevilPrague.exe", "3b7cceb3e4bdb031dc5d8f290936e94b", 16360454), GAME_ENTRY_EN("thedevilsshroudpart4", "DevilVaduz.exe", "3b7cceb3e4bdb031dc5d8f290936e94b", 32025519), + GAME_ENTRY_EN("thedevilsteeth", "The Devil's Teeth.exe", "0564de07d3fd5c16e6947a647061913c", 12560271), GAME_ENTRY_EN("thedigitalspell", "Digital.exe", "4d17844029d8910fbaae1bdc99e250f2", 14657385), GAME_ENTRY_EN("thedisgracedprince", "Byzanz 2.exe", "23a67b6de10ec35e9f5a4dfc7d928222", 12592231), GAME_ENTRY_EN("thedollhousech1", "DH.exe", "6e861b1f476ff7cdf036082abb271329", 4931346), From be62305248dad42902a0ebc69fbcc67b54c1294d Mon Sep 17 00:00:00 2001 From: Eugene Sandulenko Date: Sat, 4 Feb 2023 15:48:12 +0100 Subject: [PATCH 015/412] DIRECTOR: Implemented debugger commands for drawing bitmapcast outlines and frame number --- engines/director/castmember.cpp | 7 +++++++ engines/director/debugger.cpp | 37 +++++++++++++++++++++++++++++++++ engines/director/debugger.h | 2 ++ engines/director/director.h | 2 ++ engines/director/types.h | 5 +++++ engines/director/window.cpp | 9 ++++++++ 6 files changed, 62 insertions(+) diff --git a/engines/director/castmember.cpp b/engines/director/castmember.cpp index 8ac132a71ffa..1bd0c848077d 100644 --- a/engines/director/castmember.cpp +++ b/engines/director/castmember.cpp @@ -401,6 +401,13 @@ void BitmapCastMember::copyStretchImg(Graphics::Surface *surface, const Common:: } else { surface->copyFrom(*srcSurf); } + + if (g_director->_debugDraw & kDebugDrawCast) { + surface->frameRect(Common::Rect(0, 0, surface->w, surface->h), _wm->_colorWhite); + + const Graphics::Font *font = FontMan.getFontByUsage(Graphics::FontManager::kConsoleFont); + font->drawString(surface, Common::String::format("%d", _castId), 2, 2, 10, _wm->_colorWhite); + } } bool BitmapCastMember::isModified() { diff --git a/engines/director/debugger.cpp b/engines/director/debugger.cpp index e219f30dfa0c..3cb59f28fb7a 100644 --- a/engines/director/debugger.cpp +++ b/engines/director/debugger.cpp @@ -96,6 +96,8 @@ Debugger::Debugger(): GUI::Debugger() { registerCmd("bpdisable", WRAP_METHOD(Debugger, cmdBpDisable)); registerCmd("bplist", WRAP_METHOD(Debugger, cmdBpList)); + registerCmd("draw", WRAP_METHOD(Debugger, cmdDraw)); + _nextFrame = false; _nextFrameCounter = 0; _nextMovie = false; @@ -179,6 +181,9 @@ bool Debugger::cmdHelp(int argc, const char **argv) { debugPrintf(" bpenable [n] - Enables a specific breakpoint\n"); debugPrintf(" bpdisable [n] - Disables a specific breakpoint\n"); debugPrintf(" bplist - Lists all breakpoints\n"); + debugPrintf("\n"); + debugPrintf("GFX:\n"); + debugPrintf(" draw [cast|frame|off] - Draws debug outlines for cast or frame number\n"); return true; } @@ -766,6 +771,38 @@ bool Debugger::cmdBpList(int argc, const char **argv) { return true; } +bool Debugger::cmdDraw(int argc, const char **argv) { + if (argc > 1) { + for (int i = 1; i < argc; i++) { + if (!scumm_stricmp(argv[i], "off")) { + g_director->_debugDraw = 0; + } else if (!scumm_stricmp(argv[i], "cast")) { + g_director->_debugDraw |= kDebugDrawCast; + } else if (!scumm_stricmp(argv[i], "frame")) { + g_director->_debugDraw |= kDebugDrawFrame; + } else { + debugPrintf("Valid parameters are 'cast', 'frame' or 'off'.\n"); + return true; + } + } + } + + debugPrintf("Draw: "); + if (g_director->_debugDraw & kDebugDrawCast) + debugPrintf("cast "); + + if (g_director->_debugDraw & kDebugDrawFrame) + debugPrintf("frame "); + + if (!g_director->_debugDraw) + debugPrintf("off "); + + debugPrintf("\n"); + + return true; +} + + void Debugger::bpUpdateState() { _bpCheckFunc = false; _bpCheckMoviePath = false; diff --git a/engines/director/debugger.h b/engines/director/debugger.h index a1fa5aea017c..16781b7bba6c 100644 --- a/engines/director/debugger.h +++ b/engines/director/debugger.h @@ -141,6 +141,8 @@ class Debugger : public GUI::Debugger { bool cmdBpDisable(int argc, const char **argv); bool cmdBpList(int argc, const char **argv); + bool cmdDraw(int argc, const char **argv); + void bpUpdateState(); void bpTest(bool forceCheck = false); diff --git a/engines/director/director.h b/engines/director/director.h index b0e79f997bda..335439dd149e 100644 --- a/engines/director/director.h +++ b/engines/director/director.h @@ -230,6 +230,8 @@ class DirectorEngine : public ::Engine { Graphics::MacWindowManager *_wm; Graphics::PixelFormat _pixelformat; + uint32 _debugDraw = 0; + public: int _colorDepth; Common::HashMap _KeyCodes; diff --git a/engines/director/types.h b/engines/director/types.h index 227160543d67..7f28f3f569c4 100644 --- a/engines/director/types.h +++ b/engines/director/types.h @@ -400,6 +400,11 @@ enum CompareResult { kCompareError }; +enum DebugDrawModes { + kDebugDrawCast = 1 << 0, + kDebugDrawFrame = 1 << 1, +}; + struct Datum; struct PCell; typedef Common::Array DatumArray; diff --git a/engines/director/window.cpp b/engines/director/window.cpp index 4f4b0039d07b..f8327f629088 100644 --- a/engines/director/window.cpp +++ b/engines/director/window.cpp @@ -170,6 +170,15 @@ bool Window::render(bool forceRedraw, Graphics::ManagedSurface *blitTo) { } } + if (g_director->_debugDraw & kDebugDrawFrame) { + const Graphics::Font *font = FontMan.getFontByUsage(Graphics::FontManager::kConsoleFont); + Common::String msg = Common::String::format("Frame: %d", g_director->getCurrentMovie()->getScore()->getCurrentFrame()); + uint32 width = font->getStringWidth(msg); + + blitTo->fillRect(Common::Rect(blitTo->w - 3 - width, 1, blitTo->w - 1, font->getFontHeight() + 1), _wm->_colorBlack); + font->drawString(blitTo, msg, blitTo->w - 2 - width, 2, width , _wm->_colorWhite); + } + _dirtyRects.clear(); _contentIsDirty = true; From 3a21c360197a39fa67c0cc05f6664f0012e4de2a Mon Sep 17 00:00:00 2001 From: Eugene Sandulenko Date: Sat, 4 Feb 2023 16:44:32 +0100 Subject: [PATCH 016/412] DIRECTOR: Fix build --- engines/director/castmember.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/engines/director/castmember.cpp b/engines/director/castmember.cpp index 1bd0c848077d..4003231b20c9 100644 --- a/engines/director/castmember.cpp +++ b/engines/director/castmember.cpp @@ -403,10 +403,10 @@ void BitmapCastMember::copyStretchImg(Graphics::Surface *surface, const Common:: } if (g_director->_debugDraw & kDebugDrawCast) { - surface->frameRect(Common::Rect(0, 0, surface->w, surface->h), _wm->_colorWhite); + surface->frameRect(Common::Rect(0, 0, surface->w, surface->h), g_director->_wm->_colorWhite); const Graphics::Font *font = FontMan.getFontByUsage(Graphics::FontManager::kConsoleFont); - font->drawString(surface, Common::String::format("%d", _castId), 2, 2, 10, _wm->_colorWhite); + font->drawString(surface, Common::String::format("%d", _castId), 2, 2, 10, g_director->_wm->_colorWhite); } } From c30df70a12b490802fdd447ba189b4194e728c60 Mon Sep 17 00:00:00 2001 From: Matthew Jimenez Date: Sat, 4 Feb 2023 10:37:26 -0600 Subject: [PATCH 017/412] ULTIMA8: Remove debugger.h from pent_include.h --- engines/ultima/ultima8/audio/music_flex.cpp | 2 +- engines/ultima/ultima8/audio/sound_flex.cpp | 2 +- engines/ultima/ultima8/audio/speech_flex.cpp | 1 + engines/ultima/ultima8/audio/speech_flex.h | 1 + engines/ultima/ultima8/conf/config_file_manager.cpp | 2 +- engines/ultima/ultima8/convert/convert_shape.cpp | 2 +- engines/ultima/ultima8/filesys/archive.cpp | 2 +- engines/ultima/ultima8/filesys/archive_file.cpp | 2 +- engines/ultima/ultima8/filesys/flex_file.cpp | 2 +- engines/ultima/ultima8/filesys/raw_archive.cpp | 2 +- engines/ultima/ultima8/filesys/u8_save_file.cpp | 2 +- engines/ultima/ultima8/games/game.cpp | 2 +- engines/ultima/ultima8/games/game_info.cpp | 2 +- engines/ultima/ultima8/games/u8_game.cpp | 2 +- engines/ultima/ultima8/graphics/anim_dat.cpp | 2 +- engines/ultima/ultima8/graphics/fonts/font.cpp | 1 + engines/ultima/ultima8/graphics/fonts/font_shape_archive.cpp | 2 +- engines/ultima/ultima8/graphics/fonts/jp_font.cpp | 1 + engines/ultima/ultima8/graphics/fonts/jp_rendered_text.cpp | 1 + .../ultima/ultima8/graphics/fonts/shape_rendered_text.cpp | 1 + engines/ultima/ultima8/graphics/gump_shape_archive.cpp | 2 +- engines/ultima/ultima8/graphics/main_shape_archive.cpp | 2 +- engines/ultima/ultima8/graphics/palette.cpp | 2 +- engines/ultima/ultima8/graphics/palette_manager.cpp | 2 +- engines/ultima/ultima8/graphics/raw_shape_frame.cpp | 2 +- engines/ultima/ultima8/graphics/render_surface.cpp | 2 +- engines/ultima/ultima8/graphics/shape.cpp | 2 +- engines/ultima/ultima8/graphics/shape_archive.cpp | 2 +- engines/ultima/ultima8/graphics/skf_player.cpp | 2 +- engines/ultima/ultima8/graphics/soft_render_surface.cpp | 2 +- engines/ultima/ultima8/graphics/type_flags.cpp | 2 +- engines/ultima/ultima8/graphics/wpn_ovlay_dat.cpp | 2 +- engines/ultima/ultima8/kernel/kernel.cpp | 1 + engines/ultima/ultima8/kernel/object.h | 1 + engines/ultima/ultima8/kernel/object_manager.cpp | 1 + engines/ultima/ultima8/kernel/process.h | 1 + engines/ultima/ultima8/misc/id_man.cpp | 2 +- engines/ultima/ultima8/misc/pent_include.h | 5 ----- engines/ultima/ultima8/usecode/bit_set.cpp | 2 +- engines/ultima/ultima8/usecode/byte_set.cpp | 2 +- engines/ultima/ultima8/usecode/uc_list.cpp | 2 +- engines/ultima/ultima8/usecode/uc_stack.cpp | 2 +- engines/ultima/ultima8/usecode/usecode_flex.cpp | 2 +- engines/ultima/ultima8/world/actors/actor.cpp | 1 + engines/ultima/ultima8/world/actors/animation_tracker.cpp | 1 + engines/ultima/ultima8/world/actors/npc_dat.cpp | 2 +- engines/ultima/ultima8/world/crosshair_process.cpp | 1 + engines/ultima/ultima8/world/current_map.cpp | 2 +- engines/ultima/ultima8/world/get_object.cpp | 1 + engines/ultima/ultima8/world/map.cpp | 2 +- engines/ultima/ultima8/world/map_glob.cpp | 2 +- engines/ultima/ultima8/world/missile_tracker.cpp | 1 + engines/ultima/ultima8/world/world.cpp | 2 +- 53 files changed, 52 insertions(+), 42 deletions(-) diff --git a/engines/ultima/ultima8/audio/music_flex.cpp b/engines/ultima/ultima8/audio/music_flex.cpp index d863a26596be..ccf3469b3080 100644 --- a/engines/ultima/ultima8/audio/music_flex.cpp +++ b/engines/ultima/ultima8/audio/music_flex.cpp @@ -19,7 +19,7 @@ * */ -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/debugger.h" #include "ultima/ultima8/audio/music_flex.h" #include "common/memstream.h" diff --git a/engines/ultima/ultima8/audio/sound_flex.cpp b/engines/ultima/ultima8/audio/sound_flex.cpp index 6ef6b283db0f..b817faef391b 100644 --- a/engines/ultima/ultima8/audio/sound_flex.cpp +++ b/engines/ultima/ultima8/audio/sound_flex.cpp @@ -19,7 +19,7 @@ * */ -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/debugger.h" #include "ultima/ultima8/audio/sound_flex.h" #include "ultima/ultima8/audio/sonarc_audio_sample.h" diff --git a/engines/ultima/ultima8/audio/speech_flex.cpp b/engines/ultima/ultima8/audio/speech_flex.cpp index c3d9fe1a64aa..90bae2ec1bbd 100644 --- a/engines/ultima/ultima8/audio/speech_flex.cpp +++ b/engines/ultima/ultima8/audio/speech_flex.cpp @@ -19,6 +19,7 @@ * */ +#include "ultima/ultima8/misc/debugger.h" #include "ultima/ultima8/misc/pent_include.h" #include "ultima/ultima8/audio/speech_flex.h" #include "ultima/ultima8/audio/audio_sample.h" diff --git a/engines/ultima/ultima8/audio/speech_flex.h b/engines/ultima/ultima8/audio/speech_flex.h index e5a913d537fb..781851316a7f 100644 --- a/engines/ultima/ultima8/audio/speech_flex.h +++ b/engines/ultima/ultima8/audio/speech_flex.h @@ -24,6 +24,7 @@ #include "ultima/ultima8/audio/sound_flex.h" #include "ultima/shared/std/containers.h" +#include "ultima/ultima8/misc/istring.h" namespace Ultima { namespace Ultima8 { diff --git a/engines/ultima/ultima8/conf/config_file_manager.cpp b/engines/ultima/ultima8/conf/config_file_manager.cpp index 5f3f84266f66..02983f00fe3c 100644 --- a/engines/ultima/ultima8/conf/config_file_manager.cpp +++ b/engines/ultima/ultima8/conf/config_file_manager.cpp @@ -19,7 +19,7 @@ * */ -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/debugger.h" #include "ultima/ultima8/conf/config_file_manager.h" #include "ultima/ultima8/filesys/file_system.h" diff --git a/engines/ultima/ultima8/convert/convert_shape.cpp b/engines/ultima/ultima8/convert/convert_shape.cpp index a88959b6791f..a981a0b8c405 100644 --- a/engines/ultima/ultima8/convert/convert_shape.cpp +++ b/engines/ultima/ultima8/convert/convert_shape.cpp @@ -23,7 +23,7 @@ #include "ultima/ultima.h" #include "ultima/ultima8/convert/convert_shape.h" #include "ultima/ultima8/misc/stream_util.h" -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/debugger.h" namespace Ultima { namespace Ultima8 { diff --git a/engines/ultima/ultima8/filesys/archive.cpp b/engines/ultima/ultima8/filesys/archive.cpp index 1227205de085..dc227f5852f5 100644 --- a/engines/ultima/ultima8/filesys/archive.cpp +++ b/engines/ultima/ultima8/filesys/archive.cpp @@ -19,7 +19,7 @@ * */ -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/debugger.h" #include "ultima/ultima8/filesys/archive.h" #include "ultima/ultima8/filesys/flex_file.h" #include "ultima/ultima8/filesys/u8_save_file.h" diff --git a/engines/ultima/ultima8/filesys/archive_file.cpp b/engines/ultima/ultima8/filesys/archive_file.cpp index 42a7653b903e..1a5392850fa7 100644 --- a/engines/ultima/ultima8/filesys/archive_file.cpp +++ b/engines/ultima/ultima8/filesys/archive_file.cpp @@ -19,7 +19,7 @@ * */ -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/debugger.h" #include "ultima/ultima8/filesys/archive_file.h" #include "common/memstream.h" diff --git a/engines/ultima/ultima8/filesys/flex_file.cpp b/engines/ultima/ultima8/filesys/flex_file.cpp index eb1c3a2f61b2..c5a7249b1532 100644 --- a/engines/ultima/ultima8/filesys/flex_file.cpp +++ b/engines/ultima/ultima8/filesys/flex_file.cpp @@ -19,7 +19,7 @@ * */ -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/debugger.h" #include "ultima/ultima8/filesys/flex_file.h" namespace Ultima { diff --git a/engines/ultima/ultima8/filesys/raw_archive.cpp b/engines/ultima/ultima8/filesys/raw_archive.cpp index 6bea555ba498..0e899f57b900 100644 --- a/engines/ultima/ultima8/filesys/raw_archive.cpp +++ b/engines/ultima/ultima8/filesys/raw_archive.cpp @@ -20,7 +20,7 @@ */ #include "common/memstream.h" -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/debugger.h" #include "ultima/ultima8/filesys/raw_archive.h" namespace Ultima { diff --git a/engines/ultima/ultima8/filesys/u8_save_file.cpp b/engines/ultima/ultima8/filesys/u8_save_file.cpp index 6066f92b1016..8db2fae01bed 100644 --- a/engines/ultima/ultima8/filesys/u8_save_file.cpp +++ b/engines/ultima/ultima8/filesys/u8_save_file.cpp @@ -19,7 +19,7 @@ * */ -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/debugger.h" #include "ultima/ultima8/filesys/u8_save_file.h" diff --git a/engines/ultima/ultima8/games/game.cpp b/engines/ultima/ultima8/games/game.cpp index 76fd077e2e17..c49b0429e58d 100644 --- a/engines/ultima/ultima8/games/game.cpp +++ b/engines/ultima/ultima8/games/game.cpp @@ -21,7 +21,7 @@ #include "common/config-manager.h" -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/debugger.h" #include "ultima/ultima8/games/u8_game.h" #include "ultima/ultima8/games/cru_game.h" #include "ultima/ultima8/graphics/palette_manager.h" diff --git a/engines/ultima/ultima8/games/game_info.cpp b/engines/ultima/ultima8/games/game_info.cpp index 643545fe3e43..c01f8123cb43 100644 --- a/engines/ultima/ultima8/games/game_info.cpp +++ b/engines/ultima/ultima8/games/game_info.cpp @@ -19,7 +19,7 @@ * */ -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/debugger.h" #include "ultima/ultima8/games/game_info.h" #include "ultima/ultima8/misc/util.h" diff --git a/engines/ultima/ultima8/games/u8_game.cpp b/engines/ultima/ultima8/games/u8_game.cpp index 9aa2155a265f..b247ec600db2 100644 --- a/engines/ultima/ultima8/games/u8_game.cpp +++ b/engines/ultima/ultima8/games/u8_game.cpp @@ -21,7 +21,7 @@ #include "common/config-manager.h" -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/debugger.h" #include "ultima/ultima8/games/u8_game.h" diff --git a/engines/ultima/ultima8/graphics/anim_dat.cpp b/engines/ultima/ultima8/graphics/anim_dat.cpp index b5a0351cc759..fb3834de7591 100644 --- a/engines/ultima/ultima8/graphics/anim_dat.cpp +++ b/engines/ultima/ultima8/graphics/anim_dat.cpp @@ -19,7 +19,7 @@ * */ -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/debugger.h" #include "ultima/ultima8/graphics/anim_dat.h" diff --git a/engines/ultima/ultima8/graphics/fonts/font.cpp b/engines/ultima/ultima8/graphics/fonts/font.cpp index 14dc55c7d531..da4e423d7498 100644 --- a/engines/ultima/ultima8/graphics/fonts/font.cpp +++ b/engines/ultima/ultima8/graphics/fonts/font.cpp @@ -20,6 +20,7 @@ */ #include "ultima/ultima.h" +#include "ultima/ultima8/misc/debugger.h" #include "ultima/ultima8/misc/pent_include.h" #include "ultima/ultima8/graphics/fonts/font.h" diff --git a/engines/ultima/ultima8/graphics/fonts/font_shape_archive.cpp b/engines/ultima/ultima8/graphics/fonts/font_shape_archive.cpp index 65a10e3bdbb3..6954fe66b5fe 100644 --- a/engines/ultima/ultima8/graphics/fonts/font_shape_archive.cpp +++ b/engines/ultima/ultima8/graphics/fonts/font_shape_archive.cpp @@ -19,7 +19,7 @@ * */ -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/debugger.h" #include "ultima/ultima8/graphics/fonts/font_shape_archive.h" #include "ultima/ultima8/misc/util.h" diff --git a/engines/ultima/ultima8/graphics/fonts/jp_font.cpp b/engines/ultima/ultima8/graphics/fonts/jp_font.cpp index c7ad7531223a..ad81a0751e2d 100644 --- a/engines/ultima/ultima8/graphics/fonts/jp_font.cpp +++ b/engines/ultima/ultima8/graphics/fonts/jp_font.cpp @@ -19,6 +19,7 @@ * */ +#include "ultima/ultima8/misc/debugger.h" #include "ultima/ultima8/misc/pent_include.h" #include "ultima/ultima8/graphics/fonts/jp_font.h" #include "ultima/ultima8/graphics/fonts/shape_font.h" diff --git a/engines/ultima/ultima8/graphics/fonts/jp_rendered_text.cpp b/engines/ultima/ultima8/graphics/fonts/jp_rendered_text.cpp index 04d41bd6f2ba..f65a4a94455c 100644 --- a/engines/ultima/ultima8/graphics/fonts/jp_rendered_text.cpp +++ b/engines/ultima/ultima8/graphics/fonts/jp_rendered_text.cpp @@ -19,6 +19,7 @@ * */ +#include "ultima/ultima8/misc/debugger.h" #include "ultima/ultima8/misc/pent_include.h" #include "ultima/ultima8/graphics/fonts/jp_rendered_text.h" #include "ultima/ultima8/graphics/fonts/shape_font.h" diff --git a/engines/ultima/ultima8/graphics/fonts/shape_rendered_text.cpp b/engines/ultima/ultima8/graphics/fonts/shape_rendered_text.cpp index 52dc87c80fea..f7ccf2675dd6 100644 --- a/engines/ultima/ultima8/graphics/fonts/shape_rendered_text.cpp +++ b/engines/ultima/ultima8/graphics/fonts/shape_rendered_text.cpp @@ -19,6 +19,7 @@ * */ +#include "ultima/ultima8/misc/debugger.h" #include "ultima/ultima8/misc/pent_include.h" #include "ultima/ultima8/graphics/fonts/shape_rendered_text.h" diff --git a/engines/ultima/ultima8/graphics/gump_shape_archive.cpp b/engines/ultima/ultima8/graphics/gump_shape_archive.cpp index de32d81d0448..bb01ad40fa77 100644 --- a/engines/ultima/ultima8/graphics/gump_shape_archive.cpp +++ b/engines/ultima/ultima8/graphics/gump_shape_archive.cpp @@ -19,7 +19,7 @@ * */ -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/debugger.h" #include "ultima/ultima8/graphics/gump_shape_archive.h" #include "ultima/ultima8/misc/rect.h" diff --git a/engines/ultima/ultima8/graphics/main_shape_archive.cpp b/engines/ultima/ultima8/graphics/main_shape_archive.cpp index 0f2da7b8ad74..1e67f5a94f6e 100644 --- a/engines/ultima/ultima8/graphics/main_shape_archive.cpp +++ b/engines/ultima/ultima8/graphics/main_shape_archive.cpp @@ -19,7 +19,7 @@ * */ -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/debugger.h" #include "ultima/ultima8/graphics/main_shape_archive.h" #include "ultima/ultima8/graphics/type_flags.h" #include "ultima/ultima8/graphics/anim_dat.h" diff --git a/engines/ultima/ultima8/graphics/palette.cpp b/engines/ultima/ultima8/graphics/palette.cpp index bc2eeab57e9e..8629ac3cbd12 100644 --- a/engines/ultima/ultima8/graphics/palette.cpp +++ b/engines/ultima/ultima8/graphics/palette.cpp @@ -19,7 +19,7 @@ * */ -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/debugger.h" #include "ultima/ultima8/graphics/palette.h" namespace Ultima { diff --git a/engines/ultima/ultima8/graphics/palette_manager.cpp b/engines/ultima/ultima8/graphics/palette_manager.cpp index 58119ff73511..0bc46a88cbc9 100644 --- a/engines/ultima/ultima8/graphics/palette_manager.cpp +++ b/engines/ultima/ultima8/graphics/palette_manager.cpp @@ -19,7 +19,7 @@ * */ -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/debugger.h" #include "ultima/ultima8/graphics/palette_manager.h" #include "ultima/ultima8/graphics/render_surface.h" diff --git a/engines/ultima/ultima8/graphics/raw_shape_frame.cpp b/engines/ultima/ultima8/graphics/raw_shape_frame.cpp index 1a5177c41423..f78890878b98 100644 --- a/engines/ultima/ultima8/graphics/raw_shape_frame.cpp +++ b/engines/ultima/ultima8/graphics/raw_shape_frame.cpp @@ -19,7 +19,7 @@ * */ -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/debugger.h" #include "ultima/ultima8/graphics/raw_shape_frame.h" #include "ultima/ultima8/convert/u8/convert_shape_u8.h" diff --git a/engines/ultima/ultima8/graphics/render_surface.cpp b/engines/ultima/ultima8/graphics/render_surface.cpp index 4616213ea1cb..b8a35390985b 100644 --- a/engines/ultima/ultima8/graphics/render_surface.cpp +++ b/engines/ultima/ultima8/graphics/render_surface.cpp @@ -19,7 +19,7 @@ * */ -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/debugger.h" #include "ultima/ultima8/graphics/soft_render_surface.h" #include "ultima/ultima8/graphics/palette.h" #include "ultima/ultima8/graphics/texture.h" diff --git a/engines/ultima/ultima8/graphics/shape.cpp b/engines/ultima/ultima8/graphics/shape.cpp index 1fa4f9dee82c..8b6724941951 100644 --- a/engines/ultima/ultima8/graphics/shape.cpp +++ b/engines/ultima/ultima8/graphics/shape.cpp @@ -19,7 +19,7 @@ * */ -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/debugger.h" #include "ultima/ultima8/graphics/shape.h" #include "ultima/ultima8/graphics/shape_frame.h" diff --git a/engines/ultima/ultima8/graphics/shape_archive.cpp b/engines/ultima/ultima8/graphics/shape_archive.cpp index 6a363be79a6e..0fadb8d0054f 100644 --- a/engines/ultima/ultima8/graphics/shape_archive.cpp +++ b/engines/ultima/ultima8/graphics/shape_archive.cpp @@ -19,7 +19,7 @@ * */ -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/debugger.h" #include "ultima/ultima8/graphics/shape_archive.h" #include "ultima/ultima8/graphics/shape.h" diff --git a/engines/ultima/ultima8/graphics/skf_player.cpp b/engines/ultima/ultima8/graphics/skf_player.cpp index 08b6c86e6c16..c1e8ee60f301 100644 --- a/engines/ultima/ultima8/graphics/skf_player.cpp +++ b/engines/ultima/ultima8/graphics/skf_player.cpp @@ -20,7 +20,7 @@ */ #include "ultima/ultima.h" -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/debugger.h" #include "ultima/ultima8/graphics/skf_player.h" #include "ultima/ultima8/convert/u8/convert_shape_u8.h" #include "ultima/ultima8/filesys/raw_archive.h" diff --git a/engines/ultima/ultima8/graphics/soft_render_surface.cpp b/engines/ultima/ultima8/graphics/soft_render_surface.cpp index aadda655ed88..94cfe786fd18 100644 --- a/engines/ultima/ultima8/graphics/soft_render_surface.cpp +++ b/engines/ultima/ultima8/graphics/soft_render_surface.cpp @@ -19,7 +19,7 @@ * */ -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/debugger.h" #include "ultima/ultima8/graphics/soft_render_surface.h" #include "ultima/ultima8/graphics/shape.h" #include "ultima/ultima8/graphics/shape_frame.h" diff --git a/engines/ultima/ultima8/graphics/type_flags.cpp b/engines/ultima/ultima8/graphics/type_flags.cpp index 15cc152aecd4..0589fa9872ae 100644 --- a/engines/ultima/ultima8/graphics/type_flags.cpp +++ b/engines/ultima/ultima8/graphics/type_flags.cpp @@ -19,7 +19,7 @@ * */ -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/debugger.h" #include "ultima/ultima8/graphics/type_flags.h" #include "ultima/ultima8/conf/config_file_manager.h" diff --git a/engines/ultima/ultima8/graphics/wpn_ovlay_dat.cpp b/engines/ultima/ultima8/graphics/wpn_ovlay_dat.cpp index 3e2bf81eee51..fc873c12e51e 100644 --- a/engines/ultima/ultima8/graphics/wpn_ovlay_dat.cpp +++ b/engines/ultima/ultima8/graphics/wpn_ovlay_dat.cpp @@ -19,7 +19,7 @@ * */ -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/debugger.h" #include "ultima/ultima8/graphics/wpn_ovlay_dat.h" diff --git a/engines/ultima/ultima8/kernel/kernel.cpp b/engines/ultima/ultima8/kernel/kernel.cpp index 387337e43e0e..78db920aac67 100644 --- a/engines/ultima/ultima8/kernel/kernel.cpp +++ b/engines/ultima/ultima8/kernel/kernel.cpp @@ -19,6 +19,7 @@ * */ +#include "ultima/ultima8/misc/debugger.h" #include "ultima/ultima8/misc/pent_include.h" #include "ultima/ultima8/kernel/kernel.h" #include "ultima/ultima8/kernel/process.h" diff --git a/engines/ultima/ultima8/kernel/object.h b/engines/ultima/ultima8/kernel/object.h index 6b9944adbc02..a363d5efd4d2 100644 --- a/engines/ultima/ultima8/kernel/object.h +++ b/engines/ultima/ultima8/kernel/object.h @@ -23,6 +23,7 @@ #define ULTIMA8_KERNEL_OBJECT_H #include "ultima/ultima8/misc/classtype.h" +#include "ultima/ultima8/misc/debugger.h" #include "ultima/ultima8/misc/pent_include.h" namespace Ultima { diff --git a/engines/ultima/ultima8/kernel/object_manager.cpp b/engines/ultima/ultima8/kernel/object_manager.cpp index 354cde2bb18d..31ac11e2b05a 100644 --- a/engines/ultima/ultima8/kernel/object_manager.cpp +++ b/engines/ultima/ultima8/kernel/object_manager.cpp @@ -19,6 +19,7 @@ * */ +#include "ultima/ultima8/misc/debugger.h" #include "ultima/ultima8/misc/pent_include.h" #include "ultima/ultima8/kernel/object_manager.h" #include "ultima/ultima8/misc/id_man.h" diff --git a/engines/ultima/ultima8/kernel/process.h b/engines/ultima/ultima8/kernel/process.h index dda666fd8690..8975c35ddcb2 100644 --- a/engines/ultima/ultima8/kernel/process.h +++ b/engines/ultima/ultima8/kernel/process.h @@ -24,6 +24,7 @@ #include "ultima/shared/std/containers.h" #include "ultima/ultima8/misc/classtype.h" +#include "ultima/ultima8/misc/debugger.h" #include "ultima/ultima8/misc/pent_include.h" namespace Ultima { diff --git a/engines/ultima/ultima8/misc/id_man.cpp b/engines/ultima/ultima8/misc/id_man.cpp index bdd0d2c703ab..ec7ead7acb84 100644 --- a/engines/ultima/ultima8/misc/id_man.cpp +++ b/engines/ultima/ultima8/misc/id_man.cpp @@ -19,7 +19,7 @@ * */ -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/debugger.h" #include "ultima/ultima8/misc/id_man.h" namespace Ultima { diff --git a/engines/ultima/ultima8/misc/pent_include.h b/engines/ultima/ultima8/misc/pent_include.h index 2b0f8a9d6820..a01863c4214f 100644 --- a/engines/ultima/ultima8/misc/pent_include.h +++ b/engines/ultima/ultima8/misc/pent_include.h @@ -40,9 +40,4 @@ #include "ultima/ultima8/misc/istring.h" -// -// The Debugger -// -#include "ultima/ultima8/misc/debugger.h" - #endif diff --git a/engines/ultima/ultima8/usecode/bit_set.cpp b/engines/ultima/ultima8/usecode/bit_set.cpp index ab16eec8dac8..f1ca170b2e87 100644 --- a/engines/ultima/ultima8/usecode/bit_set.cpp +++ b/engines/ultima/ultima8/usecode/bit_set.cpp @@ -19,7 +19,7 @@ * */ -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/debugger.h" #include "ultima/ultima8/usecode/bit_set.h" namespace Ultima { diff --git a/engines/ultima/ultima8/usecode/byte_set.cpp b/engines/ultima/ultima8/usecode/byte_set.cpp index 5b10d06cd58c..275441cd1f6a 100644 --- a/engines/ultima/ultima8/usecode/byte_set.cpp +++ b/engines/ultima/ultima8/usecode/byte_set.cpp @@ -19,7 +19,7 @@ * */ -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/debugger.h" #include "ultima/ultima8/usecode/byte_set.h" namespace Ultima { diff --git a/engines/ultima/ultima8/usecode/uc_list.cpp b/engines/ultima/ultima8/usecode/uc_list.cpp index 4c5e1ba33842..ee22df36b352 100644 --- a/engines/ultima/ultima8/usecode/uc_list.cpp +++ b/engines/ultima/ultima8/usecode/uc_list.cpp @@ -19,7 +19,7 @@ * */ -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/debugger.h" #include "ultima/ultima8/usecode/uc_list.h" #include "ultima/ultima8/usecode/uc_machine.h" diff --git a/engines/ultima/ultima8/usecode/uc_stack.cpp b/engines/ultima/ultima8/usecode/uc_stack.cpp index 7cfd954f75ad..3460c77e6bb6 100644 --- a/engines/ultima/ultima8/usecode/uc_stack.cpp +++ b/engines/ultima/ultima8/usecode/uc_stack.cpp @@ -19,7 +19,7 @@ * */ -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/debugger.h" #include "ultima/ultima8/usecode/uc_stack.h" namespace Ultima { diff --git a/engines/ultima/ultima8/usecode/usecode_flex.cpp b/engines/ultima/ultima8/usecode/usecode_flex.cpp index 8ab16d4fb1a2..def50098a88f 100644 --- a/engines/ultima/ultima8/usecode/usecode_flex.cpp +++ b/engines/ultima/ultima8/usecode/usecode_flex.cpp @@ -19,7 +19,7 @@ * */ -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/debugger.h" #include "ultima/ultima8/usecode/usecode_flex.h" #include "ultima/ultima8/ultima8.h" diff --git a/engines/ultima/ultima8/world/actors/actor.cpp b/engines/ultima/ultima8/world/actors/actor.cpp index 0778a8464688..cb684a671215 100644 --- a/engines/ultima/ultima8/world/actors/actor.cpp +++ b/engines/ultima/ultima8/world/actors/actor.cpp @@ -20,6 +20,7 @@ */ #include "ultima/ultima.h" +#include "ultima/ultima8/misc/debugger.h" #include "ultima/ultima8/misc/pent_include.h" #include "ultima/ultima8/kernel/object_manager.h" #include "ultima/ultima8/kernel/kernel.h" diff --git a/engines/ultima/ultima8/world/actors/animation_tracker.cpp b/engines/ultima/ultima8/world/actors/animation_tracker.cpp index 5462a168b422..bf931d6e6b28 100644 --- a/engines/ultima/ultima8/world/actors/animation_tracker.cpp +++ b/engines/ultima/ultima8/world/actors/animation_tracker.cpp @@ -19,6 +19,7 @@ * */ +#include "ultima/ultima8/misc/debugger.h" #include "ultima/ultima8/misc/pent_include.h" #include "ultima/ultima8/world/actors/animation_tracker.h" #include "ultima/ultima8/games/game_data.h" diff --git a/engines/ultima/ultima8/world/actors/npc_dat.cpp b/engines/ultima/ultima8/world/actors/npc_dat.cpp index 55f8f473e3a1..b071a09c760d 100644 --- a/engines/ultima/ultima8/world/actors/npc_dat.cpp +++ b/engines/ultima/ultima8/world/actors/npc_dat.cpp @@ -19,7 +19,7 @@ * */ -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/debugger.h" #include "ultima/ultima8/world/actors/npc_dat.h" #include "ultima/ultima8/kernel/kernel.h" diff --git a/engines/ultima/ultima8/world/crosshair_process.cpp b/engines/ultima/ultima8/world/crosshair_process.cpp index a0090bef0621..df6e0b28520a 100644 --- a/engines/ultima/ultima8/world/crosshair_process.cpp +++ b/engines/ultima/ultima8/world/crosshair_process.cpp @@ -19,6 +19,7 @@ * */ +#include "ultima/ultima8/misc/debugger.h" #include "ultima/ultima8/misc/pent_include.h" #include "ultima/ultima8/kernel/kernel.h" diff --git a/engines/ultima/ultima8/world/current_map.cpp b/engines/ultima/ultima8/world/current_map.cpp index 3c68d8fbdd67..afe2aae44e62 100644 --- a/engines/ultima/ultima8/world/current_map.cpp +++ b/engines/ultima/ultima8/world/current_map.cpp @@ -20,7 +20,7 @@ */ #include "ultima/ultima.h" -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/debugger.h" #include "ultima/ultima8/world/current_map.h" #include "ultima/ultima8/world/map.h" #include "ultima/ultima8/world/actors/actor.h" diff --git a/engines/ultima/ultima8/world/get_object.cpp b/engines/ultima/ultima8/world/get_object.cpp index 2b360893d824..f3d9a70107a8 100644 --- a/engines/ultima/ultima8/world/get_object.cpp +++ b/engines/ultima/ultima8/world/get_object.cpp @@ -19,6 +19,7 @@ * */ +#include "ultima/ultima8/misc/debugger.h" #include "ultima/ultima8/misc/pent_include.h" #include "ultima/ultima8/kernel/object_manager.h" diff --git a/engines/ultima/ultima8/world/map.cpp b/engines/ultima/ultima8/world/map.cpp index cce00f2131b2..c5e021b5c40c 100644 --- a/engines/ultima/ultima8/world/map.cpp +++ b/engines/ultima/ultima8/world/map.cpp @@ -20,7 +20,7 @@ */ #include "ultima/ultima.h" -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/debugger.h" #include "ultima/ultima8/world/map.h" #include "ultima/ultima8/world/item_factory.h" #include "ultima/ultima8/world/container.h" diff --git a/engines/ultima/ultima8/world/map_glob.cpp b/engines/ultima/ultima8/world/map_glob.cpp index ae2abca94d49..6718511b88cd 100644 --- a/engines/ultima/ultima8/world/map_glob.cpp +++ b/engines/ultima/ultima8/world/map_glob.cpp @@ -19,7 +19,7 @@ * */ -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/debugger.h" #include "ultima/ultima8/world/map_glob.h" diff --git a/engines/ultima/ultima8/world/missile_tracker.cpp b/engines/ultima/ultima8/world/missile_tracker.cpp index 3c2f8913cb92..7e1d9da4a0dd 100644 --- a/engines/ultima/ultima8/world/missile_tracker.cpp +++ b/engines/ultima/ultima8/world/missile_tracker.cpp @@ -20,6 +20,7 @@ */ #include "ultima/ultima.h" +#include "ultima/ultima8/misc/debugger.h" #include "ultima/ultima8/misc/pent_include.h" #include "ultima/ultima8/world/missile_tracker.h" diff --git a/engines/ultima/ultima8/world/world.cpp b/engines/ultima/ultima8/world/world.cpp index 6b27e98f7f8c..fa87458a651d 100644 --- a/engines/ultima/ultima8/world/world.cpp +++ b/engines/ultima/ultima8/world/world.cpp @@ -19,7 +19,7 @@ * */ -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/debugger.h" #include "ultima/ultima8/world/world.h" #include "ultima/ultima8/world/map.h" #include "ultima/ultima8/world/current_map.h" From 7ea747ff4011b667777a4565d41c8e5de6c8da49 Mon Sep 17 00:00:00 2001 From: Matthew Jimenez Date: Sat, 4 Feb 2023 10:54:23 -0600 Subject: [PATCH 018/412] ULTIMA8: Remove istring.h from pent_include.h --- engines/ultima/ultima8/games/game_data.h | 1 + engines/ultima/ultima8/graphics/fonts/font.h | 1 + engines/ultima/ultima8/graphics/fonts/font_manager.h | 1 + engines/ultima/ultima8/gumps/bark_gump.h | 1 + engines/ultima/ultima8/gumps/book_gump.h | 1 + engines/ultima/ultima8/gumps/computer_gump.cpp | 1 + engines/ultima/ultima8/gumps/credits_gump.h | 1 + engines/ultima/ultima8/gumps/cru_pickup_gump.h | 1 + engines/ultima/ultima8/gumps/message_box_gump.h | 1 + engines/ultima/ultima8/gumps/movie_gump.h | 1 + engines/ultima/ultima8/gumps/paperdoll_gump.h | 1 + engines/ultima/ultima8/gumps/readable_gump.h | 1 + engines/ultima/ultima8/gumps/scroll_gump.h | 1 + engines/ultima/ultima8/gumps/u8_save_gump.h | 1 + engines/ultima/ultima8/gumps/weasel_gump.h | 1 + engines/ultima/ultima8/gumps/widgets/button_widget.h | 1 + engines/ultima/ultima8/kernel/kernel.h | 1 + engines/ultima/ultima8/kernel/object_manager.h | 1 + engines/ultima/ultima8/misc/pent_include.h | 7 ------- engines/ultima/ultima8/usecode/uc_machine.h | 1 + 20 files changed, 19 insertions(+), 7 deletions(-) diff --git a/engines/ultima/ultima8/games/game_data.h b/engines/ultima/ultima8/games/game_data.h index 9dbb56deeb50..c783f1049e3b 100644 --- a/engines/ultima/ultima8/games/game_data.h +++ b/engines/ultima/ultima8/games/game_data.h @@ -23,6 +23,7 @@ #define ULTIMA8_GAMES_GAMEDATA_H #include "ultima/shared/std/containers.h" +#include "ultima/shared/std/string.h" #include "ultima/ultima8/graphics/frame_id.h" namespace Ultima { diff --git a/engines/ultima/ultima8/graphics/fonts/font.h b/engines/ultima/ultima8/graphics/fonts/font.h index 72676148ad31..e098ad5d0b03 100644 --- a/engines/ultima/ultima8/graphics/fonts/font.h +++ b/engines/ultima/ultima8/graphics/fonts/font.h @@ -23,6 +23,7 @@ #define ULTIMA8_GRAPHICS_FONTS_FONT_H #include "ultima/shared/std/containers.h" +#include "ultima/shared/std/string.h" #include "ultima/ultima8/misc/rect.h" #include "ultima/ultima8/misc/encoding.h" diff --git a/engines/ultima/ultima8/graphics/fonts/font_manager.h b/engines/ultima/ultima8/graphics/fonts/font_manager.h index e4c95b00cf32..9104425831ec 100644 --- a/engines/ultima/ultima8/graphics/fonts/font_manager.h +++ b/engines/ultima/ultima8/graphics/fonts/font_manager.h @@ -23,6 +23,7 @@ #define ULTIMA8_GRAPHICS_FONTS_FONTMANAGER_H #include "ultima/shared/std/containers.h" +#include "ultima/shared/std/string.h" #include "graphics/font.h" namespace Ultima { diff --git a/engines/ultima/ultima8/gumps/bark_gump.h b/engines/ultima/ultima8/gumps/bark_gump.h index e20bce184f68..3fde5fbeca11 100644 --- a/engines/ultima/ultima8/gumps/bark_gump.h +++ b/engines/ultima/ultima8/gumps/bark_gump.h @@ -22,6 +22,7 @@ #ifndef ULTIMA8_GUMPS_BARKGUMP_H #define ULTIMA8_GUMPS_BARKGUMP_H +#include "ultima/shared/std/string.h" #include "ultima/ultima8/gumps/item_relative_gump.h" #include "ultima/ultima8/misc/classtype.h" diff --git a/engines/ultima/ultima8/gumps/book_gump.h b/engines/ultima/ultima8/gumps/book_gump.h index 606bde2dfba7..31132149b7ba 100644 --- a/engines/ultima/ultima8/gumps/book_gump.h +++ b/engines/ultima/ultima8/gumps/book_gump.h @@ -22,6 +22,7 @@ #ifndef ULTIMA8_GUMPS_BOOKGUMP_H #define ULTIMA8_GUMPS_BOOKGUMP_H +#include "ultima/shared/std/string.h" #include "ultima/ultima8/gumps/modal_gump.h" #include "ultima/ultima8/usecode/intrinsics.h" #include "ultima/ultima8/misc/classtype.h" diff --git a/engines/ultima/ultima8/gumps/computer_gump.cpp b/engines/ultima/ultima8/gumps/computer_gump.cpp index 10e2f5b7bb3a..4e4a6ddb5a57 100644 --- a/engines/ultima/ultima8/gumps/computer_gump.cpp +++ b/engines/ultima/ultima8/gumps/computer_gump.cpp @@ -21,6 +21,7 @@ #include "common/keyboard.h" +#include "ultima/shared/std/string.h" #include "ultima/ultima8/gumps/computer_gump.h" #include "ultima/ultima8/games/game_data.h" #include "ultima/ultima8/audio/audio_process.h" diff --git a/engines/ultima/ultima8/gumps/credits_gump.h b/engines/ultima/ultima8/gumps/credits_gump.h index ca33c25bb12a..1a643e1ef6bc 100644 --- a/engines/ultima/ultima8/gumps/credits_gump.h +++ b/engines/ultima/ultima8/gumps/credits_gump.h @@ -22,6 +22,7 @@ #ifndef ULTIMA8_GUMPS_CREDITSGUMP_H #define ULTIMA8_GUMPS_CREDITSGUMP_H +#include "ultima/shared/std/string.h" #include "ultima/ultima8/gumps/modal_gump.h" #include "ultima/ultima8/misc/classtype.h" diff --git a/engines/ultima/ultima8/gumps/cru_pickup_gump.h b/engines/ultima/ultima8/gumps/cru_pickup_gump.h index 26a1b9ce30d3..cc328c15f2a0 100644 --- a/engines/ultima/ultima8/gumps/cru_pickup_gump.h +++ b/engines/ultima/ultima8/gumps/cru_pickup_gump.h @@ -22,6 +22,7 @@ #ifndef ULTIMA8_GUMPS_CRUPICKUPGUMP_H #define ULTIMA8_GUMPS_CRUPICKUPGUMP_H +#include "ultima/shared/std/string.h" #include "ultima/ultima8/gumps/gump.h" #include "ultima/ultima8/misc/classtype.h" diff --git a/engines/ultima/ultima8/gumps/message_box_gump.h b/engines/ultima/ultima8/gumps/message_box_gump.h index 93df5bbeb4eb..0f5302fd7580 100644 --- a/engines/ultima/ultima8/gumps/message_box_gump.h +++ b/engines/ultima/ultima8/gumps/message_box_gump.h @@ -25,6 +25,7 @@ #include "ultima/ultima8/gumps/modal_gump.h" #include "ultima/ultima8/usecode/intrinsics.h" +#include "ultima/shared/std/string.h" #include "ultima/shared/std/containers.h" #include "ultima/ultima8/misc/classtype.h" diff --git a/engines/ultima/ultima8/gumps/movie_gump.h b/engines/ultima/ultima8/gumps/movie_gump.h index dd1637556fb5..b6e942a4c949 100644 --- a/engines/ultima/ultima8/gumps/movie_gump.h +++ b/engines/ultima/ultima8/gumps/movie_gump.h @@ -22,6 +22,7 @@ #ifndef ULTIMA8_GUMPS_MOVIEGUMP_H #define ULTIMA8_GUMPS_MOVIEGUMP_H +#include "ultima/shared/std/string.h" #include "ultima/ultima8/gumps/modal_gump.h" #include "ultima/ultima8/usecode/intrinsics.h" #include "ultima/ultima8/misc/classtype.h" diff --git a/engines/ultima/ultima8/gumps/paperdoll_gump.h b/engines/ultima/ultima8/gumps/paperdoll_gump.h index f65b93c3de4d..9ef786196dd2 100644 --- a/engines/ultima/ultima8/gumps/paperdoll_gump.h +++ b/engines/ultima/ultima8/gumps/paperdoll_gump.h @@ -22,6 +22,7 @@ #ifndef ULTIMA8_GUMPS_PAPERDOLLGUMP_H #define ULTIMA8_GUMPS_PAPERDOLLGUMP_H +#include "ultima/shared/std/string.h" #include "ultima/ultima8/gumps/container_gump.h" #include "ultima/ultima8/misc/classtype.h" diff --git a/engines/ultima/ultima8/gumps/readable_gump.h b/engines/ultima/ultima8/gumps/readable_gump.h index c83088c68668..83de65a9eca4 100644 --- a/engines/ultima/ultima8/gumps/readable_gump.h +++ b/engines/ultima/ultima8/gumps/readable_gump.h @@ -22,6 +22,7 @@ #ifndef ULTIMA8_GUMPS_READABLEGUMP_H #define ULTIMA8_GUMPS_READABLEGUMP_H +#include "ultima/shared/std/string.h" #include "ultima/ultima8/gumps/modal_gump.h" #include "ultima/ultima8/usecode/intrinsics.h" #include "ultima/ultima8/misc/classtype.h" diff --git a/engines/ultima/ultima8/gumps/scroll_gump.h b/engines/ultima/ultima8/gumps/scroll_gump.h index bfbbc8905921..8e3abca42de1 100644 --- a/engines/ultima/ultima8/gumps/scroll_gump.h +++ b/engines/ultima/ultima8/gumps/scroll_gump.h @@ -22,6 +22,7 @@ #ifndef ULTIMA8_GUMPS_SCROLLGUMP_H #define ULTIMA8_GUMPS_SCROLLGUMP_H +#include "ultima/shared/std/string.h" #include "ultima/ultima8/gumps/modal_gump.h" #include "ultima/ultima8/usecode/intrinsics.h" #include "ultima/ultima8/misc/classtype.h" diff --git a/engines/ultima/ultima8/gumps/u8_save_gump.h b/engines/ultima/ultima8/gumps/u8_save_gump.h index 6f54456c15c5..16090162499b 100644 --- a/engines/ultima/ultima8/gumps/u8_save_gump.h +++ b/engines/ultima/ultima8/gumps/u8_save_gump.h @@ -22,6 +22,7 @@ #ifndef ULTIMA8_GUMPS_U8SAVEGUMP_H #define ULTIMA8_GUMPS_U8SAVEGUMP_H +#include "ultima/shared/std/string.h" #include "ultima/ultima8/gumps/gump.h" #include "ultima/ultima8/misc/classtype.h" diff --git a/engines/ultima/ultima8/gumps/weasel_gump.h b/engines/ultima/ultima8/gumps/weasel_gump.h index 07f0fe9897f0..c0b52144d639 100644 --- a/engines/ultima/ultima8/gumps/weasel_gump.h +++ b/engines/ultima/ultima8/gumps/weasel_gump.h @@ -22,6 +22,7 @@ #ifndef ULTIMA8_GUMPS_REMORSEMENUGUMP_H #define ULTIMA8_GUMPS_REMORSEMENUGUMP_H +#include "ultima/shared/std/string.h" #include "ultima/ultima8/gumps/modal_gump.h" #include "ultima/ultima8/misc/classtype.h" diff --git a/engines/ultima/ultima8/gumps/widgets/button_widget.h b/engines/ultima/ultima8/gumps/widgets/button_widget.h index 54333a7a3958..6a1a24dfa597 100644 --- a/engines/ultima/ultima8/gumps/widgets/button_widget.h +++ b/engines/ultima/ultima8/gumps/widgets/button_widget.h @@ -22,6 +22,7 @@ #ifndef ULTIMA8_GUMPS_WIDGETS_BUTTONWIDGET_H #define ULTIMA8_GUMPS_WIDGETS_BUTTONWIDGET_H +#include "ultima/shared/std/string.h" #include "ultima/ultima8/gumps/gump.h" #include "ultima/ultima8/graphics/frame_id.h" #include "ultima/ultima8/misc/classtype.h" diff --git a/engines/ultima/ultima8/kernel/kernel.h b/engines/ultima/ultima8/kernel/kernel.h index 7de322e5b89f..508844dfc084 100644 --- a/engines/ultima/ultima8/kernel/kernel.h +++ b/engines/ultima/ultima8/kernel/kernel.h @@ -23,6 +23,7 @@ #define ULTIMA8_KERNEL_KERNEL_H #include "ultima/shared/std/containers.h" +#include "ultima/shared/std/string.h" #include "ultima/ultima8/usecode/intrinsics.h" namespace Ultima { diff --git a/engines/ultima/ultima8/kernel/object_manager.h b/engines/ultima/ultima8/kernel/object_manager.h index 47c0329c176e..d6f2d3204b01 100644 --- a/engines/ultima/ultima8/kernel/object_manager.h +++ b/engines/ultima/ultima8/kernel/object_manager.h @@ -22,6 +22,7 @@ #ifndef ULTIMA8_KERNEL_OBJECTMANAGER_H #define ULTIMA8_KERNEL_OBJECTMANAGER_H +#include "ultima/shared/std/string.h" #include "ultima/shared/std/containers.h" #include "ultima/ultima8/misc/common_types.h" diff --git a/engines/ultima/ultima8/misc/pent_include.h b/engines/ultima/ultima8/misc/pent_include.h index a01863c4214f..10c15c6333fb 100644 --- a/engines/ultima/ultima8/misc/pent_include.h +++ b/engines/ultima/ultima8/misc/pent_include.h @@ -33,11 +33,4 @@ // #include "ultima/ultima8/misc/classtype.h" - -// -// Strings -// -#include "ultima/ultima8/misc/istring.h" - - #endif diff --git a/engines/ultima/ultima8/usecode/uc_machine.h b/engines/ultima/ultima8/usecode/uc_machine.h index 0fc9658ddb81..4c15ac29c44e 100644 --- a/engines/ultima/ultima8/usecode/uc_machine.h +++ b/engines/ultima/ultima8/usecode/uc_machine.h @@ -23,6 +23,7 @@ #define ULTIMA8_USECODE_UCMACHINE_H #include "ultima/ultima8/misc/common_types.h" +#include "ultima/shared/std/string.h" #include "ultima/shared/std/containers.h" #include "ultima/ultima8/usecode/intrinsics.h" From bbc32662993539899946494a2eef3d4bf0978f88 Mon Sep 17 00:00:00 2001 From: Matthew Jimenez Date: Sat, 4 Feb 2023 11:10:53 -0600 Subject: [PATCH 019/412] ULTIMA8: Remove pent_include.h --- .../ultima/ultima8/audio/audio_channel.cpp | 2 +- engines/ultima/ultima8/audio/audio_sample.cpp | 2 +- .../ultima/ultima8/audio/raw_audio_sample.cpp | 2 +- .../ultima8/audio/sonarc_audio_sample.cpp | 2 +- engines/ultima/ultima8/audio/speech_flex.cpp | 2 +- engines/ultima/ultima8/games/cru_game.cpp | 2 +- engines/ultima/ultima8/games/game_data.cpp | 2 +- .../ultima/ultima8/games/treasure_loader.cpp | 2 +- .../ultima/ultima8/graphics/fonts/font.cpp | 2 +- .../ultima8/graphics/fonts/font_manager.cpp | 2 +- .../ultima/ultima8/graphics/fonts/jp_font.cpp | 2 +- .../graphics/fonts/jp_rendered_text.cpp | 2 +- .../ultima8/graphics/fonts/rendered_text.cpp | 2 +- .../ultima8/graphics/fonts/shape_font.cpp | 2 +- .../graphics/fonts/shape_rendered_text.cpp | 1 - .../ultima/ultima8/graphics/fonts/tt_font.cpp | 2 +- .../graphics/fonts/ttf_rendered_text.cpp | 2 +- engines/ultima/ultima8/graphics/frame_id.cpp | 1 - .../ultima/ultima8/graphics/shape_frame.cpp | 2 +- .../ultima/ultima8/graphics/shape_info.cpp | 2 +- engines/ultima/ultima8/kernel/kernel.cpp | 1 - engines/ultima/ultima8/kernel/mouse.cpp | 1 - engines/ultima/ultima8/kernel/object.h | 1 - .../ultima/ultima8/kernel/object_manager.cpp | 1 - engines/ultima/ultima8/kernel/process.h | 1 - engines/ultima/ultima8/misc/encoding.cpp | 2 +- engines/ultima/ultima8/misc/pent_include.h | 36 ------------------- engines/ultima/ultima8/usecode/uc_machine.cpp | 1 - engines/ultima/ultima8/usecode/usecode.cpp | 2 +- engines/ultima/ultima8/world/actors/actor.cpp | 1 - .../ultima/ultima8/world/actors/animation.cpp | 1 - .../world/actors/animation_tracker.cpp | 1 - .../ultima8/world/actors/combat_dat.cpp | 1 - .../ultima8/world/crosshair_process.cpp | 1 - .../ultima/ultima8/world/fire_type_table.cpp | 2 +- engines/ultima/ultima8/world/get_object.cpp | 1 - engines/ultima/ultima8/world/item_factory.cpp | 2 +- engines/ultima/ultima8/world/item_sorter.cpp | 2 +- .../ultima/ultima8/world/missile_tracker.cpp | 1 - 39 files changed, 23 insertions(+), 74 deletions(-) delete mode 100644 engines/ultima/ultima8/misc/pent_include.h diff --git a/engines/ultima/ultima8/audio/audio_channel.cpp b/engines/ultima/ultima8/audio/audio_channel.cpp index cb569ee6178d..a80e05311a10 100644 --- a/engines/ultima/ultima8/audio/audio_channel.cpp +++ b/engines/ultima/ultima8/audio/audio_channel.cpp @@ -19,7 +19,7 @@ * */ -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/common_types.h" #include "ultima/ultima8/audio/audio_channel.h" #include "ultima/ultima8/audio/audio_sample.h" #include "common/memstream.h" diff --git a/engines/ultima/ultima8/audio/audio_sample.cpp b/engines/ultima/ultima8/audio/audio_sample.cpp index 40ff6b73cd8a..40aeb4e77d3c 100644 --- a/engines/ultima/ultima8/audio/audio_sample.cpp +++ b/engines/ultima/ultima8/audio/audio_sample.cpp @@ -19,7 +19,7 @@ * */ -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/common_types.h" #include "ultima/ultima8/audio/audio_sample.h" namespace Ultima { diff --git a/engines/ultima/ultima8/audio/raw_audio_sample.cpp b/engines/ultima/ultima8/audio/raw_audio_sample.cpp index 0a5b2feb5cdc..787f41553d87 100644 --- a/engines/ultima/ultima8/audio/raw_audio_sample.cpp +++ b/engines/ultima/ultima8/audio/raw_audio_sample.cpp @@ -19,7 +19,7 @@ * */ -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/common_types.h" #include "ultima/ultima8/audio/raw_audio_sample.h" namespace Ultima { diff --git a/engines/ultima/ultima8/audio/sonarc_audio_sample.cpp b/engines/ultima/ultima8/audio/sonarc_audio_sample.cpp index 260ccbd72392..d008c28f2053 100644 --- a/engines/ultima/ultima8/audio/sonarc_audio_sample.cpp +++ b/engines/ultima/ultima8/audio/sonarc_audio_sample.cpp @@ -19,7 +19,7 @@ * */ -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/common_types.h" #include "ultima/ultima8/audio/sonarc_audio_sample.h" namespace Ultima { diff --git a/engines/ultima/ultima8/audio/speech_flex.cpp b/engines/ultima/ultima8/audio/speech_flex.cpp index 90bae2ec1bbd..670addb12942 100644 --- a/engines/ultima/ultima8/audio/speech_flex.cpp +++ b/engines/ultima/ultima8/audio/speech_flex.cpp @@ -20,7 +20,7 @@ */ #include "ultima/ultima8/misc/debugger.h" -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/common_types.h" #include "ultima/ultima8/audio/speech_flex.h" #include "ultima/ultima8/audio/audio_sample.h" #include "ultima/ultima8/misc/util.h" diff --git a/engines/ultima/ultima8/games/cru_game.cpp b/engines/ultima/ultima8/games/cru_game.cpp index 6f31479bdd22..e6b59bcb219b 100644 --- a/engines/ultima/ultima8/games/cru_game.cpp +++ b/engines/ultima/ultima8/games/cru_game.cpp @@ -22,7 +22,7 @@ #include "common/config-manager.h" #include "common/translation.h" -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/common_types.h" #include "ultima/ultima8/games/cru_game.h" #include "ultima/ultima8/games/start_crusader_process.h" #include "ultima/ultima8/filesys/file_system.h" diff --git a/engines/ultima/ultima8/games/game_data.cpp b/engines/ultima/ultima8/games/game_data.cpp index 61bbddc1fd99..de949e798192 100644 --- a/engines/ultima/ultima8/games/game_data.cpp +++ b/engines/ultima/ultima8/games/game_data.cpp @@ -21,7 +21,7 @@ #include "common/config-manager.h" -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/common_types.h" #include "ultima/ultima8/misc/util.h" #include "ultima/ultima8/games/game_data.h" #include "ultima/ultima8/filesys/file_system.h" diff --git a/engines/ultima/ultima8/games/treasure_loader.cpp b/engines/ultima/ultima8/games/treasure_loader.cpp index 2f8a3ffb1eb0..447b3331d375 100644 --- a/engines/ultima/ultima8/games/treasure_loader.cpp +++ b/engines/ultima/ultima8/games/treasure_loader.cpp @@ -19,7 +19,7 @@ * */ -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/common_types.h" #include "ultima/ultima8/games/treasure_loader.h" #include "ultima/ultima8/conf/config_file_manager.h" diff --git a/engines/ultima/ultima8/graphics/fonts/font.cpp b/engines/ultima/ultima8/graphics/fonts/font.cpp index da4e423d7498..e7fd531831a0 100644 --- a/engines/ultima/ultima8/graphics/fonts/font.cpp +++ b/engines/ultima/ultima8/graphics/fonts/font.cpp @@ -21,7 +21,7 @@ #include "ultima/ultima.h" #include "ultima/ultima8/misc/debugger.h" -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/common_types.h" #include "ultima/ultima8/graphics/fonts/font.h" namespace Ultima { diff --git a/engines/ultima/ultima8/graphics/fonts/font_manager.cpp b/engines/ultima/ultima8/graphics/fonts/font_manager.cpp index 4acfbd594b57..8092eb47e357 100644 --- a/engines/ultima/ultima8/graphics/fonts/font_manager.cpp +++ b/engines/ultima/ultima8/graphics/fonts/font_manager.cpp @@ -20,7 +20,7 @@ */ #include "ultima/ultima.h" -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/common_types.h" #include "ultima/ultima8/graphics/fonts/font_manager.h" diff --git a/engines/ultima/ultima8/graphics/fonts/jp_font.cpp b/engines/ultima/ultima8/graphics/fonts/jp_font.cpp index ad81a0751e2d..3bf4d179abe0 100644 --- a/engines/ultima/ultima8/graphics/fonts/jp_font.cpp +++ b/engines/ultima/ultima8/graphics/fonts/jp_font.cpp @@ -20,7 +20,7 @@ */ #include "ultima/ultima8/misc/debugger.h" -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/common_types.h" #include "ultima/ultima8/graphics/fonts/jp_font.h" #include "ultima/ultima8/graphics/fonts/shape_font.h" #include "ultima/ultima8/graphics/shape_frame.h" diff --git a/engines/ultima/ultima8/graphics/fonts/jp_rendered_text.cpp b/engines/ultima/ultima8/graphics/fonts/jp_rendered_text.cpp index f65a4a94455c..573ac943d086 100644 --- a/engines/ultima/ultima8/graphics/fonts/jp_rendered_text.cpp +++ b/engines/ultima/ultima8/graphics/fonts/jp_rendered_text.cpp @@ -20,7 +20,7 @@ */ #include "ultima/ultima8/misc/debugger.h" -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/common_types.h" #include "ultima/ultima8/graphics/fonts/jp_rendered_text.h" #include "ultima/ultima8/graphics/fonts/shape_font.h" #include "ultima/ultima8/graphics/render_surface.h" diff --git a/engines/ultima/ultima8/graphics/fonts/rendered_text.cpp b/engines/ultima/ultima8/graphics/fonts/rendered_text.cpp index 229dce9818ed..85a43e9e9961 100644 --- a/engines/ultima/ultima8/graphics/fonts/rendered_text.cpp +++ b/engines/ultima/ultima8/graphics/fonts/rendered_text.cpp @@ -19,7 +19,7 @@ * */ -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/common_types.h" #include "ultima/ultima8/graphics/fonts/rendered_text.h" namespace Ultima { diff --git a/engines/ultima/ultima8/graphics/fonts/shape_font.cpp b/engines/ultima/ultima8/graphics/fonts/shape_font.cpp index fd89fea91246..6ad278e353cd 100644 --- a/engines/ultima/ultima8/graphics/fonts/shape_font.cpp +++ b/engines/ultima/ultima8/graphics/fonts/shape_font.cpp @@ -19,7 +19,7 @@ * */ -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/common_types.h" #include "ultima/ultima8/ultima8.h" #include "ultima/ultima8/graphics/fonts/shape_font.h" #include "ultima/ultima8/graphics/shape_frame.h" diff --git a/engines/ultima/ultima8/graphics/fonts/shape_rendered_text.cpp b/engines/ultima/ultima8/graphics/fonts/shape_rendered_text.cpp index f7ccf2675dd6..9ba44def4e92 100644 --- a/engines/ultima/ultima8/graphics/fonts/shape_rendered_text.cpp +++ b/engines/ultima/ultima8/graphics/fonts/shape_rendered_text.cpp @@ -20,7 +20,6 @@ */ #include "ultima/ultima8/misc/debugger.h" -#include "ultima/ultima8/misc/pent_include.h" #include "ultima/ultima8/graphics/fonts/shape_rendered_text.h" #include "ultima/ultima8/graphics/fonts/shape_font.h" diff --git a/engines/ultima/ultima8/graphics/fonts/tt_font.cpp b/engines/ultima/ultima8/graphics/fonts/tt_font.cpp index 7ac15eb92565..2a13f1a897a0 100644 --- a/engines/ultima/ultima8/graphics/fonts/tt_font.cpp +++ b/engines/ultima/ultima8/graphics/fonts/tt_font.cpp @@ -19,7 +19,7 @@ * */ -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/common_types.h" #include "ultima/ultima8/graphics/fonts/tt_font.h" #include "ultima/ultima8/graphics/fonts/ttf_rendered_text.h" #include "ultima/ultima8/graphics/texture.h" diff --git a/engines/ultima/ultima8/graphics/fonts/ttf_rendered_text.cpp b/engines/ultima/ultima8/graphics/fonts/ttf_rendered_text.cpp index 1fb02b4b1564..055813bf3ab1 100644 --- a/engines/ultima/ultima8/graphics/fonts/ttf_rendered_text.cpp +++ b/engines/ultima/ultima8/graphics/fonts/ttf_rendered_text.cpp @@ -19,7 +19,7 @@ * */ -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/common_types.h" #include "ultima/ultima8/graphics/fonts/ttf_rendered_text.h" #include "ultima/ultima8/graphics/fonts/tt_font.h" #include "ultima/ultima8/graphics/render_surface.h" diff --git a/engines/ultima/ultima8/graphics/frame_id.cpp b/engines/ultima/ultima8/graphics/frame_id.cpp index 74e0b25619f1..6a6fcc7b7fb7 100644 --- a/engines/ultima/ultima8/graphics/frame_id.cpp +++ b/engines/ultima/ultima8/graphics/frame_id.cpp @@ -19,7 +19,6 @@ * */ -#include "ultima/ultima8/misc/pent_include.h" #include "ultima/ultima8/graphics/frame_id.h" namespace Ultima { diff --git a/engines/ultima/ultima8/graphics/shape_frame.cpp b/engines/ultima/ultima8/graphics/shape_frame.cpp index b62c900876d2..3b430d21ae93 100644 --- a/engines/ultima/ultima8/graphics/shape_frame.cpp +++ b/engines/ultima/ultima8/graphics/shape_frame.cpp @@ -19,7 +19,7 @@ * */ -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/common_types.h" #include "ultima/ultima8/graphics/shape_frame.h" #include "ultima/ultima8/graphics/raw_shape_frame.h" diff --git a/engines/ultima/ultima8/graphics/shape_info.cpp b/engines/ultima/ultima8/graphics/shape_info.cpp index bca4258eb0bf..e4e9073cb675 100644 --- a/engines/ultima/ultima8/graphics/shape_info.cpp +++ b/engines/ultima/ultima8/graphics/shape_info.cpp @@ -19,7 +19,7 @@ * */ -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/common_types.h" #include "ultima/ultima8/graphics/shape_info.h" #include "ultima/ultima8/ultima8.h" diff --git a/engines/ultima/ultima8/kernel/kernel.cpp b/engines/ultima/ultima8/kernel/kernel.cpp index 78db920aac67..21d1d1e461cf 100644 --- a/engines/ultima/ultima8/kernel/kernel.cpp +++ b/engines/ultima/ultima8/kernel/kernel.cpp @@ -20,7 +20,6 @@ */ #include "ultima/ultima8/misc/debugger.h" -#include "ultima/ultima8/misc/pent_include.h" #include "ultima/ultima8/kernel/kernel.h" #include "ultima/ultima8/kernel/process.h" #include "ultima/ultima8/misc/id_man.h" diff --git a/engines/ultima/ultima8/kernel/mouse.cpp b/engines/ultima/ultima8/kernel/mouse.cpp index efd41cb07b76..19aca88d6fe1 100644 --- a/engines/ultima/ultima8/kernel/mouse.cpp +++ b/engines/ultima/ultima8/kernel/mouse.cpp @@ -22,7 +22,6 @@ #include "graphics/cursorman.h" #include "ultima/ultima.h" #include "ultima/ultima8/kernel/mouse.h" -#include "ultima/ultima8/misc/pent_include.h" #include "ultima/ultima8/games/game_data.h" #include "ultima/ultima8/graphics/render_surface.h" #include "ultima/ultima8/gumps/gump.h" diff --git a/engines/ultima/ultima8/kernel/object.h b/engines/ultima/ultima8/kernel/object.h index a363d5efd4d2..bcf554a896a1 100644 --- a/engines/ultima/ultima8/kernel/object.h +++ b/engines/ultima/ultima8/kernel/object.h @@ -24,7 +24,6 @@ #include "ultima/ultima8/misc/classtype.h" #include "ultima/ultima8/misc/debugger.h" -#include "ultima/ultima8/misc/pent_include.h" namespace Ultima { namespace Ultima8 { diff --git a/engines/ultima/ultima8/kernel/object_manager.cpp b/engines/ultima/ultima8/kernel/object_manager.cpp index 31ac11e2b05a..f324306cc860 100644 --- a/engines/ultima/ultima8/kernel/object_manager.cpp +++ b/engines/ultima/ultima8/kernel/object_manager.cpp @@ -20,7 +20,6 @@ */ #include "ultima/ultima8/misc/debugger.h" -#include "ultima/ultima8/misc/pent_include.h" #include "ultima/ultima8/kernel/object_manager.h" #include "ultima/ultima8/misc/id_man.h" #include "ultima/ultima8/ultima8.h" diff --git a/engines/ultima/ultima8/kernel/process.h b/engines/ultima/ultima8/kernel/process.h index 8975c35ddcb2..6b6ecaedb83c 100644 --- a/engines/ultima/ultima8/kernel/process.h +++ b/engines/ultima/ultima8/kernel/process.h @@ -25,7 +25,6 @@ #include "ultima/shared/std/containers.h" #include "ultima/ultima8/misc/classtype.h" #include "ultima/ultima8/misc/debugger.h" -#include "ultima/ultima8/misc/pent_include.h" namespace Ultima { namespace Ultima8 { diff --git a/engines/ultima/ultima8/misc/encoding.cpp b/engines/ultima/ultima8/misc/encoding.cpp index e4c682f85261..3396d021ce06 100644 --- a/engines/ultima/ultima8/misc/encoding.cpp +++ b/engines/ultima/ultima8/misc/encoding.cpp @@ -26,7 +26,7 @@ Copyright (C) 1999-2004 Free Software Foundation, Inc. */ -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/common_types.h" namespace Ultima { diff --git a/engines/ultima/ultima8/misc/pent_include.h b/engines/ultima/ultima8/misc/pent_include.h deleted file mode 100644 index 10c15c6333fb..000000000000 --- a/engines/ultima/ultima8/misc/pent_include.h +++ /dev/null @@ -1,36 +0,0 @@ -/* 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 . - * - */ - -#ifndef ULTIMA8_MISC_PENT_INCLUDE_H -#define ULTIMA8_MISC_PENT_INCLUDE_H - -// -// Common/base types -// -#include "ultima/ultima8/misc/common_types.h" - - -// -// RuntimeClassType -// -#include "ultima/ultima8/misc/classtype.h" - -#endif diff --git a/engines/ultima/ultima8/usecode/uc_machine.cpp b/engines/ultima/ultima8/usecode/uc_machine.cpp index ee73d2fa4a7a..048cf2d0e9e5 100644 --- a/engines/ultima/ultima8/usecode/uc_machine.cpp +++ b/engines/ultima/ultima8/usecode/uc_machine.cpp @@ -21,7 +21,6 @@ #include "common/memstream.h" -#include "ultima/ultima8/misc/pent_include.h" #include "ultima/ultima8/usecode/uc_machine.h" #include "ultima/ultima8/usecode/uc_process.h" #include "ultima/ultima8/usecode/usecode.h" diff --git a/engines/ultima/ultima8/usecode/usecode.cpp b/engines/ultima/ultima8/usecode/usecode.cpp index 584ded4cad37..6cbdccbc0ab7 100644 --- a/engines/ultima/ultima8/usecode/usecode.cpp +++ b/engines/ultima/ultima8/usecode/usecode.cpp @@ -19,7 +19,7 @@ * */ -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/common_types.h" #include "ultima/ultima8/usecode/usecode.h" #include "ultima/ultima8/ultima8.h" diff --git a/engines/ultima/ultima8/world/actors/actor.cpp b/engines/ultima/ultima8/world/actors/actor.cpp index cb684a671215..a904a4ab8bd0 100644 --- a/engines/ultima/ultima8/world/actors/actor.cpp +++ b/engines/ultima/ultima8/world/actors/actor.cpp @@ -21,7 +21,6 @@ #include "ultima/ultima.h" #include "ultima/ultima8/misc/debugger.h" -#include "ultima/ultima8/misc/pent_include.h" #include "ultima/ultima8/kernel/object_manager.h" #include "ultima/ultima8/kernel/kernel.h" #include "ultima/ultima8/kernel/delay_process.h" diff --git a/engines/ultima/ultima8/world/actors/animation.cpp b/engines/ultima/ultima8/world/actors/animation.cpp index 49947f519f81..a3916afa9a86 100644 --- a/engines/ultima/ultima8/world/actors/animation.cpp +++ b/engines/ultima/ultima8/world/actors/animation.cpp @@ -19,7 +19,6 @@ * */ -#include "ultima/ultima8/misc/pent_include.h" #include "ultima/ultima8/world/actors/animation.h" #include "ultima/ultima8/ultima8.h" diff --git a/engines/ultima/ultima8/world/actors/animation_tracker.cpp b/engines/ultima/ultima8/world/actors/animation_tracker.cpp index bf931d6e6b28..405a57edbb91 100644 --- a/engines/ultima/ultima8/world/actors/animation_tracker.cpp +++ b/engines/ultima/ultima8/world/actors/animation_tracker.cpp @@ -20,7 +20,6 @@ */ #include "ultima/ultima8/misc/debugger.h" -#include "ultima/ultima8/misc/pent_include.h" #include "ultima/ultima8/world/actors/animation_tracker.h" #include "ultima/ultima8/games/game_data.h" #include "ultima/ultima8/world/actors/actor.h" diff --git a/engines/ultima/ultima8/world/actors/combat_dat.cpp b/engines/ultima/ultima8/world/actors/combat_dat.cpp index dff4ebe56046..3f5d014b9f08 100644 --- a/engines/ultima/ultima8/world/actors/combat_dat.cpp +++ b/engines/ultima/ultima8/world/actors/combat_dat.cpp @@ -19,7 +19,6 @@ * */ -#include "ultima/ultima8/misc/pent_include.h" #include "ultima/ultima8/world/actors/combat_dat.h" namespace Ultima { diff --git a/engines/ultima/ultima8/world/crosshair_process.cpp b/engines/ultima/ultima8/world/crosshair_process.cpp index df6e0b28520a..a725e225d420 100644 --- a/engines/ultima/ultima8/world/crosshair_process.cpp +++ b/engines/ultima/ultima8/world/crosshair_process.cpp @@ -20,7 +20,6 @@ */ #include "ultima/ultima8/misc/debugger.h" -#include "ultima/ultima8/misc/pent_include.h" #include "ultima/ultima8/kernel/kernel.h" #include "ultima/ultima8/world/actors/main_actor.h" diff --git a/engines/ultima/ultima8/world/fire_type_table.cpp b/engines/ultima/ultima8/world/fire_type_table.cpp index 941b32e7a517..b1bc05a70037 100644 --- a/engines/ultima/ultima8/world/fire_type_table.cpp +++ b/engines/ultima/ultima8/world/fire_type_table.cpp @@ -19,7 +19,7 @@ * */ -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/common_types.h" #include "ultima/ultima8/world/fire_type_table.h" #include "ultima/ultima8/world/fire_type.h" diff --git a/engines/ultima/ultima8/world/get_object.cpp b/engines/ultima/ultima8/world/get_object.cpp index f3d9a70107a8..0bfd409c68f9 100644 --- a/engines/ultima/ultima8/world/get_object.cpp +++ b/engines/ultima/ultima8/world/get_object.cpp @@ -20,7 +20,6 @@ */ #include "ultima/ultima8/misc/debugger.h" -#include "ultima/ultima8/misc/pent_include.h" #include "ultima/ultima8/kernel/object_manager.h" #include "ultima/ultima8/world/actors/main_actor.h" diff --git a/engines/ultima/ultima8/world/item_factory.cpp b/engines/ultima/ultima8/world/item_factory.cpp index b7b644de9b6f..e033bcb7978f 100644 --- a/engines/ultima/ultima8/world/item_factory.cpp +++ b/engines/ultima/ultima8/world/item_factory.cpp @@ -19,7 +19,7 @@ * */ -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/common_types.h" #include "ultima/ultima8/world/item_factory.h" #include "ultima/ultima8/games/game_data.h" diff --git a/engines/ultima/ultima8/world/item_sorter.cpp b/engines/ultima/ultima8/world/item_sorter.cpp index 32096b9fad2b..fe2d570cef2f 100644 --- a/engines/ultima/ultima8/world/item_sorter.cpp +++ b/engines/ultima/ultima8/world/item_sorter.cpp @@ -20,7 +20,7 @@ */ #include "ultima/ultima.h" -#include "ultima/ultima8/misc/pent_include.h" +#include "ultima/ultima8/misc/common_types.h" #include "ultima/ultima8/world/item_sorter.h" #include "ultima/ultima8/world/item.h" #include "ultima/ultima8/graphics/shape.h" diff --git a/engines/ultima/ultima8/world/missile_tracker.cpp b/engines/ultima/ultima8/world/missile_tracker.cpp index 7e1d9da4a0dd..8bdae4bd3d59 100644 --- a/engines/ultima/ultima8/world/missile_tracker.cpp +++ b/engines/ultima/ultima8/world/missile_tracker.cpp @@ -21,7 +21,6 @@ #include "ultima/ultima.h" #include "ultima/ultima8/misc/debugger.h" -#include "ultima/ultima8/misc/pent_include.h" #include "ultima/ultima8/world/missile_tracker.h" From 4ed5e694f13a586dcb992d8ac6320d1ef8cff56f Mon Sep 17 00:00:00 2001 From: Walter Agazzi Date: Sat, 4 Feb 2023 20:50:37 +0100 Subject: [PATCH 020/412] AGS: Add detection for many new versions --- engines/ags/detection_tables.h | 40 +++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/engines/ags/detection_tables.h b/engines/ags/detection_tables.h index b7b9d84617ce..6ab663fe281c 100644 --- a/engines/ags/detection_tables.h +++ b/engines/ags/detection_tables.h @@ -3988,7 +3988,8 @@ const AGSGameDescription GAME_DESCRIPTIONS[] = { DEMO_ENTRY_EN("bookofdestiny", "SG.exe", "f3a13b2d6c2e0fe04c6f466062920e23", 1198451), DEMO_ENTRY_EN("bowanddork", "BowAndDork.exe", "7db052bc30700d1f30f5330f5814f519", 17121243), // Windows DEMO_ENTRY_EN("bowanddork", "BowAndDork.ags", "8728011855017e243bb95682d2898004", 14086087), // Linux - DEMO_ENTRY_EN("brotherswreckers", "Brothers & Wreckers.exe", "f24c533ce89a2566c157b871f87a4ce4", 42831964), + DEMO_ENTRY_EN("brotherswreckers", "Brothers & Wreckers.exe", "f24c533ce89a2566c157b871f87a4ce4", 42831964), // v1.0 + DEMO_ENTRY_EN("brotherswreckers", "Brothers & Wreckers.exe", "24da4d1b11cb22967dd0689aa6a3dbb4", 45934052), // v1.0.3 DEMO_ENTRY_EN("bytheswordconspiracy", "bts.exe", "7dc7f61f79ba7a77d4ef8168bfd3d173", 60246329), DEMO_ENTRY_EN("byzantine", "byza.exe", "39d7a558298a9f1d40c1f415daf9bb74", 3708632), DEMO_ENTRY_EN("byzantine", "byza.exe", "ecc8eaa38fe3adea61ffc525d2ce5c0e", 3660405), @@ -4081,7 +4082,9 @@ const AGSGameDescription GAME_DESCRIPTIONS[] = { DEMO_ENTRY_EN("ghostdream", "ghostdream.exe", "05594881531d62e4575545f3c8fd2576", 225600520), DEMO_ENTRY_EN("graceward", "Red_Black_Brown.exe", "0564de07d3fd5c16e6947a647061913c", 167543007), //itch.io DEMO_ENTRY_EN("graceward", "Graceward.exe", "0564de07d3fd5c16e6947a647061913c", 210565575), //itch.io 1.15 - DEMO_ENTRY_EN("graceward", "Graceward.exe", "0564de07d3fd5c16e6947a647061913c", 292537766), //itch.io CE + DEMO_ENTRY_EN("graceward", "Graceward.exe", "0564de07d3fd5c16e6947a647061913c", 226256533), //itch.io 1.2 + DETECTION_ENTRY("graceward", "Graceward.exe", "0564de07d3fd5c16e6947a647061913c", 292537766, Common::EN_ANY, "Complete Edition Demo", nullptr, ADGF_DEMO), //itch.io CE + DETECTION_ENTRY("graceward", "Graceward.exe", "0564de07d3fd5c16e6947a647061913c", 292501437, Common::EN_ANY, "Complete Edition Demo", nullptr, ADGF_DEMO), //itch.io CE DETECTION_ENTRY("grandmabadass", "grandmaDEMO.exe", "636250e131f51c7a97989992cc97cf02", 525503237, Common::UNK_LANG, "Prologue Demo", nullptr, ADGF_DEMO), // Multi DEMO_ENTRY("grandmabadass", "grandmaDEMO.exe", "65917d4eba3b2e3cf2befc06340c1f53", 1512973969), // Multi DEMO_ENTRY_EN("greenback", "Greenback.exe", "b80b5892fc0291add209a0d3de6dedc5", 10490547), @@ -4316,6 +4319,7 @@ const AGSGameDescription GAME_DESCRIPTIONS[] = { DEMO_ENTRY_EN("startrekmansion", "ST_BTTM.exe", "615e73fc1874e92d60a1996c2330ea36", 42877388), DEMO_ENTRY_EN("startropy", "Startropy.exe", "86cc8cd9b7443b68a374ad5d002c2945", 333959797), DEMO_ENTRY("stellarmessep1", "StellarMessShortDemo.exe", "a409703089eebbcfa13f0a22f6fb71ed", 8067581), // En-Fr-De-Es + DEMO_ENTRY("stellarmessep1", "StellarMessShortDemo.exe", "a409703089eebbcfa13f0a22f6fb71ed", 8713074), // En-Es DEMO_ENTRY_EN("stickmanrpg", "Stickman RPG.exe", "465f972675db2da6040518221af5b0ba", 2030693), DEMO_ENTRY_EN("stuckathome", "shtrl1.exe", "0500aacb6c176d47ac0f8158f055db83", 819147), DEMO_ENTRY_EN("subterra", "SUBTERRA.exe", "fd3ecd8289bebadbf775fe8a13b9c5d7", 17981991), @@ -4547,8 +4551,10 @@ const AGSGameDescription GAME_DESCRIPTIONS[] = { GAME_ENTRY_EN("annieandroidautomatedaffection", "annie source.exe", "fc17e9b3ab53f6b4841e2a4af5c782ff", 5015270), GAME_ENTRY_EN("anoffer", "An offer you cannot refuse.exe", "17009da9820f5aa86d0588023d497db8", 217468062), GAME_ENTRY_LANG("anoffer", "Ponuka ktora sa neodmieta.exe", "17009da9820f5aa86d0588023d497db8", 217460167, Common::SK_SVK), //Slovak - GAME_ENTRY("anothermuseum", "Another Museum.exe", "4308fc11a6564fecdd07aad435db9c3a", 71226691), // Windows Eng-Esp - GAME_ENTRY("anothermuseum", "Another Museum.ags", "0061e366527684fc95f566c498bbc9da", 68102348), // Linux Eng-Esp + GAME_ENTRY_PLATFORM("anothermuseum", "Another Museum.exe", "4308fc11a6564fecdd07aad435db9c3a", 71226691, "MAGS"), // Windows Eng-Esp + GAME_ENTRY_PLATFORM("anothermuseum", "Another Museum.ags", "0061e366527684fc95f566c498bbc9da", 68102348, "MAGS"), // Linux Eng-Esp + GAME_ENTRY("anothermuseum", "Another Museum.exe", "4308fc11a6564fecdd07aad435db9c3a", 71243854), // Windows Eng-Esp + GAME_ENTRY("anothermuseum", "Another Museum.ags", "c21271e254f5f390306235a41eede490", 68119098), // Linux Eng-Esp GAME_ENTRY_EN("anotherwayout", "1week.exe", "3b7cceb3e4bdb031dc5d8f290936e94b", 7870567), GAME_ENTRY_EN("anthonysessay", "copy of school.exe", "3b7cceb3e4bdb031dc5d8f290936e94b", 11033611), GAME_ENTRY_EN("anticipatingmurder", "ags.exe", "f120690b506dd63cd7d1112ea6af2f77", 19907137), @@ -4586,6 +4592,7 @@ const AGSGameDescription GAME_DESCRIPTIONS[] = { GAME_ENTRY_EN("artofdying", "die.exe", "89df481678b2ddc40ecc9f83caa76b89", 4804446), GAME_ENTRY("asecondface", "eye of geltz.exe", "0e32c4b3380e286dc0cea8550f1c045e", 7061019), //Multi GAME_ENTRY("asecondface", "eye of geltz.exe", "5bda06bea6f5e620d5f3f1ca75dd6da4", 7092197), + GAME_ENTRY("asecondface", "eye of geltz.exe", "50bc7406920eda1fd882c209060ae1f8", 556196897), // v1.7 Itch.io Multi GAME_ENTRY_EN("ashortnightmare", "a_short_nightmare.exe", "b142b43c146c25443a1d155d441a6a81", 94221930), GAME_ENTRY_EN("asimplefix", "A simple fix.exe", "615e73fc1874e92d60a1996c2330ea36", 27488921), GAME_ENTRY_EN("asledmundo", "asl.exe", "6e3d6225dee662ff6450a3bfa942773b", 2749868), @@ -4867,6 +4874,8 @@ const AGSGameDescription GAME_DESCRIPTIONS[] = { GAME_ENTRY_EN("chalksquest", "chalk.exe", "0710e2ec71042617f565c01824f0cf3c", 5138049), GAME_ENTRY("challengetentacle", "Challenge of the Tentacle.exe", "44d2715f4d78a639a588e94cf19b5821", 489037337), // Win En-De GAME_ENTRY("challengetentacle", "Challenge of the Tentacle.ags", "b24cdc761ea244ed460f32329627cc45", 485577733), // Linux En-De + GAME_ENTRY("challengetentacle", "Challenge of the Tentacle.exe", "44d2715f4d78a639a588e94cf19b5821", 489037341), // Win En-De v1.0.2 + GAME_ENTRY("challengetentacle", "Challenge of the Tentacle.ags", "deed6ad8466f2cdc31fe84112a2f949d", 485577737), // Linux En-De v1.0.2 GAME_ENTRY_EN("chanceofthedead", "chance.exe", "8418b150c267e4f1d462b9a5d60e507d", 5597569), GAME_ENTRY_EN("charamba1", "Charamba.exe", "354e3016d64ac3378478d3d52ef0460d", 7468361), GAME_ENTRY_EN("charamba2", "CharambaII.exe", "354e3016d64ac3378478d3d52ef0460d", 4975542), @@ -4915,6 +4924,7 @@ const AGSGameDescription GAME_DESCRIPTIONS[] = { GAME_ENTRY_EN("clotildesoffritti", "Clotilde astronave.exe", "286551ded3eedc428451e506e29196c9", 368664276), GAME_ENTRY_EN("clotildesoffritti", "Clotilde astronave.exe", "286551ded3eedc428451e506e29196c9", 368848300), GAME_ENTRY_EN("clotildesoffritti2", "Clotilde 2.exe", "6b1455146ef5f67b4ff83cc60646b964", 107838654), + GAME_ENTRY_EN("clotildesoffritti2", "Clotilde 2.exe", "6b1455146ef5f67b4ff83cc60646b964", 108688904), GAME_ENTRY_EN("clubofevil", "club of evil.exe", "65f53f81071dab6b3ab8363e4c76d12e", 11838011), GAME_ENTRY_LANG("coderbattle", "coderbattle.exe", "8bae5a42f382b38d516a7f8c8f686376", 23992763, Common::DE_DEU), GAME_ENTRY_EN("coinopafternoon", "Let's Play Something.exe", "615e73fc1874e92d60a1996c2330ea36", 1225364411), //English @@ -4951,6 +4961,7 @@ const AGSGameDescription GAME_DESCRIPTIONS[] = { GAME_ENTRY_EN("content", "Content.exe", "9878f9ded585f7191df2eebc01867c6e", 29828265), // Windows Eng GAME_ENTRY_LANG("content", "Content_Kor.exe", "9878f9ded585f7191df2eebc01867c6e", 30127981, Common::KO_KOR), // Windows Korean GAME_ENTRY_EN("content", "Content.ags", "7a0e6b41e951aedd4385c10c15513835", 26690197), // Linux Eng + GAME_ENTRY("content", "Content.exe", "1e950496692a009ea163eb276702e008", 29814856), // Windows Eng-Kor GAME_ENTRY("contrapasso", "Commissar's Contrapasso.exe", "164da3f495c1fff9695893ec6622f4eb", 440822669), // Win Eng-Swe GAME_ENTRY("contrapasso", "Commissar's Contrapasso.ags", "3e99c4265fbfcd89f04fc85d367289cd", 438328189), // Linux Eng-Swe GAME_ENTRY("contrapasso", "ac2game.dat", "3e99c4265fbfcd89f04fc85d367289cd", 438328189), // Mac Eng-Swe @@ -5285,8 +5296,10 @@ const AGSGameDescription GAME_DESCRIPTIONS[] = { GAME_ENTRY_EN("flamebarrels", "Flame barrel.exe", "06a03fe35791b0578068ab1873455463", 2298745), GAME_ENTRY_EN("flashmccoy", "FlashMcCoy.exe", "0564de07d3fd5c16e6947a647061913c", 16314015), GAME_ENTRY_EN("flightrobots", "FlightFromTheRobots.exe", "3ab9922a2ab7c5875af4c9794b33e012", 4517631), - GAME_ENTRY_EN("flightrobotsch2", "FlightFromTheRobots2.exe", "9bb70a54ea1c4063c6821c88c7427dfb", 4751416), - GAME_ENTRY_EN("flightrobotsch2", "FlightFromTheRobots2.ags", "ae9236152eef64bf635f7bb63c981a88", 1643556), + GAME_ENTRY_EN_PLATFORM("flightrobotsch2", "FlightFromTheRobots2.exe", "9bb70a54ea1c4063c6821c88c7427dfb", 4751416, "Original Version"), + GAME_ENTRY_EN_PLATFORM("flightrobotsch2", "FlightFromTheRobots2.ags", "ae9236152eef64bf635f7bb63c981a88", 1643556, "Original Version"), + GAME_ENTRY_EN("flightrobotsch2", "FlightFromTheRobots2.exe", "0595b55383d72a99cd995092c5bf8475", 5624650), + GAME_ENTRY_EN("flightrobotsch2", "FlightFromTheRobots2.ags", "14991349066fababce1050b192c0951b", 2515766), GAME_ENTRY_EN("floatyrog", "FloatyRog.exe", "6e6f33162242d74dd1fa042429f16562", 2592017), GAME_ENTRY_EN("flophouse", "FlopHigh.exe", "0241777c2537fc5d077c05cde10bfa9f", 5807004), GAME_ENTRY_EN_PLATFORM("flophouse", "FlopHigh.exe", "0241777c2537fc5d077c05cde10bfa9f", 9159785, "Deluxe"), @@ -5614,8 +5627,9 @@ const AGSGameDescription GAME_DESCRIPTIONS[] = { GAME_ENTRY_EN("ioawn4t", "ioawn4t.exe", "11bd8123982f9442f372ed5defc88b50", 888895169), GAME_ENTRY_EN("ioawn4t", "game.ags", "11bd8123982f9442f372ed5defc88b50", 888895169), GAME_ENTRY_EN_STEAM("ioawn4t", "ioawn4t.exe", "11bd8123982f9442f372ed5defc88b50", 888897420), - GAME_ENTRY_EN("irentedaboat", "I_rented_a_boat.exe", "792c0a0eaeba1a8846cb7b1af1e3266e", 144007992), // Windows - GAME_ENTRY_EN("irentedaboat", "I_rented_a_boat.ags", "9c8cbf1ee6f0a797fdaee29177a43224", 140971300), // Linux + GAME_ENTRY_EN_PLATFORM("irentedaboat", "I_rented_a_boat.exe", "792c0a0eaeba1a8846cb7b1af1e3266e", 144007992, "MAGS"), // Windows + GAME_ENTRY_EN_PLATFORM("irentedaboat", "I_rented_a_boat.ags", "9c8cbf1ee6f0a797fdaee29177a43224", 140971300, "MAGS"), // Linux + GAME_ENTRY_EN("irentedaboat", "I_rented_a_boat.exe", "69059264cbe5973082ddeec0aead82a9", 121845045), // Windows GAME_ENTRY_EN("irishcoffee", "Irish Coffee.exe", "6d012687b4944c2b9167dad450579527", 18381150), GAME_ENTRY("isaacodyssey", "isaacsoddysee.exe", "615e73fc1874e92d60a1996c2330ea36", 5339324), //v1.1 Eng-Esp GAME_ENTRY_EN("isnkill", "ISN.exe", "4d17844029d8910fbaae1bdc99e250f2", 7932669), @@ -5848,7 +5862,8 @@ const AGSGameDescription GAME_DESCRIPTIONS[] = { GAME_ENTRY_EN("lordoflight", "LordofLight.ags", "020597575b9a190f6d770c3d4b9bb180", 95597987), GAME_ENTRY_EN("lorrylen", "Lorry Len.exe", "f120690b506dd63cd7d1112ea6af2f77", 1252505), GAME_ENTRY_EN("losjovenesdelaguerra", "guerra.exe", "97d700529f5cc826f230c27acf81adfd", 4286035), - GAME_ENTRY("losno", "Ladies of Sorrow Night One.ags", "f2b7c42a39683cbae37be67a562fe36a", 175792352), // Windows, Linux + GAME_ENTRY("losno", "Ladies of Sorrow Night One.ags", "f2b7c42a39683cbae37be67a562fe36a", 175792352), // Windows, Linux Multi + GAME_ENTRY("losno", "Ladies of Sorrow Night One.ags", "c472fb6ec3379d0af51076e99934ceb2", 178529328), // Windows, Linux Multi v1.1b GAME_ENTRY("lostanswers", "Lost Answers.exe", "c88de182eae58fdb43e5b4e587095ff5", 254684884), // Windows Eng-Tur GAME_ENTRY("lostanswers", "Lost Answers.ags", "ee0ec2b06f61dd4cb5e57fe5d7898aa0", 252104900), // Linux Eng-Tur GAME_ENTRY_EN("lostdollar", "Ron.exe", "c87aa6377abc18c1a1b2968ae6db08eb", 4542929), @@ -5945,6 +5960,7 @@ const AGSGameDescription GAME_DESCRIPTIONS[] = { GAME_ENTRY_EN_STEAM("meta", "meta.exe", "9358670438c3fab77489a1dd229029b1", 2536926), GAME_ENTRY_EN("metaphobia", "Metaphobia.exe", "10da7427cf74ba0cc7ceb29f99ff0a67", 92083437), // itch.io 1.01 Windows GAME_ENTRY_EN("metaphobia", "ac2game.exe", "10da7427cf74ba0cc7ceb29f99ff0a67", 92083437), // itch.io MacOS + GAME_ENTRY("metaphobia", "Metaphobia.exe", "10da7427cf74ba0cc7ceb29f99ff0a67", 92157492), // itch.io Eng-Ita GAME_ENTRY_EN_STEAM("metaphobia", "Metaphobia.exe", "10da7427cf74ba0cc7ceb29f99ff0a67", 92086491), GAME_ENTRY("meteorhead1", "Meteorhead.exe", "6cddccb3744ec5c6af7c398fb7b3b11c", 5081311), // En-De GAME_ENTRY_LANG("meteorhead2", "mh2.exe", "06a03fe35791b0578068ab1873455463", 5833556, Common::DE_DEU), @@ -6678,6 +6694,7 @@ const AGSGameDescription GAME_DESCRIPTIONS[] = { GAME_ENTRY_EN("rockpaperscissors2", "Rock, Paper, Scissors 2.exe", "89a94326c8afd9e0234e269bd7330130", 2926218), GAME_ENTRY_EN("rockrockrock", "rrr.exe", "7dd36aa863ed40ede1b09ae505e478cc", 9362761), GAME_ENTRY_EN("rocktravis", "rock travis - camilla's case.exe", "17009da9820f5aa86d0588023d497db8", 126975468), + GAME_ENTRY_EN("rocktravis", "rock travis - camilla's case.exe", "17009da9820f5aa86d0588023d497db8", 126975803), GAME_ENTRY_EN("rockyroams", "Rocky.exe", "a01a9639ce30bdcd5bf82e528b51fa06", 16978200), GAME_ENTRY_EN("rodequest2", "RQ2.exe", "12c03a3c782237821acd590fd91af4c5", 4192097), GAME_ENTRY_EN("rodequest2", "RQ2b.exe", "12c03a3c782237821acd590fd91af4c5", 4192097), @@ -7314,6 +7331,7 @@ const AGSGameDescription GAME_DESCRIPTIONS[] = { GAME_ENTRY_LANG("thewhitecanvas", "Lienzo en blanco.exe", "5871918713de85ee4bae331ca3284184", 427232201, Common::ES_ESP), GAME_ENTRY("thewife", "The wife who wasn't there game.exe", "a524cbb1c51589903c4043b98917f1d9", 94508281), //En-Fr GAME_ENTRY_EN("thewill", "The Will.exe", "f3aad40970211ace6278d9591e872b87", 16523785), + GAME_ENTRY_EN("thewill", "The Will.exe", "f3aad40970211ace6278d9591e872b87", 16523066), GAME_ENTRY_EN("theworm", "Worm.exe", "e88fd6a23a5e498d7b0d50e3bb914085", 40704028), GAME_ENTRY_EN("thinker", "ThinkerAdventure.exe", "bb4e465c16a70e1d6bc7d45f63a35a87", 4800053), // Windows GAME_ENTRY_EN("thinker", "ThinkerAdventure.ags", "dc475c59572938bc8e489367a7084e5b", 1611297), // Linux @@ -7402,6 +7420,7 @@ const AGSGameDescription GAME_DESCRIPTIONS[] = { DETECTION_ENTRY_GUIO("twelvethirteense", "1213 SE.exe", "3b7cceb3e4bdb031dc5d8f290936e94b", 644458, Common::EN_ANY, nullptr, GUIO2(GUIO_NOLANG, GUIO_NOLAUNCHLOAD), nullptr, ADGF_NO_FLAGS), // Menu GAME_ENTRY_EN("twentiesflappersvsthemummy", "Twenties Flappers vs The Mummy.exe", "a524cbb1c51589903c4043b98917f1d9", 15042196), GAME_ENTRY("twoghosts", "Ghosts.exe", "2f2bc0b9c539d20529c0e343315d5f65", 4525238), // En-Fr + GAME_ENTRY("twoghosts", "Ghosts.exe", "2f2bc0b9c539d20529c0e343315d5f65", 4525343), // En-Fr GAME_ENTRY_EN("twoofakind", "toak.exe", "465f972675db2da6040518221af5b0ba", 24644765), GAME_ENTRY_EN("ugalembrace", "UgalsEmbrace.exe", "308026eea716ec1aeed39f7f8d8cfd18", 30046377), GAME_ENTRY_EN("uglyfiles", "ugly.exe", "0394af1c29e1060fcdbacf2a3dd9b231", 4169486), @@ -7412,7 +7431,8 @@ const AGSGameDescription GAME_DESCRIPTIONS[] = { GAME_ENTRY_EN("underworld", "Underworld.exe", "6cddccb3744ec5c6af7c398fb7b3b11c", 5147661), GAME_ENTRY_EN("unexpectedguest", "unexpectedGuest.exe", "5e1d1fbbaadb46b5cfd5474d71080c9d", 4541793), GAME_ENTRY_EN("unexpectedquest", "UQ.exe", "f120690b506dd63cd7d1112ea6af2f77", 1837663), - GAME_ENTRY_EN("unfair", "Unfair.exe", "8d1ff95c16500befbdc72260d461d73f", 5203436), + GAME_ENTRY_EN_PLATFORM("unfair", "Unfair.exe", "8d1ff95c16500befbdc72260d461d73f", 5203436, "MAGS"), + GAME_ENTRY_EN("unfair", "Unfair.exe", "8d1ff95c16500befbdc72260d461d73f", 5212077), GAME_ENTRY_EN("unfinished", "mags.exe", "0710e2ec71042617f565c01824f0cf3c", 12092514), GAME_ENTRY_EN("unfinishedbusiness", "business.exe", "089fab88e6e1075a2f5b271f6f5b3c57", 2202413), GAME_ENTRY("unfinishedtales", "shst.exe", "28f82e420b82d07651b68114f90223c8", 1013809), // Eng-Esp From 894a24dd63514b0445abfbc6b378adf2003a3464 Mon Sep 17 00:00:00 2001 From: Matthew Duggan Date: Sat, 4 Feb 2023 09:07:48 +0900 Subject: [PATCH 021/412] JANITORIAL: Clarify comments about screenFormat --- common/system.h | 6 +++++- engines/util.h | 9 +++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/common/system.h b/common/system.h index 75ec497bdd5a..1d99f746c2b7 100644 --- a/common/system.h +++ b/common/system.h @@ -681,7 +681,11 @@ class OSystem : Common::NonCopyable { #ifdef USE_RGB_COLOR /** - * Determine the pixel format currently in use for screen rendering. + * Fetch the pixel format currently in use for screen rendering. + * + * This is not neccessarily the native format for the system - if unset + * it defaults toCLUT8. To set a different format, engines should set + * their preferred format using ::initGraphics(). * * @return the active screen pixel format. * diff --git a/engines/util.h b/engines/util.h index ed3187e753bf..d84ddbc48224 100644 --- a/engines/util.h +++ b/engines/util.h @@ -58,11 +58,12 @@ void initGraphicsModes(const Graphics::ModeList &modes); * Shows various warnings on certain backend graphics * transaction failures (aspect switch, fullscreen switch, etc.). * - * Errors are returned when the backend is not able to switch to the specified - * mode. + * An error dialog will be generated when the backend is not able to switch + * to the specified mode. * - * Defaults to 256 color palette mode if no graphics format is provided. - * Uses the preferred format of the backend if graphics format pointer is NULL. + * Defaults to CLUT8 (256 color palette) if only width and height provided. + * If graphics format is explicitly set to nullptr, uses the preferred format of + * the backend. * Finds the best compatible format if a list of graphics formats is provided. */ void initGraphics(int width, int height); From 7a782f5b24fe8b618ac582edc41deeda6689435d Mon Sep 17 00:00:00 2001 From: Matthew Duggan Date: Sat, 4 Feb 2023 16:33:35 +0900 Subject: [PATCH 022/412] TETRAEDGE: Fixes for TinyGL rendering, almost works --- engines/tetraedge/te/te_3d_texture_opengl.cpp | 4 +- engines/tetraedge/te/te_3d_texture_tinygl.cpp | 14 +++--- engines/tetraedge/te/te_mesh_tinygl.cpp | 20 ++++---- engines/tetraedge/te/te_renderer.h | 1 + engines/tetraedge/te/te_renderer_opengl.cpp | 8 +++- engines/tetraedge/te/te_renderer_opengl.h | 1 + engines/tetraedge/te/te_renderer_tinygl.cpp | 48 +++++++++++++------ engines/tetraedge/te/te_renderer_tinygl.h | 1 + 8 files changed, 63 insertions(+), 34 deletions(-) diff --git a/engines/tetraedge/te/te_3d_texture_opengl.cpp b/engines/tetraedge/te/te_3d_texture_opengl.cpp index efb352aa3c82..004baa8e4716 100644 --- a/engines/tetraedge/te/te_3d_texture_opengl.cpp +++ b/engines/tetraedge/te/te_3d_texture_opengl.cpp @@ -195,8 +195,8 @@ void Te3DTextureOpenGL::update(const TeImage &img, uint xoff, uint yoff) { setAccessName(img.getAccessName().append(".3dtex")); glBindTexture(GL_TEXTURE_2D, _glTexture); - glPixelStorei(GL_UNPACK_SWAP_BYTES, 0); - glPixelStorei(GL_UNPACK_LSB_FIRST, 0); + glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE); + glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE); glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); diff --git a/engines/tetraedge/te/te_3d_texture_tinygl.cpp b/engines/tetraedge/te/te_3d_texture_tinygl.cpp index 4b00e9f5b297..71116ecb6061 100644 --- a/engines/tetraedge/te/te_3d_texture_tinygl.cpp +++ b/engines/tetraedge/te/te_3d_texture_tinygl.cpp @@ -132,12 +132,13 @@ bool Te3DTextureTinyGL::load(const TeImage &img) { _texHeight = _height; tglBindTexture(TGL_TEXTURE_2D, _glTexture); + // Note: these are unsupported in TGL but should be the defaults? //tglPixelStorei(TGL_UNPACK_SWAP_BYTES, TGL_FALSE); //tglPixelStorei(TGL_UNPACK_LSB_FIRST, TGL_FALSE); //tglPixelStorei(TGL_UNPACK_ROW_LENGTH, 0); //tglPixelStorei(TGL_UNPACK_SKIP_ROWS, 0); //tglPixelStorei(TGL_UNPACK_SKIP_PIXELS, 0); - //tglPixelStorei(TGL_UNPACK_ALIGNMENT, 1); + tglPixelStorei(TGL_UNPACK_ALIGNMENT, 1); const void *imgdata = img.getPixels(); if (_format == TeImage::RGB8) { @@ -185,11 +186,12 @@ void Te3DTextureTinyGL::update(const TeImage &img, uint xoff, uint yoff) { setAccessName(img.getAccessName().append(".3dtex")); tglBindTexture(TGL_TEXTURE_2D, _glTexture); - tglPixelStorei(TGL_UNPACK_SWAP_BYTES, 0); - tglPixelStorei(TGL_UNPACK_LSB_FIRST, 0); - tglPixelStorei(TGL_UNPACK_ROW_LENGTH, 0); - tglPixelStorei(TGL_UNPACK_SKIP_ROWS, 0); - tglPixelStorei(TGL_UNPACK_SKIP_PIXELS, 0); + // Note: these are unsupported in TGL but should be the defaults? + //tglPixelStorei(TGL_UNPACK_SWAP_BYTES, TGL_FALSE); + //tglPixelStorei(TGL_UNPACK_LSB_FIRST, TGL_FALSE); + //tglPixelStorei(TGL_UNPACK_ROW_LENGTH, 0); + //tglPixelStorei(TGL_UNPACK_SKIP_ROWS, 0); + //tglPixelStorei(TGL_UNPACK_SKIP_PIXELS, 0); tglPixelStorei(TGL_UNPACK_ALIGNMENT, 1); //const void *imgdata = img.getPixels(); diff --git a/engines/tetraedge/te/te_mesh_tinygl.cpp b/engines/tetraedge/te/te_mesh_tinygl.cpp index 3f9db8ea0ca3..f100363eebec 100644 --- a/engines/tetraedge/te/te_mesh_tinygl.cpp +++ b/engines/tetraedge/te/te_mesh_tinygl.cpp @@ -28,7 +28,7 @@ namespace Tetraedge { -TeMeshTinyGL::TeMeshTinyGL() : _glMeshMode(TGL_POINTS), _gltexEnvMode(TGL_MODULATE) { +TeMeshTinyGL::TeMeshTinyGL() : _glMeshMode(TGL_POINTS), _gltexEnvMode(TGL_DECAL) { } void TeMeshTinyGL::draw() { @@ -141,8 +141,8 @@ void TeMeshTinyGL::draw() { if (!renderer->scissorEnabled()) tglDisable(TGL_SCISSOR_TEST); - // TODO: not supported in TGL - //tglTexEnvi(TGL_TEXTURE_ENV, TGL_TEXTURE_ENV_MODE, TGL_MODULATE); + // TODO: GL_MODULATE not supported in TGL + //tglTexEnvi(TGL_TEXTURE_ENV, TGL_TEXTURE_ENV_MODE, TGL_DECAL); tglDisableClientState(TGL_VERTEX_ARRAY); tglDisableClientState(TGL_NORMAL_ARRAY); tglDisableClientState(TGL_COLOR_ARRAY); @@ -151,19 +151,19 @@ void TeMeshTinyGL::draw() { if (_drawWires && !normals.empty()) { renderer->disableAllLights(); - error("TODO: Properly implement _drawWires case in TeMesh::draw"); - /* + //error("TODO: Properly implement _drawWires case in TeMesh::draw"); + ///* // TODO: Reimplement without glBegin/glEnd - glBegin(TGL_LINES); + tglBegin(TGL_LINES); renderer->setCurrentColor(TeColor(255, 255, 255, 255)); for (uint i = 0; i < verticies.size(); i++) { - glVertex3f(verticies[i].x(), verticies[i].y(), verticies[i].z()); - glVertex3f(verticies[i].x() + normals[i].x(), + tglVertex3f(verticies[i].x(), verticies[i].y(), verticies[i].z()); + tglVertex3f(verticies[i].x() + normals[i].x(), verticies[i].y() + normals[i].y(), verticies[i].z() + normals[i].z()); } - glEnd(); - */ + tglEnd(); + //*/ } renderer->setMatrixMode(TeRenderer::MM_GL_MODELVIEW); diff --git a/engines/tetraedge/te/te_renderer.h b/engines/tetraedge/te/te_renderer.h index 4b72f6e6ca15..edb46d14c5d0 100644 --- a/engines/tetraedge/te/te_renderer.h +++ b/engines/tetraedge/te/te_renderer.h @@ -134,6 +134,7 @@ class TeRenderer { void dumpTransparentMeshData() const; const TeColor ¤tColor() const { return _currentColor; } + virtual void updateScreen() = 0; virtual void updateGlobalLight() = 0; virtual void applyMaterial(const TeMaterial &m) = 0; diff --git a/engines/tetraedge/te/te_renderer_opengl.cpp b/engines/tetraedge/te/te_renderer_opengl.cpp index a4be743d8c0b..4a14b3dc2f25 100644 --- a/engines/tetraedge/te/te_renderer_opengl.cpp +++ b/engines/tetraedge/te/te_renderer_opengl.cpp @@ -21,6 +21,7 @@ #include "common/textconsole.h" #include "common/debug.h" +#include "common/system.h" #include "graphics/opengl/system_headers.h" @@ -99,7 +100,8 @@ void TeRendererOpenGL::init(uint width, uint height) { // Note: original doesn't separate but blends are nicer that way. glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glDepthFunc(GL_LEQUAL); - glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_DONT_CARE); + // Original does this, probably not needed? + //glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_DONT_CARE); glClearDepth(1.0); glClearStencil(0); _clearColor = TeColor(0, 0, 0, 255); @@ -382,6 +384,10 @@ void TeRendererOpenGL::updateGlobalLight() { TeLightOpenGL::updateGlobal(); } +void TeRendererOpenGL::updateScreen() { + g_system->updateScreen(); +} + Common::String TeRendererOpenGL::vendor() { return Common::String((const char *)glGetString(GL_VENDOR)); } diff --git a/engines/tetraedge/te/te_renderer_opengl.h b/engines/tetraedge/te/te_renderer_opengl.h index 7bdd43ab1c24..128bce826636 100644 --- a/engines/tetraedge/te/te_renderer_opengl.h +++ b/engines/tetraedge/te/te_renderer_opengl.h @@ -54,6 +54,7 @@ class TeRendererOpenGL : public TeRenderer { Common::String vendor() override; void applyMaterial(const TeMaterial &m) override; void updateGlobalLight() override; + void updateScreen() override; protected: diff --git a/engines/tetraedge/te/te_renderer_tinygl.cpp b/engines/tetraedge/te/te_renderer_tinygl.cpp index 8bd830f305cf..a82b25a1055c 100644 --- a/engines/tetraedge/te/te_renderer_tinygl.cpp +++ b/engines/tetraedge/te/te_renderer_tinygl.cpp @@ -90,9 +90,9 @@ void TeRendererTinyGL::enableZBuffer() { } void TeRendererTinyGL::init(uint width, uint height) { - Graphics::PixelFormat pixelFormat = g_system->getScreenFormat(); - initGraphics(width, height, &pixelFormat); + initGraphics(width, height, nullptr); + const Graphics::PixelFormat pixelFormat = g_system->getScreenFormat(); debug(2, "INFO: TinyGL front buffer pixel format: %s", pixelFormat.toString().c_str()); TinyGL::createContext(width, height, pixelFormat, 256, true, ConfMan.getBool("dirtyrects")); @@ -107,9 +107,10 @@ void TeRendererTinyGL::init(uint width, uint height) { tglEnable(TGL_BLEND); tglBlendFunc(TGL_SRC_ALPHA, TGL_ONE_MINUS_SRC_ALPHA); tglDepthFunc(TGL_LEQUAL); - tglHint(TGL_PERSPECTIVE_CORRECTION_HINT, TGL_DONT_CARE); + // Original does this, probably not needed? + //tglHint(TGL_PERSPECTIVE_CORRECTION_HINT, TGL_DONT_CARE); tglClearDepth(1.0); - tglClearStencil(0); + //tglClearStencil(0); _clearColor = TeColor(0, 0, 0, 255); tglClearColor(0, 0, 0, 1.0); //TeOpenGLExtensions::loadExtensions(); // this does nothing in the game? @@ -196,7 +197,7 @@ void TeRendererTinyGL::renderTransparentMeshes() { if (meshProperties._scissorEnabled) { tglEnable(TGL_SCISSOR_TEST); - // No scissoring in TGL.. + // TODO: No scissoring in TGL.. /* tglScissor(meshProperties._scissorX, meshProperties._scissorY, @@ -204,7 +205,7 @@ void TeRendererTinyGL::renderTransparentMeshes() { meshProperties._scissorHeight);*/ } // TODO: not supported in TGL - //tglTexEnvi(TGL_TEXTURE_ENV, TGL_TEXTURE_ENV_MODE, meshProperties._glTexEnvMode); + //tglTexEnvi(TGL_TEXTURE_ENV, TGL_TEXTURE_ENV_MODE, TGL_DECAL/*meshProperties._glTexEnvMode*/); tglDrawElements(TGL_TRIANGLES, meshProperties._vertexCount, TGL_UNSIGNED_SHORT, _transparentMeshVertexNums.data() + vertsDrawn); @@ -215,7 +216,7 @@ void TeRendererTinyGL::renderTransparentMeshes() { tglEnableClientState(TGL_COLOR_ARRAY); } // TODO: not supported in TGL - //tglTexEnvi(TGL_TEXTURE_ENV, TGL_TEXTURE_ENV_MODE, TGL_MODULATE); + //tglTexEnvi(TGL_TEXTURE_ENV, TGL_TEXTURE_ENV_MODE, TGL_DECAL); if (meshProperties._scissorEnabled) { tglDisable(TGL_SCISSOR_TEST); } @@ -328,8 +329,8 @@ void TeRendererTinyGL::applyMaterial(const TeMaterial &m) { tglTexEnvi(TGL_TEXTURE_ENV, TGL_OPERAND0_ALPHA, TGL_SRC_ALPHA); */ } else { - // TODO: not supported in TGL - //tglTexEnvi(TGL_TEXTURE_ENV, TGL_TEXTURE_ENV_MODE, TGL_MODULATE); + // TODO: GL_MODULATE supported in TGL + //tglTexEnvi(TGL_TEXTURE_ENV, TGL_TEXTURE_ENV_MODE, TGL_DECAL); if (m._mode != TeMaterial::MaterialMode1) { tglEnable(TGL_ALPHA_TEST); tglAlphaFunc(TGL_GREATER, 0.5); @@ -360,8 +361,8 @@ void TeRendererTinyGL::applyMaterial(const TeMaterial &m) { static const float fullColor[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; TeLightTinyGL::disableAll(); tglDisable(TGL_ALPHA_TEST); - // TODO: not supported in TGL - //tglTexEnvi(TGL_TEXTURE_ENV, TGL_TEXTURE_ENV_MODE, TGL_MODULATE); + // TODO: GL_MODULATE not supported in TGL + //tglTexEnvi(TGL_TEXTURE_ENV, TGL_TEXTURE_ENV_MODE, TGL_DECAL); tglMaterialfv(TGL_FRONT_AND_BACK, TGL_AMBIENT, fullColor); tglMaterialfv(TGL_FRONT_AND_BACK, TGL_DIFFUSE, fullColor); tglMaterialfv(TGL_FRONT_AND_BACK, TGL_SPECULAR, fullColor); @@ -374,8 +375,8 @@ void TeRendererTinyGL::applyMaterial(const TeMaterial &m) { tglDisable(TGL_TEXTURE_GEN_R); tglDisable(TGL_TEXTURE_GEN_Q); } else { - // TODO: not supported in TGL - //tglTexEnvi(TGL_TEXTURE_ENV, TGL_TEXTURE_ENV_MODE, TGL_MODULATE); + // TODO: GL_MODULATE not supported in TGL + //tglTexEnvi(TGL_TEXTURE_ENV, TGL_TEXTURE_ENV_MODE, TGL_DECAL); tglEnable(TGL_TEXTURE_GEN_S); tglEnable(TGL_TEXTURE_GEN_T); tglEnable(TGL_TEXTURE_GEN_R); @@ -384,8 +385,8 @@ void TeRendererTinyGL::applyMaterial(const TeMaterial &m) { TeLightTinyGL::disableAll(); tglDisable(TGL_ALPHA_TEST); enableTexture(); - // TODO: not supported in TGL - //tglTexEnvi(TGL_TEXTURE_ENV, TGL_TEXTURE_ENV_MODE, TGL_MODULATE); + // TODO: GL_MODULATE not supported in TGL + //tglTexEnvi(TGL_TEXTURE_ENV, TGL_TEXTURE_ENV_MODE, TGL_DECAL); const float diffuse[4] = { m._diffuseColor.r() / 255.0f, m._diffuseColor.g() / 255.0f, m._diffuseColor.b() / 255.0f, m._diffuseColor.a() / 255.0f }; @@ -401,6 +402,23 @@ void TeRendererTinyGL::updateGlobalLight() { TeLightTinyGL::updateGlobal(); } +void TeRendererTinyGL::updateScreen() { + Common::List dirtyAreas; + TinyGL::presentBuffer(dirtyAreas); + + Graphics::Surface glBuffer; + TinyGL::getSurfaceRef(glBuffer); + + if (!dirtyAreas.empty()) { + for (Common::List::iterator itRect = dirtyAreas.begin(); itRect != dirtyAreas.end(); ++itRect) { + g_system->copyRectToScreen(glBuffer.getBasePtr((*itRect).left, (*itRect).top), glBuffer.pitch, + (*itRect).left, (*itRect).top, (*itRect).width(), (*itRect).height()); + } + } + + g_system->updateScreen(); +} + Common::String TeRendererTinyGL::vendor() { return "TinyGL vendor"; } diff --git a/engines/tetraedge/te/te_renderer_tinygl.h b/engines/tetraedge/te/te_renderer_tinygl.h index 60db224e5b02..209591e52248 100644 --- a/engines/tetraedge/te/te_renderer_tinygl.h +++ b/engines/tetraedge/te/te_renderer_tinygl.h @@ -54,6 +54,7 @@ class TeRendererTinyGL : public TeRenderer { void shadowMode(enum ShadowMode mode) override; void applyMaterial(const TeMaterial &m) override; void updateGlobalLight() override; + void updateScreen() override; Common::String vendor() override; protected: From fc86b54e755227ceaa128a8544036cf531972756 Mon Sep 17 00:00:00 2001 From: Matthew Duggan Date: Sat, 4 Feb 2023 21:48:46 +0900 Subject: [PATCH 023/412] TETRAEDGE: Refactor to use FSNode instead of Path Most places which previously used a Path, I actually wanted to record an FSNode for better cross-platform compatibility. --- engines/tetraedge/game/application.cpp | 33 +++++------ engines/tetraedge/game/billboard.cpp | 7 ++- engines/tetraedge/game/character.cpp | 9 +-- engines/tetraedge/game/documents_browser.cpp | 17 +++--- engines/tetraedge/game/game.cpp | 57 ++++++++++--------- engines/tetraedge/game/game.h | 2 +- engines/tetraedge/game/in_game_scene.cpp | 40 +++++++------ engines/tetraedge/game/in_game_scene.h | 10 ++-- engines/tetraedge/game/inventory.cpp | 5 +- engines/tetraedge/game/inventory_object.cpp | 4 +- engines/tetraedge/game/inventory_object.h | 2 +- engines/tetraedge/game/loc_file.cpp | 11 ++-- engines/tetraedge/game/loc_file.h | 4 +- engines/tetraedge/game/object3d.cpp | 2 +- engines/tetraedge/game/owner_error_menu.cpp | 3 +- engines/tetraedge/te/te_3d_texture.cpp | 23 ++++---- engines/tetraedge/te/te_3d_texture.h | 4 +- engines/tetraedge/te/te_3d_texture_opengl.cpp | 5 +- engines/tetraedge/te/te_3d_texture_tinygl.cpp | 5 +- engines/tetraedge/te/te_core.cpp | 48 +++++++++++----- engines/tetraedge/te/te_core.h | 2 +- engines/tetraedge/te/te_font3.cpp | 23 +++++--- engines/tetraedge/te/te_font3.h | 5 +- engines/tetraedge/te/te_i_codec.h | 2 +- engines/tetraedge/te/te_image.cpp | 12 ++-- engines/tetraedge/te/te_image.h | 2 +- engines/tetraedge/te/te_images_sequence.cpp | 26 ++++----- engines/tetraedge/te/te_images_sequence.h | 2 +- engines/tetraedge/te/te_interpolation.cpp | 6 +- engines/tetraedge/te/te_interpolation.h | 4 +- engines/tetraedge/te/te_lua_gui.cpp | 20 ++++--- engines/tetraedge/te/te_lua_gui.h | 10 ++-- .../tetraedge/te/te_lua_gui_lua_callbacks.cpp | 11 +++- engines/tetraedge/te/te_lua_script.cpp | 14 ++--- engines/tetraedge/te/te_lua_script.h | 4 +- engines/tetraedge/te/te_lua_thread.cpp | 8 +-- engines/tetraedge/te/te_lua_thread.h | 4 +- engines/tetraedge/te/te_material.cpp | 17 ++++-- engines/tetraedge/te/te_material.h | 2 +- engines/tetraedge/te/te_model.h | 4 +- engines/tetraedge/te/te_model_animation.cpp | 4 +- engines/tetraedge/te/te_music.cpp | 10 ++-- engines/tetraedge/te/te_music.h | 4 +- engines/tetraedge/te/te_resource.h | 6 +- engines/tetraedge/te/te_resource_manager.cpp | 5 +- engines/tetraedge/te/te_resource_manager.h | 29 +++++----- engines/tetraedge/te/te_scene.h | 2 +- engines/tetraedge/te/te_scummvm_codec.cpp | 10 ++-- engines/tetraedge/te/te_scummvm_codec.h | 4 +- engines/tetraedge/te/te_sound_manager.cpp | 6 +- engines/tetraedge/te/te_sprite_layout.cpp | 26 +++++++-- engines/tetraedge/te/te_sprite_layout.h | 3 +- engines/tetraedge/te/te_text_layout.cpp | 4 +- engines/tetraedge/te/te_theora.cpp | 14 ++--- engines/tetraedge/te/te_theora.h | 4 +- engines/tetraedge/te/te_tiled_surface.cpp | 28 +++++---- engines/tetraedge/te/te_tiled_surface.h | 7 ++- engines/tetraedge/te/te_tiled_texture.cpp | 13 +++-- engines/tetraedge/te/te_tiled_texture.h | 2 +- 59 files changed, 354 insertions(+), 296 deletions(-) diff --git a/engines/tetraedge/game/application.cpp b/engines/tetraedge/game/application.cpp index 9de4362532f0..7edb7be13962 100644 --- a/engines/tetraedge/game/application.cpp +++ b/engines/tetraedge/game/application.cpp @@ -98,18 +98,13 @@ void Application::create() { _mainWindow.setPosition(TeVector3f32(0.0f, 0.0f, 0.0f)); TeResourceManager *resmgr = g_engine->getResourceManager(); - _fontComic = resmgr->getResourceNoSearch("Common/Fonts/ComicRelief.ttf"); - _fontComic->load("Common/Fonts/ComicRelief.ttf"); - _fontArgh = resmgr->getResourceNoSearch("Common/Fonts/Argh.ttf"); - _fontArgh->load("Common/Fonts/Argh.ttf"); - _fontArial = resmgr->getResourceNoSearch("Common/Fonts/arial.ttf"); - _fontArial->load("Common/Fonts/arial.ttf"); - _fontChaucer = resmgr->getResourceNoSearch("Common/Fonts/CHAUCER.TTF"); - _fontChaucer->load("Common/Fonts/CHAUCER.ttf"); - _fontColaborate = resmgr->getResourceNoSearch("Common/Fonts/Colaborate-Regular.otf"); - _fontColaborate->load("Common/Fonts/Colaborate-Regular.ttf"); - _fontProDisplay = resmgr->getResourceNoSearch("Common/Fonts/ProDisplay.ttf"); - _fontProDisplay->load("Common/Fonts/ProDisplay.ttf"); + TeCore *core = g_engine->getCore(); + _fontComic = resmgr->getResource(core->findFile("Common/Fonts/ComicRelief.ttf")); + _fontArgh = resmgr->getResource(core->findFile("Common/Fonts/Argh.ttf")); + _fontArial = resmgr->getResource(core->findFile("Common/Fonts/arial.ttf")); + _fontChaucer = resmgr->getResource(core->findFile("Common/Fonts/CHAUCER.TTF")); + _fontColaborate = resmgr->getResource(core->findFile("Common/Fonts/Colaborate-Regular.otf")); + _fontProDisplay = resmgr->getResource(core->findFile("Common/Fonts/ProDisplay.ttf")); // The app prebuilds some fonts.. cover letters, numbers, a few accented chars, and punctuation. // Skip that here. @@ -136,16 +131,15 @@ void Application::create() { textBase.build(); */ - TeCore *core = g_engine->getCore(); static const char allLangs[][3] = {"en", "fr", "de", "es", "it", "ru"}; const Common::Path textsPath("texts"); // Try alternate langs.. int i = 0; - Common::Path textFilePath; + Common::FSNode textFileNode; while (i < ARRAYSIZE(allLangs)) { - textFilePath = core->findFile(textsPath.join(core->language() + ".xml")); - if (Common::File::exists(textFilePath)) + textFileNode = core->findFile(textsPath.join(core->language() + ".xml")); + if (textFileNode.isReadable()) break; core->language(allLangs[i]); i++; @@ -154,7 +148,7 @@ void Application::create() { error("Couldn't find texts/[lang].xml for any language."); } - _loc.load(textFilePath); + _loc.load(textFileNode); core->addLoc(&_loc); const Common::Path helpMenuPath("menus/help/help_"); @@ -208,8 +202,7 @@ void Application::create() { // Note: The games do some loading of a "version.ver" file here to add a // watermark to the backLayout, but that file doesn't exist in any of the // GOG games so it was probably only used during development. - const Common::Path verFilePath("version.ver"); - if (Common::File::exists(verFilePath)) { + if (Common::File::exists("version.ver")) { warning("Skipping doing anything with version.ver file"); } @@ -461,7 +454,7 @@ void Application::performRender() { drawFront(); renderer->renderTransparentMeshes(); game->scene().drawPath(); - g_system->updateScreen(); + renderer->updateScreen(); #ifdef TETRAEDGE_DUMP_LAYOUTS renderCount++; diff --git a/engines/tetraedge/game/billboard.cpp b/engines/tetraedge/game/billboard.cpp index 466fc0596506..94b36bec1e3a 100644 --- a/engines/tetraedge/game/billboard.cpp +++ b/engines/tetraedge/game/billboard.cpp @@ -25,6 +25,8 @@ #include "tetraedge/game/billboard.h" #include "tetraedge/game/game.h" +#include "tetraedge/te/te_core.h" + namespace Tetraedge { Billboard::Billboard() : _hasPos2(false) { @@ -34,8 +36,9 @@ bool Billboard::load(const Common::String &path) { _model = new TeModel(); TeIntrusivePtr texture = Te3DTexture::makeInstance(); Game *game = g_engine->getGame(); - Common::Path texpath = game->sceneZonePath().join(path); - texture->load(texpath); + TeCore *core = g_engine->getCore(); + Common::FSNode texnode = core->findFile(game->sceneZonePath().join(path)); + texture->load(texnode); _model->setName(path); Common::Array quad; quad.resize(4); diff --git a/engines/tetraedge/game/character.cpp b/engines/tetraedge/game/character.cpp index 849d204e263c..467e48e42a65 100644 --- a/engines/tetraedge/game/character.cpp +++ b/engines/tetraedge/game/character.cpp @@ -363,10 +363,10 @@ bool Character::loadModel(const Common::String &mname, bool unused) { _characterSettings = _globalCharacterSettings->getVal(mname); _model->setTexturePath("models/Textures"); _model->setEnableLights(true); - Common::Path modelPath("models"); - modelPath.joinInPlace(_characterSettings._modelFileName); - if (!_model->load(modelPath)) + if (!_model->load(Common::Path("models").join(_characterSettings._modelFileName))) { + warning("Failed to load character model %s", _characterSettings._modelFileName.c_str()); return false; + } _model->setName(mname); _model->setScale(_characterSettings._defaultScale); @@ -391,7 +391,8 @@ bool Character::loadModel(const Common::String &mname, bool unused) { _walkLoopAnimLen = animLengthFromFile(walkAnim(WalkPart_Loop), &_walkLoopAnimFrameCount); TeIntrusivePtr shadow = Te3DTexture::makeInstance(); - shadow->load("models/Textures/simple_shadow_alpha.tga"); + TeCore *core = g_engine->getCore(); + shadow->load(core->findFile("models/Textures/simple_shadow_alpha.tga")); for (int i = 0; i < 2; i++) { TeModel *pmodel = new TeModel(); diff --git a/engines/tetraedge/game/documents_browser.cpp b/engines/tetraedge/game/documents_browser.cpp index 2a7297a01d20..dea5f6639474 100644 --- a/engines/tetraedge/game/documents_browser.cpp +++ b/engines/tetraedge/game/documents_browser.cpp @@ -173,11 +173,11 @@ void DocumentsBrowser::showDocument(const Common::String &docName, int startPage TeCore *core = g_engine->getCore(); const Common::Path docPathBase(Common::String::format("DocumentsBrowser/Documents/Documents/%s_zoomed_%d", docName.c_str(), (int)startPage)); Common::Path docPath = docPathBase.append(".png"); - docPath = core->findFile(docPath); - if (!Common::File::exists(docPath)) { + Common::FSNode docNode = core->findFile(docPath); + if (!docNode.exists()) { docPath = docPathBase.append(".jpg"); - docPath = core->findFile(docPath); - if (!Common::File::exists(docPath)) { + docNode = core->findFile(docPath); + if (!docNode.exists()) { // Probably the end of the doc if (startPage == 0) warning("Can't find first page of doc named %s", docName.c_str()); @@ -189,7 +189,7 @@ void DocumentsBrowser::showDocument(const Common::String &docName, int startPage app->captureFade(); TeSpriteLayout *sprite = _gui1.spriteLayoutChecked("zoomedSprite"); //sprite->setSizeType(ABSOLUTE); - sprite->load(docPath); + sprite->load(docNode); TeVector2s32 spriteSize = sprite->_tiledSurfacePtr->tiledTexture()->totalSize(); sprite->setSizeType(RELATIVE_TO_PARENT); TeVector3f32 winSize = app->getMainWindow().size(); @@ -200,10 +200,9 @@ void DocumentsBrowser::showDocument(const Common::String &docName, int startPage error("DocumentsBrowser::showDocument Couldn't fetch scroll object"); scroll->resetScrollPosition(); scroll->playAutoScroll(); - Common::Path luaPath = docPathBase.append(".lua"); - luaPath = core->findFile(luaPath); - if (Common::File::exists(luaPath)) { - _gui2.load(luaPath); + Common::FSNode luaNode = core->findFile(docPathBase.append(".lua")); + if (luaNode.exists()) { + _gui2.load(luaNode); error("Finish DocumentsBrowser::showDocument"); } _gui1.layoutChecked("zoomed")->setVisible(true); diff --git a/engines/tetraedge/game/game.cpp b/engines/tetraedge/game/game.cpp index 90b3946b2169..8fb0cac712f9 100644 --- a/engines/tetraedge/game/game.cpp +++ b/engines/tetraedge/game/game.cpp @@ -500,23 +500,23 @@ bool Game::initWarp(const Common::String &zone, const Common::String &scene, boo TeCore *core = g_engine->getCore(); - const Common::Path intLuaPath = core->findFile(scenePath.join(Common::String::format("Int%s.lua", scene.c_str()))); - const Common::Path logicLuaPath = core->findFile(scenePath.join(Common::String::format("Logic%s.lua", scene.c_str()))); - const Common::Path setLuaPath = core->findFile(scenePath.join(Common::String::format("Set%s.lua", scene.c_str()))); - Common::Path forLuaPath = core->findFile(scenePath.join(Common::String::format("For%s.lua", scene.c_str()))); - const Common::Path markerLuaPath = core->findFile(scenePath.join(Common::String::format("Marker%s.lua", scene.c_str()))); - - bool intLuaExists = Common::File::exists(intLuaPath); - bool logicLuaExists = Common::File::exists(logicLuaPath); - bool setLuaExists = Common::File::exists(setLuaPath); - bool forLuaExists = Common::File::exists(forLuaPath); + const Common::FSNode intLuaNode = core->findFile(scenePath.join(Common::String::format("Int%s.lua", scene.c_str()))); + const Common::FSNode logicLuaNode = core->findFile(scenePath.join(Common::String::format("Logic%s.lua", scene.c_str()))); + const Common::FSNode setLuaNode = core->findFile(scenePath.join(Common::String::format("Set%s.lua", scene.c_str()))); + Common::FSNode forLuaNode = core->findFile(scenePath.join(Common::String::format("For%s.lua", scene.c_str()))); + const Common::FSNode markerLuaNode = core->findFile(scenePath.join(Common::String::format("Marker%s.lua", scene.c_str()))); + + bool intLuaExists = intLuaNode.exists(); + bool logicLuaExists = logicLuaNode.exists(); + bool setLuaExists = setLuaNode.exists(); + bool forLuaExists = forLuaNode.exists(); if (!forLuaExists) { // slight hack.. try an alternate For lua path. - forLuaPath = scenePath.join("Android-MacOSX").join(Common::String::format("For%s.lua", scene.c_str())); - forLuaExists = Common::File::exists(forLuaPath); - debug("searched for %s", forLuaPath.toString().c_str()); + forLuaNode = core->findFile(scenePath.join("Android-MacOSX").join(Common::String::format("For%s.lua", scene.c_str()))); + forLuaExists = forLuaNode.exists(); + debug("searched for %s", forLuaNode.getName().c_str()); } - bool markerLuaExists = Common::File::exists(markerLuaPath); + bool markerLuaExists = markerLuaNode.exists(); if (!intLuaExists && !logicLuaExists && !setLuaExists && !forLuaExists && !markerLuaExists) { debug("No lua scripts for scene %s zone %s", scene.c_str(), zone.c_str()); @@ -530,9 +530,9 @@ bool Game::initWarp(const Common::String &zone, const Common::String &scene, boo if (logicLuaExists) { _luaContext.addBindings(LuaBinds::LuaOpenBinds); _luaScript.attachToContext(&_luaContext); - _luaScript.load("menus/help/help.lua"); + _luaScript.load(core->findFile("menus/help/help.lua")); _luaScript.execute(); - _luaScript.load(logicLuaPath); + _luaScript.load(logicLuaNode); } if (_forGui.loaded()) @@ -544,12 +544,12 @@ bool Game::initWarp(const Common::String &zone, const Common::String &scene, boo _scene.hitObjectGui().unload(); Common::Path geomPath(Common::String::format("scenes/%s/Geometry%s.bin", zone.c_str(), zone.c_str())); - _scene.load(geomPath); - _scene.loadBackground(setLuaPath); + _scene.load(core->findFile(geomPath)); + _scene.loadBackground(setLuaNode); Application *app = g_engine->getApplication(); if (forLuaExists) { - _forGui.load(forLuaPath); + _forGui.load(forLuaNode); TeLayout *bg = _forGui.layoutChecked("background"); bg->setRatioMode(TeILayout::RATIO_MODE_NONE); app->frontLayout().addChild(bg); @@ -562,7 +562,7 @@ bool Game::initWarp(const Common::String &zone, const Common::String &scene, boo } if (intLuaExists) { - _scene.loadInteractions(intLuaPath); + _scene.loadInteractions(intLuaNode); TeLuaGUI::StringMap &blayouts = _scene.hitObjectGui().buttonLayouts(); for (auto &entry : blayouts) { HitObject *hobj = new HitObject(); @@ -608,7 +608,7 @@ bool Game::initWarp(const Common::String &zone, const Common::String &scene, boo } TeCheckboxLayout *markersCheckbox = _inGameGui.checkboxLayout("markersVisibleButton"); - markersCheckbox->setState(_markersVisible? TeCheckboxLayout::CheckboxStateActive : TeCheckboxLayout::CheckboxStateUnactive); + markersCheckbox->setState(_markersVisible ? TeCheckboxLayout::CheckboxStateActive : TeCheckboxLayout::CheckboxStateUnactive); markersCheckbox->onStateChangedSignal().add(this, &Game::onMarkersVisible); initNoScale(); @@ -860,7 +860,8 @@ bool Game::loadPlayerCharacter(const Common::String &name) { } bool Game::loadScene(const Common::String &name) { - _gameEnterScript.load("scenes/OnGameEnter.lua"); + TeCore *core = g_engine->getCore(); + _gameEnterScript.load(core->findFile("scenes/OnGameEnter.lua")); _gameEnterScript.execute(); Character *character = _scene._character; if (character && character->_model->visible()) { @@ -1037,8 +1038,8 @@ bool Game::onLockVideoButtonValidated() { } bool Game::onMarkersVisible(TeCheckboxLayout::State state) { - _markersVisible = (state == 0); - showMarkers(state == 0); + _markersVisible = (state == TeCheckboxLayout::CheckboxStateActive); + showMarkers(state == TeCheckboxLayout::CheckboxStateActive); return false; } @@ -1178,7 +1179,7 @@ bool Game::onMouseMove() { if (!_entered) return false; - const Common::Path DEFAULT_CURSOR("pictures/cursor.png"); + const Common::String DEFAULT_CURSOR("pictures/cursor.png"); Application *app = g_engine->getApplication(); @@ -1260,7 +1261,7 @@ bool Game::onVideoFinished() { app->captureFade(); TeSpriteLayout *video = _inGameGui.spriteLayoutChecked("video"); - Common::String vidPath = video->_tiledSurfacePtr->path().toString(); + Common::String vidPath = video->_tiledSurfacePtr->loadedPath(); TeButtonLayout *btn = _inGameGui.buttonLayoutChecked("videoBackgroundButton"); btn->setVisible(false); btn = _inGameGui.buttonLayoutChecked("skipVideoButton"); @@ -1392,7 +1393,7 @@ void Game::playSound(const Common::String &name, int repeats, float volume) { } } else if (repeats == -1) { for (GameSound *snd : _gameSounds) { - const Common::String accessName = snd->getAccessName().toString(); + const Common::String accessName = snd->getAccessName(); if (accessName == name) { snd->setRetain(true); return; @@ -1476,7 +1477,7 @@ bool Game::setBackground(const Common::String &name) { return _scene.changeBackground(name); } -void Game::setCurrentObjectSprite(const Common::Path &spritePath) { +void Game::setCurrentObjectSprite(const Common::String &spritePath) { TeSpriteLayout *currentSprite = _inGameGui.spriteLayout("currentObjectSprite"); if (currentSprite) { if (spritePath.empty()) diff --git a/engines/tetraedge/game/game.h b/engines/tetraedge/game/game.h index dde72dff7338..97546d619497 100644 --- a/engines/tetraedge/game/game.h +++ b/engines/tetraedge/game/game.h @@ -156,7 +156,7 @@ class Game { void resumeSounds() {}; // does nothing? void saveBackup(const Common::String &saveName); bool setBackground(const Common::String &name); - void setCurrentObjectSprite(const Common::Path &spritePath); + void setCurrentObjectSprite(const Common::String &spritePath); bool showMarkers(bool val); bool startAnimation(const Common::String &animName, int loopcount, bool reversed); void startAnimationPart(const Common::String ¶m_1, int param_2, int param_3, int param_4, bool param_5) {}; diff --git a/engines/tetraedge/game/in_game_scene.cpp b/engines/tetraedge/game/in_game_scene.cpp index dbbe1e2aac38..9d5c2509d124 100644 --- a/engines/tetraedge/game/in_game_scene.cpp +++ b/engines/tetraedge/game/in_game_scene.cpp @@ -68,6 +68,7 @@ void InGameScene::addAnchorZone(const Common::String &s1, const Common::String & } } + assert(currentCamera()); currentCamera()->apply(); AnchorZone *zone = new AnchorZone(); zone->_name = name; @@ -513,7 +514,7 @@ Common::String InGameScene::imagePathMarker(const Common::String &name) { for (Te3DObject2 *child : bg->childList()) { TeSpriteLayout *spritelayout = dynamic_cast(child); if (spritelayout && spritelayout->name() == name) { - return spritelayout->_tiledSurfacePtr->path().toString(); + return spritelayout->_tiledSurfacePtr->loadedPath(); } } return Common::String(); @@ -539,7 +540,7 @@ bool InGameScene::isObjectBlocking(const Common::String &name) { return false; } -bool InGameScene::load(const Common::Path &path) { +bool InGameScene::load(const Common::FSNode &sceneNode) { _actZones.clear(); Common::File actzonefile; if (actzonefile.open(getActZoneFileName())) { @@ -568,16 +569,18 @@ bool InGameScene::load(const Common::Path &path) { _shadowLightNo = -1; const Common::Path lightspath = getLightsFileName(); - if (Common::File::exists(lightspath)) - loadLights(lightspath); + TeCore *core = g_engine->getCore(); + const Common::FSNode lightsNode(core->findFile(lightspath)); + if (lightsNode.isReadable()) + loadLights(lightsNode); - if (!Common::File::exists(path)) + if (!sceneNode.isReadable()) return false; close(); - _loadedPath = path; + _loadedPath = sceneNode.getPath(); Common::File scenefile; - if (!scenefile.open(path)) + if (!scenefile.open(sceneNode)) return false; uint32 ncameras = scenefile.readUint32LE(); @@ -688,15 +691,15 @@ bool InGameScene::loadCharacter(const Common::String &name) { return true; } -bool InGameScene::loadLights(const Common::Path &path) { +bool InGameScene::loadLights(const Common::FSNode &node) { SceneLightsXmlParser parser; parser.setLightArray(&_lights); - if (!parser.loadFile(path.toString())) - error("InGameScene::loadLights: Can't load %s", path.toString().c_str()); + if (!parser.loadFile(node)) + error("InGameScene::loadLights: Can't load %s", node.getPath().c_str()); if (!parser.parse()) - error("InGameScene::loadLights: Can't parse %s", path.toString().c_str()); + error("InGameScene::loadLights: Can't parse %s", node.getPath().c_str()); _shadowColor = parser.getShadowColor(); _shadowLightNo = parser.getShadowLightNo(); @@ -722,8 +725,8 @@ bool InGameScene::loadLights(const Common::Path &path) { return true; } -void InGameScene::loadMarkers(const Common::Path &path) { - _markerGui.load(path); +void InGameScene::loadMarkers(const Common::FSNode &node) { + _markerGui.load(node); TeLayout *bg = _bgGui.layoutChecked("background"); TeSpriteLayout *root = Game::findSpriteLayoutByName(bg, "root"); bg->setRatioMode(TeILayout::RATIO_MODE_NONE); @@ -749,12 +752,13 @@ bool InGameScene::loadObject(const Common::String &name) { bool InGameScene::loadObjectMaterials(const Common::String &name) { TeImage img; bool retval = false; + TeCore *core = g_engine->getCore(); for (auto &obj : _objects) { if (obj._name.empty()) continue; Common::Path mpath = _loadedPath.getParent().join(name).join(obj._name + ".png"); - if (img.load(mpath)) { + if (img.load(core->findFile(mpath))) { Te3DTexture *tex = Te3DTexture::makeInstance(); tex->load(img); obj._model->meshes()[0]->defaultMaterial(tex); @@ -852,8 +856,8 @@ void InGameScene::loadBlockers() { } } -void InGameScene::loadBackground(const Common::Path &path) { - _bgGui.load(path); +void InGameScene::loadBackground(const Common::FSNode &node) { + _bgGui.load(node); TeLayout *bg = _bgGui.layout("background"); TeLayout *root = _bgGui.layout("root"); bg->setRatioMode(TeILayout::RATIO_MODE_NONE); @@ -887,8 +891,8 @@ bool InGameScene::loadBillboard(const Common::String &name) { } } -void InGameScene::loadInteractions(const Common::Path &path) { - _hitObjectGui.load(path); +void InGameScene::loadInteractions(const Common::FSNode &node) { + _hitObjectGui.load(node); TeLayout *bgbackground = _bgGui.layoutChecked("background"); Game *game = g_engine->getGame(); TeSpriteLayout *root = game->findSpriteLayoutByName(bgbackground, "root"); diff --git a/engines/tetraedge/game/in_game_scene.h b/engines/tetraedge/game/in_game_scene.h index 7f799b6059c2..183dd82dc570 100644 --- a/engines/tetraedge/game/in_game_scene.h +++ b/engines/tetraedge/game/in_game_scene.h @@ -134,14 +134,14 @@ class InGameScene : public TeScene { bool isVisibleMarker(const Common::String &name); TeVector2f32 layerSize(); - virtual bool load(const Common::Path &path) override; - void loadBackground(const Common::Path &path); + virtual bool load(const Common::FSNode &node) override; + void loadBackground(const Common::FSNode &node); bool loadBillboard(const Common::String &name); void loadBlockers(); bool loadCharacter(const Common::String &name); - void loadInteractions(const Common::Path &path); - bool loadLights(const Common::Path &path); - void loadMarkers(const Common::Path &path); + void loadInteractions(const Common::FSNode &node); + bool loadLights(const Common::FSNode &node); + void loadMarkers(const Common::FSNode &node); bool loadObject(const Common::String &oname); bool loadObjectMaterials(const Common::String &name); bool loadObjectMaterials(const Common::String &path, const Common::String &name); diff --git a/engines/tetraedge/game/inventory.cpp b/engines/tetraedge/game/inventory.cpp index 422e46e7c580..dd499915b732 100644 --- a/engines/tetraedge/game/inventory.cpp +++ b/engines/tetraedge/game/inventory.cpp @@ -426,7 +426,8 @@ void Inventory::selectedObject(InventoryObject *obj) { objectDescription(objId).c_str()); _gui.textLayout("text")->setText(text); _gui.buttonLayoutChecked("lire")->setEnable(isDocument(objId)); - game->setCurrentObjectSprite(obj->spritePath()); + const Common::String spritePathStr = obj->spritePath(); + game->setCurrentObjectSprite(spritePathStr); TeLayout *textObj = _gui.layout("textObject"); for (int i = 0; i < textObj->childCount(); i++) { if (textObj->child(i)->name() == obj->name()) { @@ -436,7 +437,7 @@ void Inventory::selectedObject(InventoryObject *obj) { textObj->child(i)->setVisible(false); } } - game->inGameGui().spriteLayoutChecked("selectedObject")->load(obj->spritePath()); + game->inGameGui().spriteLayoutChecked("selectedObject")->load(spritePathStr); } } diff --git a/engines/tetraedge/game/inventory_object.cpp b/engines/tetraedge/game/inventory_object.cpp index 8bf17bc5662f..8e4ce0f9d0ee 100644 --- a/engines/tetraedge/game/inventory_object.cpp +++ b/engines/tetraedge/game/inventory_object.cpp @@ -38,8 +38,8 @@ void InventoryObject::load(const Common::String &newName) { // TODO: btn->setDoubleValidationProtectionEnabled(false) } -Common::Path InventoryObject::spritePath() { - return Common::Path("Inventory/Objects").join(name()).append(".png"); +Common::String InventoryObject::spritePath() { + return Common::Path("Inventory/Objects").join(name()).append(".png").toString(); } bool InventoryObject::onButtonDown() { diff --git a/engines/tetraedge/game/inventory_object.h b/engines/tetraedge/game/inventory_object.h index ccee9fe5a14f..0a9c4c782d8b 100644 --- a/engines/tetraedge/game/inventory_object.h +++ b/engines/tetraedge/game/inventory_object.h @@ -33,7 +33,7 @@ class InventoryObject : public TeLayout { InventoryObject(); void load(const Common::String &name); - Common::Path spritePath(); + Common::String spritePath(); bool onButtonDown(); TeSignal1Param &selectedSignal() { return _selectedSignal; }; diff --git a/engines/tetraedge/game/loc_file.cpp b/engines/tetraedge/game/loc_file.cpp index c89f69502d92..1019e6e82f3d 100644 --- a/engines/tetraedge/game/loc_file.cpp +++ b/engines/tetraedge/game/loc_file.cpp @@ -31,12 +31,13 @@ namespace Tetraedge { LocFile::LocFile() { } -void LocFile::load(const Common::Path &path) { +void LocFile::load(const Common::FSNode &fsnode) { TeNameValXmlParser parser; const Common::String xmlHeader(""); Common::File locFile; - if (!locFile.open(path)) - error("LocFile::load: failed to open %s.", path.toString().c_str()); + const Common::String path = fsnode.getName(); + if (!locFile.open(fsnode)) + error("LocFile::load: failed to open %s.", path.c_str()); int64 fileLen = locFile.size(); char *buf = new char[fileLen + 1]; @@ -46,10 +47,10 @@ void LocFile::load(const Common::Path &path) { delete [] buf; locFile.close(); if (!parser.loadBuffer((const byte *)xmlContents.c_str(), xmlContents.size())) - error("LocFile::load: failed to load %s.", path.toString().c_str()); + error("LocFile::load: failed to load %s.", path.c_str()); if (!parser.parse()) - error("LocFile::load: failed to parse %s.", path.toString().c_str()); + error("LocFile::load: failed to parse %s.", path.c_str()); _map = parser.getMap(); } diff --git a/engines/tetraedge/game/loc_file.h b/engines/tetraedge/game/loc_file.h index 77051a5b2f4e..f1e182b995dd 100644 --- a/engines/tetraedge/game/loc_file.h +++ b/engines/tetraedge/game/loc_file.h @@ -23,7 +23,7 @@ #define TETRAEDGE_GAME_LOC_FILE_H #include "common/str.h" -#include "common/path.h" +#include "common/fs.h" #include "tetraedge/te/te_i_loc.h" @@ -34,7 +34,7 @@ class LocFile : public TeILoc { LocFile(); //const Common::String *avatar(const Common::String &key); - void load(const Common::Path &path); + void load(const Common::FSNode &fsnode); const Common::String *value(const Common::String &key) const; }; diff --git a/engines/tetraedge/game/object3d.cpp b/engines/tetraedge/game/object3d.cpp index 4006e12ee710..c4b3e51809a2 100644 --- a/engines/tetraedge/game/object3d.cpp +++ b/engines/tetraedge/game/object3d.cpp @@ -49,7 +49,7 @@ bool Object3D::loadModel(const Common::String &name) { _modelFileName = settings->_value._modelFileName; _defaultScale = settings->_value._defaultScale; _modelPtr->setTexturePath("objects/Textures"); - bool loaded = _modelPtr->load(Common::Path("objects").join(_modelFileName)); + bool loaded = _modelPtr->load(Common::Path("objects").join(_modelFileName).toString()); if (loaded) { _modelPtr->setName(name); _modelPtr->setScale(_defaultScale); diff --git a/engines/tetraedge/game/owner_error_menu.cpp b/engines/tetraedge/game/owner_error_menu.cpp index f2adc7e179b3..6d2797b04e04 100644 --- a/engines/tetraedge/game/owner_error_menu.cpp +++ b/engines/tetraedge/game/owner_error_menu.cpp @@ -34,8 +34,7 @@ OwnerErrorMenu::OwnerErrorMenu() : _entered(false) { void OwnerErrorMenu::enter() { _entered = true; - const Common::Path luaPath("menus/ownerError/ownerError.lua"); - load(luaPath); + load("menus/ownerError/ownerError.lua"); Application *app = g_engine->getApplication(); TeLayout *menuLayout = layoutChecked("menu"); app->frontLayout().addChild(menuLayout); diff --git a/engines/tetraedge/te/te_3d_texture.cpp b/engines/tetraedge/te/te_3d_texture.cpp index 65b96d4f9847..8a9e5517128f 100644 --- a/engines/tetraedge/te/te_3d_texture.cpp +++ b/engines/tetraedge/te/te_3d_texture.cpp @@ -44,28 +44,31 @@ bool Te3DTexture::hasAlpha() const { } /*static*/ -TeIntrusivePtr Te3DTexture::load2(const Common::Path &path, uint size) { - Common::Path fullPath = path.append(".3dtex"); +TeIntrusivePtr Te3DTexture::load2(const Common::FSNode &node, uint size) { + const Common::String fullPath = node.getPath() + ".3dtex"; TeResourceManager *resMgr = g_engine->getResourceManager(); if (!resMgr->exists(fullPath)) { TeIntrusivePtr retval(makeInstance()); - retval->load(path); + if (!node.isReadable()) + warning("Request to load unreadable texture %s", node.getPath().c_str()); + bool result = retval->load(node); + if (!result) + warning("Failed loading texture %s", node.getPath().c_str()); retval->setAccessName(fullPath); resMgr->addResource(retval.get()); return retval; } else { - return resMgr->getResourceOrMakeInstance(fullPath); + return resMgr->getResourceByName(fullPath); } } -bool Te3DTexture::load(const Common::Path &path) { +bool Te3DTexture::load(const Common::FSNode &node) { TeResourceManager *resmgr = g_engine->getResourceManager(); - Common::Path resPath = path; - TeIntrusivePtr img = resmgr->getResource(resPath); - load(*img); - setAccessName(resPath.append(".3dtex")); - return true; + TeIntrusivePtr img = resmgr->getResource(node); + bool result = load(*img); + setAccessName(node.getPath() + ".3dtex"); + return result; } /*static*/ diff --git a/engines/tetraedge/te/te_3d_texture.h b/engines/tetraedge/te/te_3d_texture.h index 3182853e9676..fa146c7bc33f 100644 --- a/engines/tetraedge/te/te_3d_texture.h +++ b/engines/tetraedge/te/te_3d_texture.h @@ -48,9 +48,9 @@ class Te3DTexture : public TeResource { TeImage::Format getFormat() const { return _format; } bool hasAlpha() const; - bool load(const Common::Path &path); + bool load(const Common::FSNode &path); virtual bool load(const TeImage &img) = 0; - static TeIntrusivePtr load2(const Common::Path &path, uint size); + static TeIntrusivePtr load2(const Common::FSNode &node, uint size); static TeVector2s32 optimisedSize(const TeVector2s32 &size); diff --git a/engines/tetraedge/te/te_3d_texture_opengl.cpp b/engines/tetraedge/te/te_3d_texture_opengl.cpp index 004baa8e4716..4436ffd1b492 100644 --- a/engines/tetraedge/te/te_3d_texture_opengl.cpp +++ b/engines/tetraedge/te/te_3d_texture_opengl.cpp @@ -111,8 +111,7 @@ void Te3DTextureOpenGL::forceTexData(uint gltexture, uint xsize, uint ysize) { } bool Te3DTextureOpenGL::load(const TeImage &img) { - Common::Path accessName = img.getAccessName(); - setAccessName(accessName.append(".3dtex")); + setAccessName(img.getAccessName() + ".3dtex"); _width = img.w; _height = img.h; @@ -193,7 +192,7 @@ void Te3DTextureOpenGL::update(const TeImage &img, uint xoff, uint yoff) { if (!img.w || !img.h) return; - setAccessName(img.getAccessName().append(".3dtex")); + setAccessName(img.getAccessName() + ".3dtex"); glBindTexture(GL_TEXTURE_2D, _glTexture); glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE); glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE); diff --git a/engines/tetraedge/te/te_3d_texture_tinygl.cpp b/engines/tetraedge/te/te_3d_texture_tinygl.cpp index 71116ecb6061..2f14d170933f 100644 --- a/engines/tetraedge/te/te_3d_texture_tinygl.cpp +++ b/engines/tetraedge/te/te_3d_texture_tinygl.cpp @@ -113,8 +113,7 @@ void Te3DTextureTinyGL::forceTexData(uint gltexture, uint xsize, uint ysize) { } bool Te3DTextureTinyGL::load(const TeImage &img) { - Common::Path accessName = img.getAccessName(); - setAccessName(accessName.append(".3dtex")); + setAccessName(img.getAccessName() + ".3dtex"); _width = img.w; _height = img.h; @@ -184,7 +183,7 @@ void Te3DTextureTinyGL::update(const TeImage &img, uint xoff, uint yoff) { if (!img.w || !img.h) return; - setAccessName(img.getAccessName().append(".3dtex")); + setAccessName(img.getAccessName() + ".3dtex"); tglBindTexture(TGL_TEXTURE_2D, _glTexture); // Note: these are unsupported in TGL but should be the defaults? //tglPixelStorei(TGL_UNPACK_SWAP_BYTES, TGL_FALSE); diff --git a/engines/tetraedge/te/te_core.cpp b/engines/tetraedge/te/te_core.cpp index 9f6059fa01a4..638a47e341d0 100644 --- a/engines/tetraedge/te/te_core.cpp +++ b/engines/tetraedge/te/te_core.cpp @@ -111,16 +111,34 @@ bool TeCore::onActivityTrackingAlarm() { error("TODO: Implement TeCore::onActivityTrackingAlarm"); } +static Common::FSNode _findSubPath(const Common::FSNode &parent, const Common::Path &childPath) { + if (childPath.empty()) + return parent; + Common::FSNode childNode = parent; + const Common::StringArray comps = childPath.splitComponents(); + unsigned int i; + for (i = 0; i < comps.size(); i++) { + childNode = childNode.getChild(comps[i]); + if (!childNode.exists()) + break; + } + if (i == comps.size()) + return childNode; + return Common::FSNode(); +} + -Common::Path TeCore::findFile(const Common::Path &path) { - if (Common::File::exists(path)) - return path; +Common::FSNode TeCore::findFile(const Common::Path &path) { + Common::FSNode node(path); + if (node.exists()) + return node; - const Common::String gamePath = ConfMan.get("path"); - const Common::Path resPath = Common::Path(gamePath).join("Resources"); - const Common::Path absolutePath = resPath.join(path); - if (Common::FSNode(absolutePath).isDirectory()) - return absolutePath; + const Common::FSNode gameRoot(ConfMan.get("path")); + if (!gameRoot.isDirectory()) + error("Game directory should be a directory"); + const Common::FSNode resNode = gameRoot.getChild("Resources"); + if (!resNode.isDirectory()) + error("Resources directory should exist in game"); const Common::Path fname = path.getLastComponent(); const Common::Path dir = path.getParent(); @@ -168,21 +186,23 @@ Common::Path TeCore::findFile(const Common::Path &path) { if (!lang.empty()) testPath.joinInPlace(lang); testPath.joinInPlace(fname); - if (Common::File::exists(testPath) || Common::FSNode(testPath).exists()) - return testPath; + node = _findSubPath(resNode, testPath); + if (node.exists()) + return node; // also try the other way around if (!lang.empty() && suffix) { testPath = dir.join(lang).joinInPlace(suffix).join(fname); - if (Common::File::exists(testPath) || Common::FSNode(testPath).exists()) - return testPath; + node = _findSubPath(resNode, testPath); + if (node.exists()) + return node; } } } // Didn't find it at all.. - warning("TeCore::findFile Searched but didn't find %s", path.toString().c_str()); - return path; + debug("TeCore::findFile Searched but didn't find %s", path.toString().c_str()); + return Common::FSNode(path); } } // end namespace Tetraedge diff --git a/engines/tetraedge/te/te_core.h b/engines/tetraedge/te/te_core.h index ec0f518d981a..431ff9743c8e 100644 --- a/engines/tetraedge/te/te_core.h +++ b/engines/tetraedge/te/te_core.h @@ -61,7 +61,7 @@ class TeCore { // Note: this is not in the original, but it's not clear how the original // adds things like "PC-MacOSX" to the path, and there is not clear logic // to them, so here we are. - Common::Path findFile(const Common::Path &path); + Common::FSNode findFile(const Common::Path &path); bool _coreNotReady; diff --git a/engines/tetraedge/te/te_font3.cpp b/engines/tetraedge/te/te_font3.cpp index 5a697c0cb04d..a42abbf783fd 100644 --- a/engines/tetraedge/te/te_font3.cpp +++ b/engines/tetraedge/te/te_font3.cpp @@ -83,12 +83,12 @@ Graphics::Font *TeFont3::getAtSize(uint size) { load(getAccessName()); if (!_fontFile.isOpen()) - error("TeFont3::: Couldn't open font file %s.", getAccessName().toString().c_str()); + error("TeFont3::: Couldn't open font file %s.", getAccessName().c_str()); _fontFile.seek(0); Graphics::Font *newFont = Graphics::loadTTFFont(_fontFile, size, Graphics::kTTFSizeModeCharacter, 0, Graphics::kTTFRenderModeNormal); if (!newFont) { - error("TeFont3::: Couldn't load font %s at size %d.", _loadedPath.toString().c_str(), size); + error("TeFont3::: Couldn't load font %s at size %d.", _loadedPath.c_str(), size); } _fonts.setVal(size, newFont); return newFont; @@ -147,24 +147,33 @@ void TeFont3::draw(TeImage &destImage, const Common::String &str, int fontSize, font->drawString(&destImage, str, 0, yoff, destImage.w, uintcol, talign); } +bool TeFont3::load(const Common::String &path) { + if (_loadedPath == path && _fontFile.isOpen()) + return true; // already open + + TeCore *core = g_engine->getCore(); + Common::FSNode node = core->findFile(path); + return load(node); +} -bool TeFont3::load(const Common::Path &path) { +bool TeFont3::load(const Common::FSNode &node) { + const Common::String path = node.getPath(); if (_loadedPath == path && _fontFile.isOpen()) return true; // already open setAccessName(path); _loadedPath = path; - if (!Common::File::exists(path)) { - warning("TeFont3::load: File %s doesn't exist", path.toString().c_str()); + if (!node.exists()) { + warning("TeFont3::load: File %s doesn't exist", path.c_str()); return false; } if (_fontFile.isOpen()) _fontFile.close(); - if (!_fontFile.open(path)) { - warning("TeFont3::load: can't open %s", path.toString().c_str()); + if (!_fontFile.open(node)) { + warning("TeFont3::load: can't open %s", path.c_str()); return false; } return true; diff --git a/engines/tetraedge/te/te_font3.h b/engines/tetraedge/te/te_font3.h index 44876c3393cf..a4fcd44f3d8a 100644 --- a/engines/tetraedge/te/te_font3.h +++ b/engines/tetraedge/te/te_font3.h @@ -62,7 +62,8 @@ class TeFont3 : public TeResource { TeIntrusivePtr _img; }; - bool load(const Common::Path &path); + bool load(const Common::String &path); + bool load(const Common::FSNode &node); void unload(); GlyphData glyph(uint size, uint charcode); @@ -88,7 +89,7 @@ class TeFont3 : public TeResource { Common::File _fontFile; Common::HashMap _fonts; - Common::Path _loadedPath; + Common::String _loadedPath; Common::HashMap> _fontSizeData; }; diff --git a/engines/tetraedge/te/te_i_codec.h b/engines/tetraedge/te/te_i_codec.h index 29909d342909..1c92aa351428 100644 --- a/engines/tetraedge/te/te_i_codec.h +++ b/engines/tetraedge/te/te_i_codec.h @@ -36,7 +36,7 @@ class TeICodec { TeICodec() {}; virtual ~TeICodec() {}; - virtual bool load(const Common::Path &path) = 0; + virtual bool load(const Common::FSNode &node) = 0; virtual uint width() = 0; virtual uint height() = 0; virtual int nbFrames() = 0; diff --git a/engines/tetraedge/te/te_image.cpp b/engines/tetraedge/te/te_image.cpp index 8d297a19b13d..b598d93e42bf 100644 --- a/engines/tetraedge/te/te_image.cpp +++ b/engines/tetraedge/te/te_image.cpp @@ -92,11 +92,12 @@ bool TeImage::isExtensionSupported(const Common::Path &path) { error("TODO: Implement TeImage::isExtensionSupported"); } -bool TeImage::load(const Common::Path &path) { +bool TeImage::load(const Common::FSNode &node) { TeCore *core = g_engine->getCore(); - TeICodec *codec = core->createVideoCodec(path); - if (!codec->load(path)) { - warning("TeImage::load: Failed to load %s.", path.toString().c_str()); + TeICodec *codec = core->createVideoCodec(node.getPath()); + if (!node.isReadable() || !codec->load(node)) { + warning("TeImage::load: Failed to load %s.", node.getPath().c_str()); + delete codec; return false; } @@ -104,8 +105,9 @@ bool TeImage::load(const Common::Path &path) { createImg(codec->width(), codec->height(), nullpal, codec->imageFormat(), codec->width(), codec->height()); if (!codec->update(0, *this)) { - error("TeImage::load: Failed to update from %s.", path.toString().c_str()); + error("TeImage::load: Failed to update from %s.", node.getPath().c_str()); } + delete codec; return true; } diff --git a/engines/tetraedge/te/te_image.h b/engines/tetraedge/te/te_image.h index 4f9b6379d3b1..4417169e5257 100644 --- a/engines/tetraedge/te/te_image.h +++ b/engines/tetraedge/te/te_image.h @@ -73,7 +73,7 @@ class TeImage : public TeResource, public Graphics::ManagedSurface { void fill(byte r, byte g, byte b, byte a); void getBuff(uint x, uint y, byte *pout, uint w, uint h); bool isExtensionSupported(const Common::Path &path); - bool load(const Common::Path &path); + bool load(const Common::FSNode &node); bool load(Common::ReadStream &stream, const Common::Path &path); bool save(const Common::Path &path, enum Type type); int serialize(Common::WriteStream &stream); diff --git a/engines/tetraedge/te/te_images_sequence.cpp b/engines/tetraedge/te/te_images_sequence.cpp index 1d993ea28a49..b8bf32a680d5 100644 --- a/engines/tetraedge/te/te_images_sequence.cpp +++ b/engines/tetraedge/te/te_images_sequence.cpp @@ -47,42 +47,40 @@ static bool compareNodes(const Common::FSNode &left, const Common::FSNode &right return left.getPath() < right.getPath(); } -bool TeImagesSequence::load(const Common::Path &path) { - Common::FSNode directory(path); +bool TeImagesSequence::load(const Common::FSNode &directory) { + const Common::String path = directory.getPath(); if (!directory.isDirectory()) { - warning("TeImagesSequence::load:: not a directory %s", path.toString().c_str()); + warning("TeImagesSequence::load:: not a directory %s", path.c_str()); return false; } Common::FSList children; if (!directory.getChildren(children, Common::FSNode::kListFilesOnly) || children.empty()) { - warning("TeImagesSequence::load:: couldn't get children of %s", path.toString().c_str()); + warning("TeImagesSequence::load:: couldn't get children of %s", path.c_str()); return false; } Common::sort(children.begin(), children.end(), compareNodes); - if (!SearchMan.hasArchive(path.toString())) - SearchMan.addDirectory(path.toString(), directory); + if (!SearchMan.hasArchive(path)) + SearchMan.addDirectory(path, directory); for (Common::FSNode &child : children) { - Common::String filePathStr = child.getPath(); + const Common::String fileName = child.getName(); - if (filePathStr.size() <= 10 || filePathStr.substr(filePathStr.size() - 7) != "fps.png") + if (fileName.size() <= 10 || fileName.substr(fileName.size() - 7) != "fps.png") continue; - Common::Path filePath(filePathStr); - Common::String fname = filePath.getLastComponent().toString(); - Common::String fstart = fname.substr(0, fname.size() - 7); + Common::String fstart = fileName.substr(0, fileName.size() - 7); int frameno = 0; int fps = 0; if (sscanf(fstart.c_str(), "%d-%d", &frameno, &fps) != 2) { - warning("TeImagesSequence::load can't match %s", fname.c_str()); + warning("TeImagesSequence::load can't match %s", fileName.c_str()); continue; } Common::SeekableReadStream *stream = child.createReadStream(); if (!stream) { - warning("TeImagesSequence::load can't open %s", filePath.toString().c_str()); + warning("TeImagesSequence::load can't open %s", child.getPath().c_str()); continue; } @@ -91,7 +89,7 @@ bool TeImagesSequence::load(const Common::Path &path) { if (!_width || (_width < 100 && _height < 100)) { Image::PNGDecoder png; if (!png.loadStream(*stream)) { - warning("Image sequence failed to load png %s", filePath.toString().c_str()); + warning("Image sequence failed to load png %s", child.getPath().c_str()); delete stream; return false; } diff --git a/engines/tetraedge/te/te_images_sequence.h b/engines/tetraedge/te/te_images_sequence.h index 92b004c1f12e..78bc7661402a 100644 --- a/engines/tetraedge/te/te_images_sequence.h +++ b/engines/tetraedge/te/te_images_sequence.h @@ -37,7 +37,7 @@ class TeImagesSequence : public TeICodec { TeImagesSequence(); virtual ~TeImagesSequence(); - virtual bool load(const Common::Path &path) override; + virtual bool load(const Common::FSNode &node) override; virtual uint width() override { return _width; } virtual uint height() override { return _height; } virtual int nbFrames() override { return _files.size(); } diff --git a/engines/tetraedge/te/te_interpolation.cpp b/engines/tetraedge/te/te_interpolation.cpp index 11a82fac83c5..0eb8b8c1ee51 100644 --- a/engines/tetraedge/te/te_interpolation.cpp +++ b/engines/tetraedge/te/te_interpolation.cpp @@ -37,10 +37,10 @@ void TeInterpolation::load(Common::ReadStream &stream) { _array[i] = stream.readFloatLE(); } -void TeInterpolation::load(Common::Path &path) { +void TeInterpolation::load(Common::FSNode &node) { Common::File f; - if (!f.open(path)) - error("Couldn't open %s", path.toString().c_str()); + if (!f.open(node)) + error("Couldn't open %s", node.getPath().c_str()); load(f); } diff --git a/engines/tetraedge/te/te_interpolation.h b/engines/tetraedge/te/te_interpolation.h index 58a7d1cacca1..98efed325df2 100644 --- a/engines/tetraedge/te/te_interpolation.h +++ b/engines/tetraedge/te/te_interpolation.h @@ -24,7 +24,7 @@ #include "common/array.h" #include "common/stream.h" -#include "common/path.h" +#include "common/fs.h" namespace Tetraedge { @@ -33,7 +33,7 @@ class TeInterpolation { TeInterpolation(); void load(Common::ReadStream &stream); - void load(Common::Path &path); + void load(Common::FSNode &node); // Note: this function is not in the original but simplifies // the code for TeCurveAnim2 a lot. diff --git a/engines/tetraedge/te/te_lua_gui.cpp b/engines/tetraedge/te/te_lua_gui.cpp index 0c61c3e01cd0..d975b165d5b9 100644 --- a/engines/tetraedge/te/te_lua_gui.cpp +++ b/engines/tetraedge/te/te_lua_gui.cpp @@ -154,7 +154,7 @@ TeButtonLayout *TeLuaGUI::buttonLayoutChecked(const Common::String &name) { TeButtonLayout *l = buttonLayout(name); if (!l) { error("No button '%s' in gui data '%s'", name.c_str(), - _scriptPath.toString().c_str()); + _scriptPath.c_str()); } return l; } @@ -163,7 +163,7 @@ TeLayout *TeLuaGUI::layoutChecked(const Common::String &name) { TeLayout *l = layout(name); if (!l) { error("No layout '%s' in gui data '%s'", name.c_str(), - _scriptPath.toString().c_str()); + _scriptPath.c_str()); } return l; } @@ -172,18 +172,20 @@ TeSpriteLayout *TeLuaGUI::spriteLayoutChecked(const Common::String &name) { TeSpriteLayout *l = spriteLayout(name); if (!l) { error("No sprite layout '%s' in gui data '%s'", name.c_str(), - _scriptPath.toString().c_str()); + _scriptPath.c_str()); } return l; } -bool TeLuaGUI::load(const Common::Path &path_) { - unload(); - _scriptPath = Common::Path(path_); +bool TeLuaGUI::load(const Common::String &subPath) { TeCore *core = g_engine->getCore(); - Common::Path path(path_); + return load(core->findFile(subPath)); +} + +bool TeLuaGUI::load(const Common::FSNode &node) { + unload(); + _scriptPath = node.getPath(); // Not the same as original, we abstract the search logic a bit. - path = core->findFile(path); _luaContext.setGlobal("Pixel", 0); _luaContext.setGlobal("Percent", 1); _luaContext.setGlobal("None", 0); @@ -208,7 +210,7 @@ bool TeLuaGUI::load(const Common::Path &path_) { _luaContext.registerCFunction("TeExtendedTextLayout", extendedTextLayoutBindings); _luaContext.setInRegistry("__TeLuaGUIThis", this); _luaScript.attachToContext(&_luaContext); - _luaScript.load(path); + _luaScript.load(node); _luaScript.execute(); _luaScript.unload(); _loaded = true; diff --git a/engines/tetraedge/te/te_lua_gui.h b/engines/tetraedge/te/te_lua_gui.h index d5eccc4efbfe..9232669f17f8 100644 --- a/engines/tetraedge/te/te_lua_gui.h +++ b/engines/tetraedge/te/te_lua_gui.h @@ -77,11 +77,11 @@ class TeLuaGUI : public TeObject { TeButtonLayout *buttonLayoutChecked(const Common::String &name); TeSpriteLayout *spriteLayoutChecked(const Common::String &name); - - bool load(const Common::Path &path); + bool load(const Common::String &subPath); + bool load(const Common::FSNode &node); void unload(); - TeVariant value(const Common::String &path); + TeVariant value(const Common::String &key); template using StringMap = Common::HashMap; @@ -99,13 +99,13 @@ class TeLuaGUI : public TeObject { StringMap *> &colorLinearAnimations() { return _colorLinearAnimations; } bool loaded() const { return _loaded; } - const Common::Path &scriptPath() const { return _scriptPath; } + const Common::String &scriptPath() const { return _scriptPath; } protected: bool _loaded; private: - Common::Path _scriptPath; + Common::String _scriptPath; TeLuaContext _luaContext; TeLuaScript _luaScript; diff --git a/engines/tetraedge/te/te_lua_gui_lua_callbacks.cpp b/engines/tetraedge/te/te_lua_gui_lua_callbacks.cpp index 8bd9152cbd37..dfa0af98a782 100644 --- a/engines/tetraedge/te/te_lua_gui_lua_callbacks.cpp +++ b/engines/tetraedge/te/te_lua_gui_lua_callbacks.cpp @@ -350,7 +350,12 @@ int spriteLayoutBindings(lua_State *L) { } if (imgPath.substr(0, 2) == "./") { imgPath = imgPath.substr(0, 2); - imgFullPath = gui->scriptPath().getParent().join(imgPath); + // NOTE: This is bad.. the scriptPath is a system-local path so the + // separator may not be '/', we can't just make a Path from it like + // this. Fortunately it seems this is never actually used? No sprites + // use './' in their data. + warning("Taking non-portable code path to load image in spriteLayoutBindings"); + imgFullPath = Common::Path(gui->scriptPath()).getParent().join(imgPath); } else { imgFullPath = imgPath; } @@ -384,8 +389,8 @@ int spriteLayoutBindings(lua_State *L) { lua_settop(L, -2); } - if (!imgFullPath.empty()) {} - layout->load(imgFullPath); + if (!imgFullPath.empty()) + layout->load(imgFullPath.toString()); lua_pushnil(L); while (lua_next(L, -2) != 0) { diff --git a/engines/tetraedge/te/te_lua_script.cpp b/engines/tetraedge/te/te_lua_script.cpp index c2568451de30..28a08c815fd1 100644 --- a/engines/tetraedge/te/te_lua_script.cpp +++ b/engines/tetraedge/te/te_lua_script.cpp @@ -37,11 +37,11 @@ void TeLuaScript::attachToContext(TeLuaContext *context) { void TeLuaScript::execute() { if (_luaContext) { - //debug("TeLuaScript::execute %s", _scriptPath.toString().c_str()); + //debug("TeLuaScript::execute %s", _scriptNode.getPath().c_str()); lua_State *state = _luaContext->luaState(); if (state) { TeLuaThread *thread = TeLuaThread::create(_luaContext); - thread->executeFile(_scriptPath); + thread->executeFile(_scriptNode); thread->release(); _started = true; } @@ -50,7 +50,7 @@ void TeLuaScript::execute() { void TeLuaScript::execute(const Common::String &fname) { if (_luaContext) { - //debug("TeLuaScript::execute %s %s", _scriptPath.toString().c_str(), fname.c_str()); + //debug("TeLuaScript::execute %s %s", _scriptNode.getPath().c_str(), fname.c_str()); TeLuaThread *thread = TeLuaThread::create(_luaContext); thread->execute(fname); thread->release(); @@ -59,7 +59,7 @@ void TeLuaScript::execute(const Common::String &fname) { void TeLuaScript::execute(const Common::String &fname, const TeVariant &p1) { if (_luaContext) { - //debug("TeLuaScript::execute %s %s(%s)", _scriptPath.toString().c_str(), fname.c_str(), p1.toString().c_str()); + //debug("TeLuaScript::execute %s %s(%s)", _scriptNode.getPath().c_str(), fname.c_str(), p1.toString().c_str()); TeLuaThread *thread = TeLuaThread::create(_luaContext); thread->execute(fname, p1); thread->release(); @@ -82,13 +82,13 @@ void TeLuaScript::execute(const Common::String &fname, const TeVariant &p1, cons } } -void TeLuaScript::load(const Common::Path &path) { +void TeLuaScript::load(const Common::FSNode &node) { _started = false; - _scriptPath = path; + _scriptNode = node; } void TeLuaScript::unload() { - _scriptPath.set(""); + _scriptNode = Common::FSNode(); _started = false; } diff --git a/engines/tetraedge/te/te_lua_script.h b/engines/tetraedge/te/te_lua_script.h index 450d3c5d6fdb..e7641796e609 100644 --- a/engines/tetraedge/te/te_lua_script.h +++ b/engines/tetraedge/te/te_lua_script.h @@ -42,13 +42,13 @@ class TeLuaScript { void execute(const Common::String &fname, const TeVariant &p1, const TeVariant &p2); void execute(const Common::String &fname, const TeVariant &p1, const TeVariant &p2, const TeVariant &p3); - void load(const Common::Path &path); + void load(const Common::FSNode &node); void unload(); private: TeLuaContext *_luaContext; - Common::Path _scriptPath; + Common::FSNode _scriptNode; bool _started; }; diff --git a/engines/tetraedge/te/te_lua_thread.cpp b/engines/tetraedge/te/te_lua_thread.cpp index 36b58928e4f7..45bc41a5861d 100644 --- a/engines/tetraedge/te/te_lua_thread.cpp +++ b/engines/tetraedge/te/te_lua_thread.cpp @@ -131,10 +131,10 @@ void TeLuaThread::execute(const Common::String &fname, const TeVariant &p1, cons } } -void TeLuaThread::executeFile(const Common::Path &path) { +void TeLuaThread::executeFile(const Common::FSNode &node) { Common::File scriptFile; - if (!scriptFile.open(path)) { - warning("TeLuaThread::executeFile: File %s can't be opened", path.toString().c_str()); + if (!scriptFile.open(node)) { + warning("TeLuaThread::executeFile: File %s can't be opened", node.getName().c_str()); return; } @@ -148,7 +148,7 @@ void TeLuaThread::executeFile(const Common::Path &path) { if (fixline) fixline[2] = '\t'; - _lastResumeResult = luaL_loadbuffer(_luaThread, buf, fileLen, path.toString().c_str()); + _lastResumeResult = luaL_loadbuffer(_luaThread, buf, fileLen, node.getPath().c_str()); if (_lastResumeResult) { const char *msg = lua_tostring(_luaThread, -1); warning("TeLuaThread::executeFile: %s", msg); diff --git a/engines/tetraedge/te/te_lua_thread.h b/engines/tetraedge/te/te_lua_thread.h index e5e4c5cf6480..1982e1fee679 100644 --- a/engines/tetraedge/te/te_lua_thread.h +++ b/engines/tetraedge/te/te_lua_thread.h @@ -24,7 +24,7 @@ #include "common/array.h" #include "common/str.h" -#include "common/path.h" +#include "common/fs.h" struct lua_State; @@ -46,7 +46,7 @@ class TeLuaThread { void execute(const Common::String &str, const TeVariant &p1, const TeVariant &p2); void execute(const Common::String &str, const TeVariant &p1, const TeVariant &p2, const TeVariant &p3); - void executeFile(const Common::Path &path); + void executeFile(const Common::FSNode &node); void pushValue(const TeVariant &val); void release(); diff --git a/engines/tetraedge/te/te_material.cpp b/engines/tetraedge/te/te_material.cpp index 8a6a27e72073..e5c45ad7dbc3 100644 --- a/engines/tetraedge/te/te_material.cpp +++ b/engines/tetraedge/te/te_material.cpp @@ -23,6 +23,7 @@ #include "tetraedge/tetraedge.h" +#include "tetraedge/te/te_core.h" #include "tetraedge/te/te_light.h" #include "tetraedge/te/te_material.h" #include "tetraedge/te/te_model.h" @@ -59,7 +60,7 @@ Common::String TeMaterial::dump() const { _specularColor.dump().c_str(), _emissionColor.dump().c_str(), (int)_mode, - _texture ? _texture->getAccessName().toString().c_str() : "None", + _texture ? _texture->getAccessName().c_str() : "None", _shininess, _enableLights ? "on" : "off"); } @@ -88,15 +89,19 @@ TeMaterial &TeMaterial::operator=(const TeMaterial &other) { return *this; } -/*static*/ void TeMaterial::deserialize(Common::SeekableReadStream &stream, TeMaterial &material, const Common::Path &texPath) { - Common::String nameStr = Te3DObject2::deserializeString(stream); +/*static*/ +void TeMaterial::deserialize(Common::SeekableReadStream &stream, TeMaterial &material, const Common::String &texPath) { + const Common::String nameStr = Te3DObject2::deserializeString(stream); TeModel::loadAlign(stream); material._mode = static_cast(stream.readUint32LE()); if (nameStr.size()) { - Common::Path fullTexPath = texPath.join(nameStr); - material._texture = Te3DTexture::load2(fullTexPath, 0x500); + TeCore *core = g_engine->getCore(); + Common::FSNode texNode = core->findFile(Common::Path(texPath).join(nameStr)); + material._texture = Te3DTexture::load2(texNode, 0x500); + if (!material._texture) + warning("failed to load texture %s (texpath %s)", nameStr.c_str(), texPath.c_str()); } material._ambientColor.deserialize(stream); @@ -114,7 +119,7 @@ TeMaterial &TeMaterial::operator=(const TeMaterial &other) { Te3DTexture *tex = material._texture.get(); Common::String texName; if (tex) { - texName = tex->getAccessName().toString(); + texName = tex->getAccessName(); // "Remove extension" twice for some reason.. size_t offset = texName.rfind('.'); if (offset != Common::String::npos) { diff --git a/engines/tetraedge/te/te_material.h b/engines/tetraedge/te/te_material.h index 1e8fab6b3659..86648a08ff0a 100644 --- a/engines/tetraedge/te/te_material.h +++ b/engines/tetraedge/te/te_material.h @@ -45,7 +45,7 @@ class TeMaterial { // Note: apply() function from original moved to TeRenderer to remove OGL specific code from here void defaultValues(); - static void deserialize(Common::SeekableReadStream &stream, TeMaterial &material, const Common::Path &path); + static void deserialize(Common::SeekableReadStream &stream, TeMaterial &material, const Common::String &path); static void serialize(Common::SeekableWriteStream &stream, TeMaterial &material); bool operator==(const TeMaterial &other) const; diff --git a/engines/tetraedge/te/te_model.h b/engines/tetraedge/te/te_model.h index 5448003b9eca..3e7e66d8d8a9 100644 --- a/engines/tetraedge/te/te_model.h +++ b/engines/tetraedge/te/te_model.h @@ -133,13 +133,13 @@ class TeModel : public Te3DObject2, public TeResource { TeIntrusivePtr tiledTexture() { return _tiledTexture; } void setEnableLights(bool val) { _enableLights = val; } - void setTexturePath(const Common::Path &path) { _texturePath = path; } + void setTexturePath(const Common::String &path) { _texturePath = path; } protected: TeMatrix4x4 lerpElementsMatrix(uint weightNum, const Common::Array &matricies); void optimize(); - Common::Path _texturePath; + Common::String _texturePath; TeIntrusivePtr _tiledTexture; bool _enableLights; diff --git a/engines/tetraedge/te/te_model_animation.cpp b/engines/tetraedge/te/te_model_animation.cpp index a56b369f63fa..d5cac67fd04f 100644 --- a/engines/tetraedge/te/te_model_animation.cpp +++ b/engines/tetraedge/te/te_model_animation.cpp @@ -181,9 +181,9 @@ int TeModelAnimation::lastFrame() const { } bool TeModelAnimation::load(const Common::Path &path) { - Common::Path foundPath = g_engine->getCore()->findFile(path); + Common::FSNode foundFile = g_engine->getCore()->findFile(path); Common::File modelFile; - if (!modelFile.open(foundPath)) { + if (!modelFile.open(foundFile)) { warning("[TeModel::load] Can't open file : %s.", path.toString().c_str()); return false; } diff --git a/engines/tetraedge/te/te_music.cpp b/engines/tetraedge/te/te_music.cpp index 59d93cce7802..9dfcc9a9bc31 100644 --- a/engines/tetraedge/te/te_music.cpp +++ b/engines/tetraedge/te/te_music.cpp @@ -60,11 +60,11 @@ void TeMusic::pause() { bool TeMusic::play() { if (isPlaying()) return true; - if (_actualPath.empty() || !Common::File::exists(_actualPath)) + if (!_fileNode.exists()) return false; Common::File *streamfile = new Common::File(); - if (!streamfile->open(_actualPath)) { + if (!streamfile->open(_fileNode)) { delete streamfile; return false; } @@ -82,7 +82,7 @@ bool TeMusic::play() { soundType = Audio::Mixer::kMusicSoundType; } - //debug("playing %s on channel %s at vol %d", _actualPath.toString().c_str(), _channelName.c_str(), vol); + //debug("playing %s on channel %s at vol %d", _fileNode.getPath().c_str(), _channelName.c_str(), vol); mixer->playStream(soundType, &_sndHandle, stream, -1, vol); _sndHandleValid = true; _isPaused = false; @@ -190,10 +190,8 @@ void TeMusic::setFilePath(const Common::String &name) { setAccessName(name); _rawPath = name; TeCore *core = g_engine->getCore(); - const Common::Path namePath(name); // Note: original search logic here abstracted away in our version.. - Common::Path modPath = core->findFile(namePath); - _actualPath = modPath; + _fileNode = core->findFile(name); } void TeMusic::update() { diff --git a/engines/tetraedge/te/te_music.h b/engines/tetraedge/te/te_music.h index c05793f0f983..691dbd3cd81f 100644 --- a/engines/tetraedge/te/te_music.h +++ b/engines/tetraedge/te/te_music.h @@ -24,7 +24,7 @@ #include "audio/mixer.h" #include "common/mutex.h" -#include "common/path.h" +#include "common/fs.h" #include "common/str.h" #include "tetraedge/te/te_resource.h" @@ -76,7 +76,7 @@ class TeMusic : public TeResource { private: Common::String _rawPath; // Plain name of file requested - Common::Path _actualPath; // actual path after finding it + Common::FSNode _fileNode; // file after finding it Common::String _channelName; bool _repeat; diff --git a/engines/tetraedge/te/te_resource.h b/engines/tetraedge/te/te_resource.h index 3c98ceccf4de..025b99d61653 100644 --- a/engines/tetraedge/te/te_resource.h +++ b/engines/tetraedge/te/te_resource.h @@ -35,16 +35,16 @@ class TeResource : public TeObject, public TeReferencesCounter { void generateAccessName(); - const Common::Path &getAccessName() const { + const Common::String &getAccessName() const { return _accessName; } - void setAccessName(const Common::Path &name) { + void setAccessName(const Common::String &name) { _accessName = name; } private: - Common::Path _accessName; + Common::String _accessName; static uint32 _idCounter; }; diff --git a/engines/tetraedge/te/te_resource_manager.cpp b/engines/tetraedge/te/te_resource_manager.cpp index 4443c63832cf..cf3a3c8f03df 100644 --- a/engines/tetraedge/te/te_resource_manager.cpp +++ b/engines/tetraedge/te/te_resource_manager.cpp @@ -43,10 +43,9 @@ void TeResourceManager::addResource(TeResource *resource) { _resources.insert_at(0, TeIntrusivePtr(resource)); } -bool TeResourceManager::exists(const Common::Path &path) { - Common::String pathstr = path.toString(); +bool TeResourceManager::exists(const Common::String &path) { for (auto &resource : _resources) { - if (resource->getAccessName() == pathstr) + if (resource->getAccessName() == path) return true; } return false; diff --git a/engines/tetraedge/te/te_resource_manager.h b/engines/tetraedge/te/te_resource_manager.h index b1abcd699ff3..fb63789fb60a 100644 --- a/engines/tetraedge/te/te_resource_manager.h +++ b/engines/tetraedge/te/te_resource_manager.h @@ -45,22 +45,22 @@ class TeResourceManager { void addResource(const TeIntrusivePtr &resource); void addResource(TeResource *resource); - bool exists(const Common::Path &path); + bool exists(const Common::String &path); void removeResource(const TeIntrusivePtr &resource); void removeResource(const TeResource *resource); - template TeIntrusivePtr getResourceNoSearch(const Common::Path &path) { + template TeIntrusivePtr getResourceByName(const Common::String &path) { for (TeIntrusivePtr &resource : this->_resources) { if (resource->getAccessName() == path) { return TeIntrusivePtr(dynamic_cast(resource.get())); } } - TeIntrusivePtr retval = new T(); - addResource(retval.get()); - return retval; + debug("getResourceByName: didn't find resource %s", path.c_str()); + return TeIntrusivePtr(); } - template TeIntrusivePtr getResource(Common::Path &path) { + template TeIntrusivePtr getResource(const Common::FSNode &node) { + Common::String path = node.getPath(); for (TeIntrusivePtr &resource : this->_resources) { if (resource->getAccessName() == path) { return TeIntrusivePtr(dynamic_cast(resource.get())); @@ -68,19 +68,19 @@ class TeResourceManager { } TeIntrusivePtr retval; - // Note: original search logic here abstracted away in our version.. - TeCore *core = g_engine->getCore(); - path = core->findFile(path); retval = new T(); if (retval.get()) { - retval->load(path); + if (!node.isReadable()) + warning("getResource: asked to fetch unreadable resource %s", node.getPath().c_str()); + retval->load(node); addResource(retval.get()); } return retval; } - template TeIntrusivePtr getResourceOrMakeInstance(Common::Path &path) { + template TeIntrusivePtr getResourceOrMakeInstance(const Common::FSNode &node) { + Common::String path = node.getPath(); for (TeIntrusivePtr &resource : this->_resources) { if (resource->getAccessName() == path) { return TeIntrusivePtr(dynamic_cast(resource.get())); @@ -88,13 +88,12 @@ class TeResourceManager { } TeIntrusivePtr retval; - // Note: original search logic here abstracted away in our version.. - TeCore *core = g_engine->getCore(); - path = core->findFile(path); retval = T::makeInstance(); if (retval.get()) { - retval->load(path); + if (!node.isReadable()) + warning("getResourceOrMakeInstance: asked to fetch unreadable resource %s", node.getPath().c_str()); + retval->load(node); addResource(retval.get()); } return retval; diff --git a/engines/tetraedge/te/te_scene.h b/engines/tetraedge/te/te_scene.h index 8a5174ae7f84..a7b213e47a2a 100644 --- a/engines/tetraedge/te/te_scene.h +++ b/engines/tetraedge/te/te_scene.h @@ -47,7 +47,7 @@ class TeScene { Common::String currentCameraName() const; virtual void draw(); - virtual bool load(const Common::Path &path) { return false; }; + virtual bool load(const Common::FSNode &node) { return false; }; void removeModel(const Common::String &mname); void setCurrentCamera(const Common::String &cname); diff --git a/engines/tetraedge/te/te_scummvm_codec.cpp b/engines/tetraedge/te/te_scummvm_codec.cpp index a89465fdf451..fe1a0121b248 100644 --- a/engines/tetraedge/te/te_scummvm_codec.cpp +++ b/engines/tetraedge/te/te_scummvm_codec.cpp @@ -37,10 +37,10 @@ TeScummvmCodec::~TeScummvmCodec() { } } -bool TeScummvmCodec::load(const Common::Path &path) { +bool TeScummvmCodec::load(const Common::FSNode &node) { Common::File file; - if (file.open(path) && load(static_cast(file))) { - _path = path; + if (file.open(node) && load(static_cast(file))) { + _loadedPath = node.getPath(); return true; } return false; @@ -66,8 +66,8 @@ bool TeScummvmCodec::update(uint i, TeImage &imgout) { if (!_loadedSurface) return false; - if (!_path.empty()) - imgout.setAccessName(_path); + if (!_loadedPath.empty()) + imgout.setAccessName(_loadedPath); if (imgout.w == _loadedSurface->w && imgout.h == _loadedSurface->h && imgout.format == _loadedSurface->format) { imgout.copyFrom(*_loadedSurface); diff --git a/engines/tetraedge/te/te_scummvm_codec.h b/engines/tetraedge/te/te_scummvm_codec.h index a4ec0541dc93..72112febf5ef 100644 --- a/engines/tetraedge/te/te_scummvm_codec.h +++ b/engines/tetraedge/te/te_scummvm_codec.h @@ -32,7 +32,7 @@ class TeScummvmCodec : public TeICodec { TeScummvmCodec(); virtual ~TeScummvmCodec(); - virtual bool load(const Common::Path &path) override; + virtual bool load(const Common::FSNode &node) override; virtual bool load(Common::SeekableReadStream &stream) = 0; virtual uint width() override; virtual uint height() override; @@ -55,7 +55,7 @@ class TeScummvmCodec : public TeICodec { protected: Graphics::Surface *_loadedSurface; - Common::Path _path; + Common::String _loadedPath; }; diff --git a/engines/tetraedge/te/te_sound_manager.cpp b/engines/tetraedge/te/te_sound_manager.cpp index e10ce8d495a7..3ac1b616b8bb 100644 --- a/engines/tetraedge/te/te_sound_manager.cpp +++ b/engines/tetraedge/te/te_sound_manager.cpp @@ -38,11 +38,11 @@ TeSoundManager::TeSoundManager() { void TeSoundManager::playFreeSound(const Common::Path &path, float vol, const Common::String &channel) { TeCore *core = g_engine->getCore(); - Common::Path modPath = core->findFile(path); + Common::FSNode sndNode = core->findFile(path); Common::File *streamfile = new Common::File(); - if (!streamfile->open(modPath)) { - warning("TeSoundManager::playFreeSound: couldn't open %s", path.toString().c_str()); + if (!sndNode.isReadable() || !streamfile->open(sndNode)) { + warning("TeSoundManager::playFreeSound: couldn't open %s", sndNode.getPath().c_str()); delete streamfile; return; } diff --git a/engines/tetraedge/te/te_sprite_layout.cpp b/engines/tetraedge/te/te_sprite_layout.cpp index 42a4d4b7b812..c23d4f45be68 100644 --- a/engines/tetraedge/te/te_sprite_layout.cpp +++ b/engines/tetraedge/te/te_sprite_layout.cpp @@ -20,6 +20,7 @@ */ #include "tetraedge/tetraedge.h" +#include "tetraedge/te/te_core.h" #include "tetraedge/te/te_matrix4x4.h" #include "tetraedge/te/te_renderer.h" #include "tetraedge/te/te_sprite_layout.h" @@ -72,16 +73,31 @@ bool TeSpriteLayout::onParentWorldColorChanged() { return false; } -bool TeSpriteLayout::load(const Common::Path &path) { +bool TeSpriteLayout::load(const Common::String &path) { if (path.empty()) { _tiledSurfacePtr = new TeTiledSurface(); return true; } + TeCore *core = g_engine->getCore(); + Common::FSNode node = core->findFile(path); + if (load(node)) { + _tiledSurfacePtr->setLoadedPath(path); + return true; + } + return false; +} + +bool TeSpriteLayout::load(const Common::FSNode &node) { + if (!node.exists()) { + _tiledSurfacePtr = new TeTiledSurface(); + return true; + } + stop(); unload(); - if (_tiledSurfacePtr->load(path)) { + if (_tiledSurfacePtr->load(node)) { const TeVector2s32 texSize = _tiledSurfacePtr->tiledTexture()->totalSize(); if (texSize._y <= 0) { setRatio(1.0); @@ -93,7 +109,7 @@ bool TeSpriteLayout::load(const Common::Path &path) { } updateMesh(); } else { - debug("Failed to load TeSpriteLayout %s", path.toString().c_str()); + debug("Failed to load TeSpriteLayout %s", node.getPath().c_str()); } return true; } @@ -115,7 +131,7 @@ bool TeSpriteLayout::load(TeIntrusivePtr &texture) { updateMesh(); return true; } else { - debug("Failed to load TeSpriteLayout from texture %s", texture->getAccessName().toString().c_str()); + debug("Failed to load TeSpriteLayout from texture %s", texture->getAccessName().c_str()); } return false; } @@ -137,7 +153,7 @@ bool TeSpriteLayout::load(TeImage &img) { updateMesh(); return true; } else { - debug("Failed to load TeSpriteLayout from texture %s", img.getAccessName().toString().c_str()); + debug("Failed to load TeSpriteLayout from texture %s", img.getAccessName().c_str()); } return false; } diff --git a/engines/tetraedge/te/te_sprite_layout.h b/engines/tetraedge/te/te_sprite_layout.h index e2621cb27bb9..bc4e9f7f3387 100644 --- a/engines/tetraedge/te/te_sprite_layout.h +++ b/engines/tetraedge/te/te_sprite_layout.h @@ -37,7 +37,8 @@ class TeSpriteLayout : public TeLayout { virtual bool onParentWorldColorChanged() override; - bool load(const Common::Path &path); + bool load(const Common::String &path); + bool load(const Common::FSNode &node); bool load(TeImage &img); bool load(TeIntrusivePtr &texture); diff --git a/engines/tetraedge/te/te_text_layout.cpp b/engines/tetraedge/te/te_text_layout.cpp index 2b55b0e4b8bc..981db3c83d46 100644 --- a/engines/tetraedge/te/te_text_layout.cpp +++ b/engines/tetraedge/te/te_text_layout.cpp @@ -118,8 +118,8 @@ void TeTextLayout::setText(const Common::String &val) { if (parser.fontFile().size()) { Common::Path fontPath(parser.fontFile()); - fontPath = g_engine->getCore()->findFile(fontPath); - TeIntrusivePtr font = g_engine->getResourceManager()->getResource(fontPath); + Common::FSNode fontNode = g_engine->getCore()->findFile(fontPath); + TeIntrusivePtr font = g_engine->getResourceManager()->getResource(fontNode); //font->load(fontPath); // lazy load this later. _base.setFont(0, font); } diff --git a/engines/tetraedge/te/te_theora.cpp b/engines/tetraedge/te/te_theora.cpp index d6bd959d7071..3cee78a3f486 100644 --- a/engines/tetraedge/te/te_theora.cpp +++ b/engines/tetraedge/te/te_theora.cpp @@ -38,9 +38,9 @@ bool TeTheora::matchExtension(const Common::String &extn) { return extn == "ogv"; } -bool TeTheora::load(const Common::Path &path) { - _path = path; - return _decoder->loadFile(path); +bool TeTheora::load(const Common::FSNode &node) { + _loadedNode = node; + return _decoder->loadStream(node.createReadStream()); } uint TeTheora::width() { @@ -98,10 +98,10 @@ float TeTheora::frameRate() { } bool TeTheora::update(uint i, TeImage &imgout) { - if (_decoder->getCurFrame() > (int)i && !_path.empty()) { + if (_decoder->getCurFrame() > (int)i && _loadedNode.isReadable()) { // rewind.. no good way to do that, but it should // only happen on loop. - load(_path); + load(_loadedNode); } const Graphics::Surface *frame = nullptr; @@ -114,9 +114,9 @@ bool TeTheora::update(uint i, TeImage &imgout) { //debug("TeTheora: %s %ld", _path.toString().c_str(), i); imgout.copyFrom(*frame); return true; - } else if (_hitEnd && !_path.empty()) { + } else if (_hitEnd && _loadedNode.isReadable()) { // Loop to the start. - load(_path); + load(_loadedNode); frame = _decoder->decodeNextFrame(); if (frame) { imgout.copyFrom(*frame); diff --git a/engines/tetraedge/te/te_theora.h b/engines/tetraedge/te/te_theora.h index d59dd60d8fcd..9715bc1ea23b 100644 --- a/engines/tetraedge/te/te_theora.h +++ b/engines/tetraedge/te/te_theora.h @@ -36,7 +36,7 @@ class TeTheora : public TeICodec { TeTheora(); virtual ~TeTheora(); - virtual bool load(const Common::Path &path) override; + virtual bool load(const Common::FSNode &node) override; virtual uint width() override; virtual uint height() override; virtual int nbFrames() override; @@ -61,7 +61,7 @@ class TeTheora : public TeICodec { private: Video::TheoraDecoder *_decoder; - Common::Path _path; + Common::FSNode _loadedNode; bool _hitEnd; }; diff --git a/engines/tetraedge/te/te_tiled_surface.cpp b/engines/tetraedge/te/te_tiled_surface.cpp index 9d8b66b3be2c..c865f9763ea8 100644 --- a/engines/tetraedge/te/te_tiled_surface.cpp +++ b/engines/tetraedge/te/te_tiled_surface.cpp @@ -60,35 +60,33 @@ byte TeTiledSurface::isLoaded() { return _tiledTexture && _tiledTexture->isLoaded(); } -bool TeTiledSurface::load(const Common::Path &path) { +bool TeTiledSurface::load(const Common::FSNode &node) { unload(); TeResourceManager *resmgr = g_engine->getResourceManager(); - _path = path; + _loadedPath = node.getPath(); TeIntrusivePtr texture; - if (resmgr->exists(path.append(".tt"))) { - texture = resmgr->getResourceNoSearch(path.append(".tt")); + if (resmgr->exists(_loadedPath + ".tt")) { + texture = resmgr->getResourceByName(_loadedPath + ".tt"); // we don't own this one.. } if (!texture) { TeCore *core = g_engine->getCore(); - - Common::Path foundPath = core->findFile(path); - _codec = core->createVideoCodec(foundPath); + _codec = core->createVideoCodec(_loadedPath); if (!_codec) return false; texture = new TeTiledTexture(); - if (_codec->load(foundPath)) { - texture->setAccessName(path.append(".tt")); + if (_codec->load(node)) { + texture->setAccessName(_loadedPath + ".tt"); resmgr->addResource(texture.get()); _imgFormat = _codec->imageFormat(); if (_imgFormat == TeImage::INVALID) { - warning("TeTiledSurface::load: Wrong image format on file %s", path.toString().c_str()); + warning("TeTiledSurface::load: Wrong image format on file %s", _loadedPath.c_str()); delete _codec; _codec = nullptr; return false; @@ -118,7 +116,7 @@ bool TeTiledSurface::load(const Common::Path &path) { texture->load(img); } } else { - warning("TeTiledSurface::load: failed to load %s", path.toString().c_str()); + warning("TeTiledSurface::load: failed to load %s", _loadedPath.c_str()); delete _codec; _codec = nullptr; } @@ -138,10 +136,10 @@ bool TeTiledSurface::load(const TeIntrusivePtr &texture) { TeResourceManager *resmgr = g_engine->getResourceManager(); TeIntrusivePtr tiledTexture; - const Common::Path ttPath = texture->getAccessName().append(".tt"); + const Common::String ttPath = texture->getAccessName() + ".tt"; if (resmgr->exists(ttPath)) { - tiledTexture = resmgr->getResourceNoSearch(ttPath); + tiledTexture = resmgr->getResourceByName(ttPath); } if (!tiledTexture) { @@ -160,7 +158,7 @@ bool TeTiledSurface::onFrameAnimCurrentFrameChanged() { return false; if (_imgFormat == TeImage::INVALID) { - warning("TeTiledSurface::load: Wrong image format on file %s", _path.toString().c_str()); + warning("TeTiledSurface::load: Wrong image format on file %s", _loadedPath.c_str()); return false; } @@ -215,7 +213,7 @@ void TeTiledSurface::setTiledTexture(const TeIntrusivePtr &textu for (uint i = 0; i < texture->numberOfColumns() * texture->numberOfRow(); i++) _meshes.push_back(Common::SharedPtr(TeMesh::makeInstance())); - setAccessName(texture->getAccessName().append(".surface")); + setAccessName(texture->getAccessName() + ".surface"); updateSurface(); } else { _meshes.clear(); diff --git a/engines/tetraedge/te/te_tiled_surface.h b/engines/tetraedge/te/te_tiled_surface.h index d9c9d14e9e7c..2cb3a79e7d86 100644 --- a/engines/tetraedge/te/te_tiled_surface.h +++ b/engines/tetraedge/te/te_tiled_surface.h @@ -45,7 +45,7 @@ class TeTiledSurface : public TeModel { void draw() override; virtual void entry() {}; byte isLoaded(); - bool load(const Common::Path &path); + bool load(const Common::FSNode &node); bool load(const TeImage &image); bool load(const TeIntrusivePtr &texture); @@ -83,7 +83,8 @@ class TeTiledSurface : public TeModel { void updateSurface(); void updateVideoProperties(); - const Common::Path &path() const { return _path; } + const Common::String &loadedPath() const { return _loadedPath; } + void setLoadedPath(const Common::String &p) { _loadedPath = p; } TeFrameAnim _frameAnim; @@ -105,7 +106,7 @@ class TeTiledSurface : public TeModel { TeImage::Format _imgFormat; - Common::Path _path; + Common::String _loadedPath; }; diff --git a/engines/tetraedge/te/te_tiled_texture.cpp b/engines/tetraedge/te/te_tiled_texture.cpp index b70c9ffb79e0..2a1c4bc02b20 100644 --- a/engines/tetraedge/te/te_tiled_texture.cpp +++ b/engines/tetraedge/te/te_tiled_texture.cpp @@ -41,15 +41,16 @@ bool TeTiledTexture::isLoaded() { } -bool TeTiledTexture::load(const Common::Path &path) { +bool TeTiledTexture::load(const Common::String &path) { release(); TeIntrusivePtr img; TeResourceManager *resmgr = g_engine->getResourceManager(); if (resmgr->exists(path)) { - img = resmgr->getResourceNoSearch(path); + img = resmgr->getResourceByName(path); } else { img = new TeImage(); - if (!img->load(path)) + TeCore *core = g_engine->getCore(); + if (!img->load(core->findFile(path))) return false; } load(*img); @@ -86,7 +87,7 @@ bool TeTiledTexture::load(const TeImage &img) { TeImage *optimizedimg = optimisedTileImage(imgArray, newTileSize, Common::SharedPtr(), img.teFormat()); img.copy(*optimizedimg, TeVector2s32(0, 0), TeVector2s32(_tileSize._x * row, _tileSize._y * col), newTileSize); //optimizedimg->_flipY = img._flipY; - Common::String accessName = Common::String::format("%s.Tile%dx%d", img.getAccessName().toString().c_str(), row, col); + Common::String accessName = Common::String::format("%s.Tile%dx%d", img.getAccessName().c_str(), row, col); optimizedimg->setAccessName(accessName); tileimage = optimizedimg; } else { @@ -115,7 +116,7 @@ bool TeTiledTexture::load(const TeImage &img) { _somethingSize._x = _somethingSize._x / cols; if (rows) _somethingSize._y = _somethingSize._y / rows; - setAccessName(img.getAccessName().append(".tt")); + setAccessName(img.getAccessName() + ".tt"); return true; } @@ -129,7 +130,7 @@ bool TeTiledTexture::load(const TeIntrusivePtr &texture) { tileData->_texture = texture; tileData->_vec2 = TeVector3f32(1, 1, 0); tileData->_vec1 = TeVector3f32(0, 0, 0); - setAccessName(texture->getAccessName().append(".tt")); + setAccessName(texture->getAccessName() + ".tt"); return true; } diff --git a/engines/tetraedge/te/te_tiled_texture.h b/engines/tetraedge/te/te_tiled_texture.h index 8a0b4e81b8fc..203030f1c320 100644 --- a/engines/tetraedge/te/te_tiled_texture.h +++ b/engines/tetraedge/te/te_tiled_texture.h @@ -46,7 +46,7 @@ class TeTiledTexture : public TeResource { uint imageFormat(); bool isLoaded(); - bool load(const Common::Path &path); + bool load(const Common::String &path); bool load(const TeImage &image); bool load(const TeIntrusivePtr &texture); uint32 numberOfColumns() const; From c6c91025c74d259e3d7d7c10f68e0ecca00efebc Mon Sep 17 00:00:00 2001 From: Matthew Duggan Date: Sun, 5 Feb 2023 07:27:53 +0900 Subject: [PATCH 024/412] TETRAEDGE: Note direction of logic in showMarkers --- engines/tetraedge/game/game.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/engines/tetraedge/game/game.cpp b/engines/tetraedge/game/game.cpp index 8fb0cac712f9..dce51c5f0364 100644 --- a/engines/tetraedge/game/game.cpp +++ b/engines/tetraedge/game/game.cpp @@ -1487,6 +1487,8 @@ void Game::setCurrentObjectSprite(const Common::String &spritePath) { } } +// Note: The naming of this function is bad, but follows the original.. +// we really set the visibility to the *opposite* of the parameter. bool Game::showMarkers(bool val) { if (!_forGui.loaded()) return false; From 31862a6847bbb894dbe31f1178b7fa97cd9ce490 Mon Sep 17 00:00:00 2001 From: Matthew Duggan Date: Sun, 5 Feb 2023 07:31:21 +0900 Subject: [PATCH 025/412] TETRAEDGE: Limit head rotation in both directions As amusing as it was for Kate to have such a flexible neck.. --- engines/tetraedge/game/in_game_scene.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engines/tetraedge/game/in_game_scene.cpp b/engines/tetraedge/game/in_game_scene.cpp index 9d5c2509d124..f86627a30697 100644 --- a/engines/tetraedge/game/in_game_scene.cpp +++ b/engines/tetraedge/game/in_game_scene.cpp @@ -1106,7 +1106,7 @@ void InGameScene::update() { if (aroundAnchorZone(zone)) { TeVector2f32 headRot(getHeadHorizontalRotation(_character, zone->_loc), getHeadVerticalRotation(_character, zone->_loc)); - if (headRot.getX() * 180.0 / M_PI > 90.0 || headRot.getY() * 180.0 / M_PI > 45.0) { + if (fabs(headRot.getX() * 180.0 / M_PI) > 90.0 || fabs(headRot.getY() * 180.0 / M_PI) > 45.0) { _character->setHasAnchor(false); _character->setLastHeadRotation(_character->headRotation()); } else { From 49aa54354091dc4b283f4cfa4cb9eac42ed1e2ec Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Sat, 4 Feb 2023 15:48:09 -0800 Subject: [PATCH 026/412] MM: MM1: Fix highlighting next round --- devtools/create_mm/files/mm1/strings_en.yml | 4 ++-- engines/mm/mm1/gfx/bitmap_font.h | 6 ++++-- engines/mm/mm1/views/combat.cpp | 5 +++++ 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/devtools/create_mm/files/mm1/strings_en.yml b/devtools/create_mm/files/mm1/strings_en.yml index 8763eaecbe8f..7cee838c92d2 100644 --- a/devtools/create_mm/files/mm1/strings_en.yml +++ b/devtools/create_mm/files/mm1/strings_en.yml @@ -348,7 +348,7 @@ dialogs: combat: "combat!" combat: combat: "combat" - round: "round #:" + round: "Round #" delay: "d delay" protect: "p protect" quickref: "q quickref" @@ -1633,4 +1633,4 @@ maps: keeper3: "in a serene voice, the data keeper says,\n""welcome to your inner sanctum\nvarnlings! i am very pleased that you've\nmade it this far. you are to be\ncommended. i've been monitoring your\nprogress."" turning to the strange\nmechanical device, he inserts a flat\nobject into a slot. your party's current\nperformance total=%u" keeper4: """you are not yet worthy for transfer. return after defeating the imposter.""" keeper5: "excellent rating! this is a rare occasion, for only a privileged few are given the opportunity for transfer to\nanother v.a.r.n. (vehicular astropod\nresearch nacelle). return now to the\ninn of sorpigal for rest and celebration\nthen continue on to your new assignment at the gates to another world..."" (+50000 exp for your accomplishment!)\n----------------------------------------\nplease send your performance total to\nnew world computing, inc.\n p. o. box 2068 van nuys, ca 91404" - + diff --git a/engines/mm/mm1/gfx/bitmap_font.h b/engines/mm/mm1/gfx/bitmap_font.h index e345308688ca..3a9904a71e52 100644 --- a/engines/mm/mm1/gfx/bitmap_font.h +++ b/engines/mm/mm1/gfx/bitmap_font.h @@ -32,11 +32,13 @@ namespace Gfx { class BitmapFont : public ::MM::BitmapFont { public: void drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const override { - MM::BitmapFont::drawChar(dst, toupper(chr), x, y, color); + chr = (chr & 0x80) | toupper(chr & 0x7f); + MM::BitmapFont::drawChar(dst, chr, x, y, color); } void drawChar(Graphics::ManagedSurface *dst, uint32 chr, int x, int y, uint32 color) const override { - MM::BitmapFont::drawChar(dst, toupper(chr), x, y, color); + chr = (chr & 0x80) | toupper(chr & 0x7f); + MM::BitmapFont::drawChar(dst, chr, x, y, color); } }; diff --git a/engines/mm/mm1/views/combat.cpp b/engines/mm/mm1/views/combat.cpp index 19c46403da98..40449349130d 100644 --- a/engines/mm/mm1/views/combat.cpp +++ b/engines/mm/mm1/views/combat.cpp @@ -47,6 +47,10 @@ void Combat::setMode(Mode newMode) { // Make a copy of monster spell _monsterSpellLines = getMonsterSpellMessage(); + if (_mode != MONSTER_ADVANCES && _mode != MONSTER_ATTACK && + _mode != MONSTER_SPELL) + _activeMonsterNum = -1; + redraw(); } @@ -98,6 +102,7 @@ bool Combat::msgGame(const GameMessage &msg) { void Combat::draw() { switch (_mode) { case NEXT_ROUND: + writeMonsters(); resetBottom(); highlightNextRound(); delaySeconds(1); From b4dabe60dc188bff3a072584b25f9c1d0a1d1fe3 Mon Sep 17 00:00:00 2001 From: Walter Agazzi Date: Sun, 5 Feb 2023 01:10:02 +0100 Subject: [PATCH 027/412] AGS: Add new versions of some commercial games --- engines/ags/detection_tables.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/engines/ags/detection_tables.h b/engines/ags/detection_tables.h index 6ab663fe281c..30669afa0ba4 100644 --- a/engines/ags/detection_tables.h +++ b/engines/ags/detection_tables.h @@ -3563,6 +3563,7 @@ const AGSGameDescription GAME_DESCRIPTIONS[] = { GAME_ENTRY_EN("astroloco", "astroloco1.exe", "06e70a826fde73b3f86f974885d31abe", 42492070), GAME_ENTRY_EN_STEAM("beer", "beer!.exe", "6f201fd7a19869c85f49c7c471d0479a", 5055091), // Windows GAME_ENTRY_EN_STEAM("beer", "Beer!.ags", "6f201fd7a19869c85f49c7c471d0479a", 5042748), // Linux + GAME_ENTRY_GOG("beyondowlsgard", "Owlsgard.exe", "0f647ddfd86c3dad2d68055fab21f091", 556521058), // Eng-Deu v1.1 GAME_ENTRY_STEAM("beyondowlsgard", "Owlsgard.exe", "0f647ddfd86c3dad2d68055fab21f091", 556512803), // Eng-Deu GAME_ENTRY_EN_GOG("blackwell1", "blackwell1.exe", "605e124cb7e0b56841c471e2d641c224", 18822697), GAME_ENTRY_EN_GOG("blackwell1", "Blackwell Legacy.exe", "92af7315126c6da1e9e0c641cd9df200", 67316743), // v2.2.1 @@ -3630,6 +3631,7 @@ const AGSGameDescription GAME_DESCRIPTIONS[] = { GAME_ENTRY_EN_GOG("blackwell5", "ac2game.dat", "8acaa20eab5589cdc2fd81ef3d55eff3", 279928291), // Mac v2.3 GAME_ENTRY_PLUGIN_STEAM_EN("blackwell5", "epiphany.exe", "c1cddd6fcdbcd030beda9f10d4e4270a", 281856724, AGSTEAM_WADJETEYE), GAME_ENTRY_PLUGIN_STEAM_EN("blackwell5", "epiphany.exe", "764f20abb335b94ab8ec6a4ef6db01ea", 283020359, AGSTEAM_WADJETEYE), + GAME_ENTRY_PLUGIN_STEAM_EN("blackwell5", "epiphany.exe", "c3f7a995bbea7ce4ba7a2a97995c677e", 283092455, AGSTEAM_WADJETEYE), GAME_ENTRY_EN_STEAM("captaindisaster", "cd-dhamsb-1-0-1.exe", "e2d290f8f21c6a83a9e8c5f3a0425b5e", 150665897), GAME_ENTRY_EN_STEAM("castleagony", "Agony.exe", "387ff720e746ae46e93f463fd58d77a4", 21017019), GAME_ENTRY_EN_STEAM("charnelhousetrilogy", "cht.ags", "55c782c9de5a09157ea6aafac90b9cc8", 339257135), @@ -3729,7 +3731,8 @@ const AGSGameDescription GAME_DESCRIPTIONS[] = { GAME_ENTRY_STEAM("mybigsister", "My Big Sister.exe", "4dc50ca8b5d2c762fe86a528b09973cf", 147257266), // En-Fr-De-Es-Pt GAME_ENTRY_STEAM("mybigsister", "My Big Sister.exe", "4dc50ca8b5d2c762fe86a528b09973cf", 147082912), // rollback GAME_ENTRY_STEAM("mybigsister", "My Big Sister.exe", "4dc50ca8b5d2c762fe86a528b09973cf", 147248623), // rollback - latest - GAME_ENTRY_EN_STEAM("mybigsisterrm", "MBSRemastered.exe", "e08c78e2591f196a2f42e5911062e56e", 156797059), + GAME_ENTRY_EN_STEAM("mybigsisterrm", "MBSRemastered.exe", "e08c78e2591f196a2f42e5911062e56e", 156797059), // rollback 0.1 + GAME_ENTRY_STEAM("mybigsisterrm", "MBSRemastered.exe", "e08c78e2591f196a2f42e5911062e56e", 157043019), // Multilang GAME_ENTRY_STEAM("nellycootalot-hd", "Nelly.exe", "521aecdb5343c8d8f1c1000c4c2fa468", 11069524), // Win En-Fr-De-Es-Pl GAME_ENTRY_STEAM("nellycootalot-hd", "Nelly.exe", "28f22ae60e2f3524665c1d5be60a0bf3", 11069220), GAME_ENTRY_STEAM("nellycootalot-hd", "ac2game.dat", "914d76b051867892f78883a2ff6be6ea", 11060916), // Mac En-Fr-De-Es-Pl @@ -3785,6 +3788,7 @@ const AGSGameDescription GAME_DESCRIPTIONS[] = { GAME_ENTRY_EN_GOG("resonance", "resonance.exe", "6cc23ce7cdf62de776c6b8ddb6b8a7ff", 850642889), // v2.2 GAME_ENTRY_EN_GOG("resonance", "resonance.exe", "6cc23ce7cdf62de776c6b8ddb6b8a7ff", 850643390), // v2.3 GAME_ENTRY_EN_GOG("resonance", "ac2game.dat", "1dd9f78fbd1947fdf66a820928baf8a4", 847433642), // Mac v2.3 + GAME_ENTRY_EN_GOG("resonance", "agsgame.dat", "2e635c22bcbf0ed3d46f1bcde71812d4", 849404957), // Linux GAME_ENTRY_PLUGIN_STEAM_EN("resonance", "resonance.exe", "2e635c22bcbf0ed3d46f1bcde71812d4", 849410915, AGSTEAM_WADJETEYE), GAME_ENTRY_EN_STEAM("richardandalice", "richardandalice.exe", "1023d348f67ba958f78ed62d029565c7", 109164768), GAME_ENTRY_EN_STEAM("richardandalice", "richardandalice.exe", "f47d11397e2059a25b11057ea6cf3409", 108264256), @@ -3820,6 +3824,8 @@ const AGSGameDescription GAME_DESCRIPTIONS[] = { GAME_ENTRY_STEAM("smallsister", "sister.exe", "78dd4ca028ee0156b6a093d6d780aa65", 18534526), // Eng-Tur GAME_ENTRY_EN_STEAM("spaceraven", "Tiny Planet.exe", "c6154d27a773ebf98a9be181a840d146", 29803571), GAME_ENTRY_STEAM("starshipquasar", "starship quasar.ags", "0ea8150e15a4f4d0f3e82c231a4659f2", 10415956), // Multilang + GAME_ENTRY_STEAM("starshipquasar", "starship quasar.ags", "0ea8150e15a4f4d0f3e82c231a4659f2", 10415936), // Multilang + GAME_ENTRY("starshipquasar", "Starship Quasar.exe", "0ea8150e15a4f4d0f3e82c231a4659f2", 10415936), // Multilang itch.io GAME_ENTRY_EN_STEAM("stayingalive", "Staying Alive.exe", "fae163b58c16e194688727d0903684be", 17380838), GAME_ENTRY("strangeland", "Strangeland.exe", "c5978d50a9b7ee1c8a50a731847d8504", 3186614879), GAME_ENTRY("strangeland", "Strangeland.exe", "c5978d50a9b7ee1c8a50a731847d8504", -1), // for 32-bit limited filesystems @@ -6596,6 +6602,7 @@ const AGSGameDescription GAME_DESCRIPTIONS[] = { GAME_ENTRY("questforyrolg", "Quest for Yrolg.exe", "c4f5b7b29be90ba0f8128298afb917de", 9388101), // Multi GAME_ENTRY("questforyrolg", "quest for yrolg.exe", "89df481678b2ddc40ecc9f83caa76b89", 9709051), // v1.8 GAME_ENTRY_STEAM("questforyrolg", "quest for yrolg.ags", "51527ed37f001db741e68b767259c81e", 8214789), + GAME_ENTRY_STEAM("questforyrolg", "quest for yrolg.ags", "51527ed37f001db741e68b767259c81e", 8214777), GAME_ENTRY_EN("quietgame", "shhhh.exe", "618d7dce9631229b4579340b964c6810", 73311624), GAME_ENTRY_EN("quimbyquestanewdope", "QQuest.exe", "615e806856b7730afadf1fea9a756b70", 8801878), GAME_ENTRY_EN("quiteannoying", "Super Annoying League.exe", "615e73fc1874e92d60a1996c2330ea36", 22513046), // Windows From 0edaaf026571172edaacbd5f278c546c26df3f57 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Sat, 4 Feb 2023 20:50:38 -0800 Subject: [PATCH 028/412] MM: MM1: Added enhanced mode automap dialog --- devtools/create_mm/files/mm1/strings_en.yml | 5 ++ engines/mm/mm1/metaengine.cpp | 1 + engines/mm/mm1/views_enh/dialogs.h | 2 + engines/mm/mm1/views_enh/game_commands.cpp | 8 +- engines/mm/mm1/views_enh/map.cpp | 25 +++--- engines/mm/mm1/views_enh/map.h | 4 + engines/mm/mm1/views_enh/map_popup.cpp | 94 +++++++++++++++++++++ engines/mm/mm1/views_enh/map_popup.h | 46 ++++++++++ engines/mm/mm1/views_enh/scroll_popup.cpp | 2 +- engines/mm/mm1/views_enh/text_view.cpp | 13 ++- engines/mm/module.mk | 1 + 11 files changed, 181 insertions(+), 20 deletions(-) create mode 100644 engines/mm/mm1/views_enh/map_popup.cpp create mode 100644 engines/mm/mm1/views_enh/map_popup.h diff --git a/devtools/create_mm/files/mm1/strings_en.yml b/devtools/create_mm/files/mm1/strings_en.yml index 7cee838c92d2..22c98afa0cc1 100644 --- a/devtools/create_mm/files/mm1/strings_en.yml +++ b/devtools/create_mm/files/mm1/strings_en.yml @@ -421,6 +421,11 @@ dialogs: 14: "thrashes at" 99: "shoots at" enhdialogs: + map: + north: "North" + south: "South" + east: "East" + west: "West" character: stats: might: "mgt" diff --git a/engines/mm/mm1/metaengine.cpp b/engines/mm/mm1/metaengine.cpp index afcaece8f9bf..5f085ea2edaf 100644 --- a/engines/mm/mm1/metaengine.cpp +++ b/engines/mm/mm1/metaengine.cpp @@ -75,6 +75,7 @@ static const KeybindingRecord NORMAL_KEYS[] = { { KEYBIND_STRAFE_LEFT, "STRAFE_LEFT", "Strafe Left", "C+LEFT", nullptr }, { KEYBIND_STRAFE_RIGHT, "STRAFE_RIGHT", "Strafe Right", "C+RIGHT", nullptr }, + { KEYBIND_MAP, "MAP", "Show Map", "m", nullptr }, { KEYBIND_MINIMAP, "MINIMAP", "Toggle Minimap", "=", nullptr }, { KEYBIND_ORDER, "ORDER", "Reorder Party", "o", nullptr }, { KEYBIND_PROTECT, "PROTECT", "Protect", "p", nullptr }, diff --git a/engines/mm/mm1/views_enh/dialogs.h b/engines/mm/mm1/views_enh/dialogs.h index 4707d78ab7bb..27802e22e82a 100644 --- a/engines/mm/mm1/views_enh/dialogs.h +++ b/engines/mm/mm1/views_enh/dialogs.h @@ -33,6 +33,7 @@ //#include "mm/mm1/views/char.h" #include "mm/mm1/views_enh/character_info.h" #include "mm/mm1/views_enh/game.h" +#include "mm/mm1/views_enh/map_popup.h" #include "mm/mm1/views_enh/locations/market.h" #include "mm/mm1/views_enh/locations/temple.h" @@ -55,6 +56,7 @@ struct Dialogs { Views::Title _title; // Views::ViewCharacters _viewCharacters; // Views::ViewCharacter _viewCharacter; + ViewsEnh::MapPopup _mapPopup; ViewsEnh::Locations::Market _market; ViewsEnh::Locations::Temple _temple; public: diff --git a/engines/mm/mm1/views_enh/game_commands.cpp b/engines/mm/mm1/views_enh/game_commands.cpp index 95f11bf790e0..f3f32df72281 100644 --- a/engines/mm/mm1/views_enh/game_commands.cpp +++ b/engines/mm/mm1/views_enh/game_commands.cpp @@ -54,9 +54,15 @@ GameCommands::GameCommands(UIElement *owner) : } bool GameCommands::msgAction(const ActionMessage & msg) { - if (msg._action == KEYBIND_MINIMAP) { + switch (msg._action) { + case KEYBIND_MINIMAP: _minimap.toggleMinimap(); return true; + case KEYBIND_MAP: + addView("MapPopup"); + return true; + default: + break; } return false; diff --git a/engines/mm/mm1/views_enh/map.cpp b/engines/mm/mm1/views_enh/map.cpp index 258ba15130f2..c116f25ae029 100644 --- a/engines/mm/mm1/views_enh/map.cpp +++ b/engines/mm/mm1/views_enh/map.cpp @@ -26,11 +26,6 @@ namespace MM { namespace MM1 { namespace ViewsEnh { -#define BORDER_SIZE 1 -#define TILE_W 10 -#define TILE_H 8 - - Map::Map(UIElement *owner) : UIElement("Map", owner) { } @@ -40,12 +35,12 @@ void Map::draw() { Graphics::ManagedSurface s = getSurface(); g_globals->_globalSprites.draw(&s, 15, - Common::Point(BORDER_SIZE, BORDER_SIZE)); + Common::Point(MAP_BORDER_SIZE, MAP_BORDER_SIZE)); - assert((_bounds.width() - BORDER_SIZE * 2) % TILE_W == 0); - assert((_bounds.height() - BORDER_SIZE * 2) % TILE_H == 0); - int totalX = (_bounds.width() - BORDER_SIZE * 2) / TILE_W, - totalY = (_bounds.height() - BORDER_SIZE * 2) / TILE_H; + assert((_bounds.width() - MAP_BORDER_SIZE * 2) % MAP_TILE_W == 0); + assert((_bounds.height() - MAP_BORDER_SIZE * 2) % MAP_TILE_H == 0); + int totalX = (_bounds.width() - MAP_BORDER_SIZE * 2) / MAP_TILE_W, + totalY = (_bounds.height() - MAP_BORDER_SIZE * 2) / MAP_TILE_H; int currentX = maps._mapPos.x; int currentY = maps._mapPos.y; @@ -55,17 +50,17 @@ void Map::draw() { MAP_H - totalY); // Iterate through the cells - for (int yp = BORDER_SIZE, mazeY = yStart + totalY - 1; - mazeY >= yStart; yp += TILE_H, --mazeY) { - for (int xp = BORDER_SIZE, mazeX = xStart; - mazeX < (xStart + totalX); xp += TILE_W, ++mazeX) { + for (int yp = MAP_BORDER_SIZE, mazeY = yStart + totalY - 1; + mazeY >= yStart; yp += MAP_TILE_H, --mazeY) { + for (int xp = MAP_BORDER_SIZE, mazeX = xStart; + mazeX < (xStart + totalX); xp += MAP_TILE_W, ++mazeX) { byte visited = map._visited[mazeY * MAP_W + mazeX]; if (!visited) { g_globals->_tileSprites.draw(&s, 1, Common::Point(xp, yp)); } else { - Common::Rect r(xp, yp, xp + TILE_W, yp + TILE_H); + Common::Rect r(xp, yp, xp + MAP_TILE_W, yp + MAP_TILE_H); byte walls = map._walls[mazeY * MAP_W + mazeX]; int wallsW = walls & 3; int wallsS = (walls >> 2) & 3; diff --git a/engines/mm/mm1/views_enh/map.h b/engines/mm/mm1/views_enh/map.h index e17189c43c77..52065d42d10b 100644 --- a/engines/mm/mm1/views_enh/map.h +++ b/engines/mm/mm1/views_enh/map.h @@ -28,6 +28,10 @@ namespace MM { namespace MM1 { namespace ViewsEnh { +#define MAP_BORDER_SIZE 1 +#define MAP_TILE_W 10 +#define MAP_TILE_H 8 + class Map : public UIElement { public: Map(UIElement *owner); diff --git a/engines/mm/mm1/views_enh/map_popup.cpp b/engines/mm/mm1/views_enh/map_popup.cpp new file mode 100644 index 000000000000..291bd2ba8b02 --- /dev/null +++ b/engines/mm/mm1/views_enh/map_popup.cpp @@ -0,0 +1,94 @@ +/* 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 "mm/mm1/views_enh/map_popup.h" +#include "mm/mm1/maps/maps.h" +#include "mm/mm1/globals.h" + +namespace MM { +namespace MM1 { +namespace ViewsEnh { + +#define ENTIRE_MAP_W (MAP_W * MAP_TILE_W) +#define ENTIRE_MAP_H (MAP_H * MAP_TILE_H) + +MapPopup::MapPopup() : ScrollPopup("MapPopup"), + _map(this) { + // Center 16x16 map area + Common::Rect area( + (320 / 2) - (ENTIRE_MAP_W / 2) - 1, + (200 / 2) - (ENTIRE_MAP_H / 2) - 1, + (320 / 2) + (ENTIRE_MAP_W / 2) + 1, + (200 / 2) + (ENTIRE_MAP_H / 2) + 1 + ); + _map.setBounds(area); + + // Allow room for scroll edges, and line at top & bottom + area.left -= 9; + area.right += 9; + area.top -= 17; + area.bottom += 17; + setBounds(area); +} + +void MapPopup::draw() { + ScrollPopup::draw(); + + // Write the map name + Maps::Map &map = *g_maps->_currentMap; + Common::String mapName = map.getName(); + mapName.setChar(toupper(mapName[0]), 0); + writeString(0, 0, mapName, ALIGN_MIDDLE); + + // Write direction + Common::String dir; + switch (g_maps->_forwardMask) { + case Maps::DIRMASK_N: + dir = STRING["enhdialogs.map.north"]; + break; + case Maps::DIRMASK_S: + dir = STRING["enhdialogs.map.south"]; + break; + case Maps::DIRMASK_E: + dir = STRING["enhdialogs.map.east"]; + break; + case Maps::DIRMASK_W: + dir = STRING["enhdialogs.map.west"]; + break; + default: + break; + } + writeString(0, _innerBounds.height() - 9, dir, ALIGN_MIDDLE); + + // Write position + writeString(2, _innerBounds.height() - 9, + Common::String::format("X = %d", g_maps->_mapPos.x), + ALIGN_LEFT + ); + writeString(0, _innerBounds.height() - 9, + Common::String::format("Y = %d", g_maps->_mapPos.y), + ALIGN_RIGHT + ); +} + +} // namespace Views +} // namespace MM1 +} // namespace MM diff --git a/engines/mm/mm1/views_enh/map_popup.h b/engines/mm/mm1/views_enh/map_popup.h new file mode 100644 index 000000000000..dd215e387573 --- /dev/null +++ b/engines/mm/mm1/views_enh/map_popup.h @@ -0,0 +1,46 @@ +/* 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 . + * + */ + +#ifndef MM1_VIEWS_ENH_MAP_POPUP_H +#define MM1_VIEWS_ENH_MAP_POPUP_H + +#include "mm/mm1/views_enh/scroll_popup.h" +#include "mm/mm1/views_enh/map.h" + +namespace MM { +namespace MM1 { +namespace ViewsEnh { + +class MapPopup : public ScrollPopup { +private: + Map _map; +public: + MapPopup(); + virtual ~MapPopup() {} + + void draw() override; +}; + +} // namespace Views +} // namespace MM1 +} // namespace MM + +#endif diff --git a/engines/mm/mm1/views_enh/scroll_popup.cpp b/engines/mm/mm1/views_enh/scroll_popup.cpp index b33112a4c1ed..64b600f3d214 100644 --- a/engines/mm/mm1/views_enh/scroll_popup.cpp +++ b/engines/mm/mm1/views_enh/scroll_popup.cpp @@ -26,7 +26,7 @@ namespace MM1 { namespace ViewsEnh { ScrollPopup::ScrollPopup(const Common::String &name) : - ScrollText("ScrollPopup") { + ScrollText(name) { } bool ScrollPopup::msgKeypress(const KeypressMessage &msg) { diff --git a/engines/mm/mm1/views_enh/text_view.cpp b/engines/mm/mm1/views_enh/text_view.cpp index 191354435df0..61e2705d91fa 100644 --- a/engines/mm/mm1/views_enh/text_view.cpp +++ b/engines/mm/mm1/views_enh/text_view.cpp @@ -109,13 +109,20 @@ void TextView::writeString(int x, int y, const Common::String &str, if (line != lines.front()) newLine(); - if (align != ALIGN_LEFT && x == 0) { + if (align != ALIGN_LEFT) { int strWidth = getFont()->getStringWidth(line); + if (x == 0) { + if (align == ALIGN_MIDDLE) + x = _innerBounds.width() / 2; + else + x = _innerBounds.width(); + } + if (align == ALIGN_MIDDLE) - _textPos.x = MAX((_innerBounds.width() - strWidth) / 2, 0); + _textPos.x = MAX(x - (strWidth / 2), 0); else - _textPos.x = MAX(_innerBounds.width() - strWidth, 0); + _textPos.x = MAX(x - strWidth, 0); } writeString(line); diff --git a/engines/mm/module.mk b/engines/mm/module.mk index 110fe69181b8..859e9055f72d 100644 --- a/engines/mm/module.mk +++ b/engines/mm/module.mk @@ -118,6 +118,7 @@ MODULE_OBJS := \ mm1/views_enh/game_commands.o \ mm1/views_enh/game_messages.o \ mm1/views_enh/map.o \ + mm1/views_enh/map_popup.o \ mm1/views_enh/scroll_popup.o \ mm1/views_enh/scroll_text.o \ mm1/views_enh/scroll_view.o \ From a91ba40fb18d72f2224c46976f5d5112b5a65e5a Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Sat, 4 Feb 2023 21:19:22 -0800 Subject: [PATCH 029/412] MM: MM1: Remove more deprecated name formatting --- engines/mm/mm1/data/character.cpp | 4 ---- engines/mm/mm1/data/character.h | 5 ----- engines/mm/mm1/game/monster_touch.cpp | 6 +++--- engines/mm/mm1/game/spells_monsters.cpp | 2 +- engines/mm/mm1/views/search.cpp | 4 ++-- 5 files changed, 6 insertions(+), 15 deletions(-) diff --git a/engines/mm/mm1/data/character.cpp b/engines/mm/mm1/data/character.cpp index 09c2e2023657..7888d90a42e7 100644 --- a/engines/mm/mm1/data/character.cpp +++ b/engines/mm/mm1/data/character.cpp @@ -593,10 +593,6 @@ bool Character::hasItem(byte itemId) const { _equipped.indexOf(itemId) != -1; } -Common::String Character::getDisplayName() const { - return Common::String::format("|%s|", _name); -} - #define PERF16(x) ((x & 0xff) + ((x >> 8) & 0xff)) #define PERF32(x) ((x & 0xff) + ((x >> 8) & 0xff) + \ ((x >> 16) & 0xff) + ((x >> 24) & 0xff)) diff --git a/engines/mm/mm1/data/character.h b/engines/mm/mm1/data/character.h index 7e3abee23b9e..322fcf04512e 100644 --- a/engines/mm/mm1/data/character.h +++ b/engines/mm/mm1/data/character.h @@ -526,11 +526,6 @@ struct Character : public PrimaryAttributes { */ bool hasItem(byte itemId) const; - /** - * Return a display version of the character's name - */ - Common::String getDisplayName() const; - /** * Gets the numeric value of every property a character * has and totals it up to give a stupid 'performance' diff --git a/engines/mm/mm1/game/monster_touch.cpp b/engines/mm/mm1/game/monster_touch.cpp index 6d8ad6d28000..9e9088bf7ae9 100644 --- a/engines/mm/mm1/game/monster_touch.cpp +++ b/engines/mm/mm1/game/monster_touch.cpp @@ -228,7 +228,7 @@ bool MonsterTouch::action14(Common::String &line) { if (canPerform(3) && isCharAffected()) { setCondition(BAD_CONDITION | STONE); line = Common::String::format("%s %s", - c.getDisplayName().c_str(), + c._name, STRING["monster_actions.turned_to_stone"].c_str() ); return true; @@ -280,7 +280,7 @@ bool MonsterTouch::action17(Common::String &line) { if (canPerform(3) && isCharAffected()) { setCondition(BAD_CONDITION | DEAD); line = Common::String::format("%s %s", - c.getDisplayName().c_str(), + c._name, STRING["monster_actions.is_killed"].c_str() ); return true; @@ -368,7 +368,7 @@ bool MonsterTouch::action23(Common::String &line) { setCondition(ERADICATED); line = Common::String::format("%s %s", - c.getDisplayName().c_str(), + c._name, STRING["monster_actions.is_eradicated"].c_str() ); diff --git a/engines/mm/mm1/game/spells_monsters.cpp b/engines/mm/mm1/game/spells_monsters.cpp index 633303269882..c96b414d2d42 100644 --- a/engines/mm/mm1/game/spells_monsters.cpp +++ b/engines/mm/mm1/game/spells_monsters.cpp @@ -446,7 +446,7 @@ bool SpellsMonsters::casts() { } void SpellsMonsters::addCharName() { - add(g_globals->_currCharacter->getDisplayName()); + add(g_globals->_currCharacter->_name); } void SpellsMonsters::damageRandomChar() { diff --git a/engines/mm/mm1/views/search.cpp b/engines/mm/mm1/views/search.cpp index d0b3f45a29e1..2d6bff703cdd 100644 --- a/engines/mm/mm1/views/search.cpp +++ b/engines/mm/mm1/views/search.cpp @@ -358,7 +358,7 @@ void Search::drawTreasure() { writeString(0, _lineNum++, Common::String::format( STRING["dialogs.search.found_gems"].c_str(), - c.getDisplayName().c_str(), + c._name, gems)); c._gems = MIN((int)c._gems + gems, 0xffff); } @@ -387,7 +387,7 @@ void Search::drawItem() { // Add line for found item writeString(0, _lineNum++, Common::String::format( STRING["dialogs.search.found_item"].c_str(), - c.getDisplayName().c_str(), + c._name, item->_name.c_str() )); From 2f7e07e1baf6746931c265a6c23311f57670f576 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Sat, 4 Feb 2023 21:30:16 -0800 Subject: [PATCH 030/412] MM: MM1: Move subtractDamage to Combat class --- engines/mm/mm1/game/combat.cpp | 30 +++++++++++++++++++++ engines/mm/mm1/game/combat.h | 6 +++++ engines/mm/mm1/game/spells_monsters.cpp | 32 +--------------------- engines/mm/mm1/game/spells_monsters.h | 36 ++++++++++++------------- engines/mm/mm1/views/combat.cpp | 2 +- 5 files changed, 56 insertions(+), 50 deletions(-) diff --git a/engines/mm/mm1/game/combat.cpp b/engines/mm/mm1/game/combat.cpp index 34b28c6b0028..2fc1347363c8 100644 --- a/engines/mm/mm1/game/combat.cpp +++ b/engines/mm/mm1/game/combat.cpp @@ -1621,6 +1621,36 @@ void Combat::combatDone() { g_globals->_party.rearrange(g_globals->_combatParty); } +void Combat::subtractDamageFromChar() { + Character &c = *g_globals->_currCharacter; + int newHp = c._hpBase - _damage; + + if (newHp > 0) { + c._hpBase = newHp; + + } else { + c._hpBase = 0; + + if (!(c._condition & (BAD_CONDITION | UNCONSCIOUS))) { + c._condition |= UNCONSCIOUS; + addCharName(); + add(' '); + add(STRING["monster_spellsState.goes_down"]); + Sound::sound2(SOUND_8); + + } else { + if (c._condition & BAD_CONDITION) + c._condition = BAD_CONDITION | DEAD; + + _lines.push_back(Line(0, 3, "")); + addCharName(); + add(' '); + add(STRING["monster_spellsState.dies"]); + Sound::sound2(SOUND_8); + } + } +} + } // namespace Game } // namespace MM1 } // namespace MM diff --git a/engines/mm/mm1/game/combat.h b/engines/mm/mm1/game/combat.h index c077f5219e45..d74a0fbdb427 100644 --- a/engines/mm/mm1/game/combat.h +++ b/engines/mm/mm1/game/combat.h @@ -104,6 +104,12 @@ class Combat : public MonsterTouch { */ virtual void combatDone(); + /** + * Subtracts the damage from the character, making + * them unconscious or die if needed + */ + void subtractDamageFromChar() override; + /** * Clear all the combat variables */ diff --git a/engines/mm/mm1/game/spells_monsters.cpp b/engines/mm/mm1/game/spells_monsters.cpp index c96b414d2d42..96b4d7c9df2f 100644 --- a/engines/mm/mm1/game/spells_monsters.cpp +++ b/engines/mm/mm1/game/spells_monsters.cpp @@ -490,7 +490,7 @@ void SpellsMonsters::handleDamage() { _damage = 1; writeDamage(); - subtractDamage(); + subtractDamageFromChar(); } } } @@ -572,36 +572,6 @@ void SpellsMonsters::writeDamage() { add(STRING["monster_spellsState.of_damage"]); } -void SpellsMonsters::subtractDamage() { - Character &c = *g_globals->_currCharacter; - int newHp = c._hpBase - _damage; - - if (newHp > 0) { - c._hpBase = newHp; - - } else { - c._hpBase = 0; - - if (!(c._condition & (BAD_CONDITION | UNCONSCIOUS))) { - c._condition |= UNCONSCIOUS; - addCharName(); - add(' '); - add(STRING["monster_spellsState.goes_down"]); - Sound::sound2(SOUND_8); - - } else { - if (c._condition & BAD_CONDITION) - c._condition = BAD_CONDITION | DEAD; - - _lines.push_back(Line(0, 3, "")); - addCharName(); - add(' '); - add(STRING["monster_spellsState.dies"]); - Sound::sound2(SOUND_8); - } - } -} - void SpellsMonsters::proc9() { const Character &c = *g_globals->_currCharacter; int val = c._level._current * 4 + c._luck._current; diff --git a/engines/mm/mm1/game/spells_monsters.h b/engines/mm/mm1/game/spells_monsters.h index 451669c91f48..c1342864333d 100644 --- a/engines/mm/mm1/game/spells_monsters.h +++ b/engines/mm/mm1/game/spells_monsters.h @@ -80,21 +80,6 @@ class SpellsMonsters : public GameLogic { */ bool casts(); - /** - * Adds text to the current line - */ - void add(const Common::String &msg) { - _lines.back()._text += msg; - } - void add(char c) { - _lines.back()._text += c; - } - - /** - * Adds current character's name - */ - void addCharName(); - /** * Selects a random character and applies the damage to them */ @@ -155,6 +140,12 @@ class SpellsMonsters : public GameLogic { virtual void dispelParty() = 0; virtual void removeMonster() = 0; + /** + * Subtracts the damage from the character, making + * them unconscious or die if needed + */ + virtual void subtractDamageFromChar() = 0; + /** * Adds text for damage effects on the party */ @@ -184,10 +175,19 @@ class SpellsMonsters : public GameLogic { void proc9(); /** - * Subtracts the damage from the character, making - * them unconscious or die if needed + * Adds text to the current line */ - void subtractDamage(); + void add(const Common::String &msg) { + _lines.back()._text += msg; + } + void add(char c) { + _lines.back()._text += c; + } + + /** + * Adds current character's name + */ + void addCharName(); public: SpellsMonsters(); diff --git a/engines/mm/mm1/views/combat.cpp b/engines/mm/mm1/views/combat.cpp index 40449349130d..45b794b331ee 100644 --- a/engines/mm/mm1/views/combat.cpp +++ b/engines/mm/mm1/views/combat.cpp @@ -682,7 +682,7 @@ void Combat::writeMonsterAttack() { // to call it from here _lines.clear(); _lines.push_back(Line(0, 3, "")); - subtractDamage(); + subtractDamageFromChar(); if (!_lines.back()._text.empty()) writeString(0, yp, _lines.back()._text); From 849ea4da6d0ff91b4b354c306299efb83b2e7809 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Sat, 4 Feb 2023 21:38:24 -0800 Subject: [PATCH 031/412] MM: MM1: Change subtractDamageFromChar to return string --- engines/mm/mm1/game/combat.cpp | 17 +++++++++-------- engines/mm/mm1/game/combat.h | 2 +- engines/mm/mm1/game/spells_monsters.cpp | 4 +++- engines/mm/mm1/game/spells_monsters.h | 2 +- engines/mm/mm1/views/combat.cpp | 13 +++---------- 5 files changed, 17 insertions(+), 21 deletions(-) diff --git a/engines/mm/mm1/game/combat.cpp b/engines/mm/mm1/game/combat.cpp index 2fc1347363c8..130b8e68e358 100644 --- a/engines/mm/mm1/game/combat.cpp +++ b/engines/mm/mm1/game/combat.cpp @@ -1621,9 +1621,10 @@ void Combat::combatDone() { g_globals->_party.rearrange(g_globals->_combatParty); } -void Combat::subtractDamageFromChar() { +Common::String Combat::subtractDamageFromChar() { Character &c = *g_globals->_currCharacter; int newHp = c._hpBase - _damage; + Common::String result; if (newHp > 0) { c._hpBase = newHp; @@ -1633,22 +1634,22 @@ void Combat::subtractDamageFromChar() { if (!(c._condition & (BAD_CONDITION | UNCONSCIOUS))) { c._condition |= UNCONSCIOUS; - addCharName(); - add(' '); - add(STRING["monster_spellsState.goes_down"]); + + result = Common::String::format("%s %s", c._name, + STRING["monster_spellsState.goes_down"]); Sound::sound2(SOUND_8); } else { if (c._condition & BAD_CONDITION) c._condition = BAD_CONDITION | DEAD; - _lines.push_back(Line(0, 3, "")); - addCharName(); - add(' '); - add(STRING["monster_spellsState.dies"]); + result = Common::String::format("%s %s", c._name, + STRING["monster_spellsState.dies"]); Sound::sound2(SOUND_8); } } + + return result; } } // namespace Game diff --git a/engines/mm/mm1/game/combat.h b/engines/mm/mm1/game/combat.h index d74a0fbdb427..d5e85d9bb084 100644 --- a/engines/mm/mm1/game/combat.h +++ b/engines/mm/mm1/game/combat.h @@ -108,7 +108,7 @@ class Combat : public MonsterTouch { * Subtracts the damage from the character, making * them unconscious or die if needed */ - void subtractDamageFromChar() override; + Common::String subtractDamageFromChar() override; /** * Clear all the combat variables diff --git a/engines/mm/mm1/game/spells_monsters.cpp b/engines/mm/mm1/game/spells_monsters.cpp index 96b4d7c9df2f..b3ebf40dc88a 100644 --- a/engines/mm/mm1/game/spells_monsters.cpp +++ b/engines/mm/mm1/game/spells_monsters.cpp @@ -490,7 +490,9 @@ void SpellsMonsters::handleDamage() { _damage = 1; writeDamage(); - subtractDamageFromChar(); + Common::String str = subtractDamageFromChar(); + if (!str.empty()) + _lines.push_back(Line(0, _lines.back().y + 1, str)); } } } diff --git a/engines/mm/mm1/game/spells_monsters.h b/engines/mm/mm1/game/spells_monsters.h index c1342864333d..0352e3bfae02 100644 --- a/engines/mm/mm1/game/spells_monsters.h +++ b/engines/mm/mm1/game/spells_monsters.h @@ -144,7 +144,7 @@ class SpellsMonsters : public GameLogic { * Subtracts the damage from the character, making * them unconscious or die if needed */ - virtual void subtractDamageFromChar() = 0; + virtual Common::String subtractDamageFromChar() = 0; /** * Adds text for damage effects on the party diff --git a/engines/mm/mm1/views/combat.cpp b/engines/mm/mm1/views/combat.cpp index 45b794b331ee..90128917a6cd 100644 --- a/engines/mm/mm1/views/combat.cpp +++ b/engines/mm/mm1/views/combat.cpp @@ -677,16 +677,9 @@ void Combat::writeMonsterAttack() { if (monsterTouch(line)) writeString(0, yp++, line); - // TODO: Maybe refactor subtractDamage to not use - // the _lines/add methods, which would make it cleaner - // to call it from here - _lines.clear(); - _lines.push_back(Line(0, 3, "")); - subtractDamageFromChar(); - - if (!_lines.back()._text.empty()) - writeString(0, yp, _lines.back()._text); - _lines.clear(); + Common::String damageStr = subtractDamageFromChar(); + if (!damageStr.empty()) + writeString(0, yp, damageStr); } } From ca7228fae05ed702048adb8274d0abecc8163757 Mon Sep 17 00:00:00 2001 From: Matthew Duggan Date: Sun, 5 Feb 2023 19:24:08 +0900 Subject: [PATCH 032/412] TETRAEDGE: Fix path usage for videos. The game should now be pretty playable in Windows. --- engines/tetraedge/te/te_core.cpp | 6 +++--- engines/tetraedge/te/te_core.h | 2 +- engines/tetraedge/te/te_image.cpp | 2 +- engines/tetraedge/te/te_tiled_surface.cpp | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/engines/tetraedge/te/te_core.cpp b/engines/tetraedge/te/te_core.cpp index 638a47e341d0..94a480e5564d 100644 --- a/engines/tetraedge/te/te_core.cpp +++ b/engines/tetraedge/te/te_core.cpp @@ -53,8 +53,8 @@ void TeCore::create() { warning("TODO: TeCore::create: Finish implementing me."); } -TeICodec *TeCore::createVideoCodec(const Common::Path &path) { - const Common::String filename = path.getLastComponent().toString(); +TeICodec *TeCore::createVideoCodec(const Common::FSNode &node) { + const Common::String filename = node.getName(); if (!filename.contains('.')) return nullptr; Common::String extn = filename.substr(filename.findFirstOf('.') + 1); @@ -72,7 +72,7 @@ TeICodec *TeCore::createVideoCodec(const Common::Path &path) { } else if (TeImagesSequence::matchExtension(extn)) { return new TeImagesSequence(); } - error("TTeCore::createVideoCodec: Unrecognised format %s", path.toString().c_str()); + error("TTeCore::createVideoCodec: Unrecognised format %s", node.getName().c_str()); } const Common::String &TeCore::fileFlagSystemFlag(const Common::String &name) const { diff --git a/engines/tetraedge/te/te_core.h b/engines/tetraedge/te/te_core.h index 431ff9743c8e..9a055534df76 100644 --- a/engines/tetraedge/te/te_core.h +++ b/engines/tetraedge/te/te_core.h @@ -41,7 +41,7 @@ class TeCore { void addLoc(TeILoc *loc); //void args(int argc, char **argv); // Probably not needed void create(); - TeICodec *createVideoCodec(const Common::Path &path); + TeICodec *createVideoCodec(const Common::FSNode &node); const Common::String &fileFlagSystemFlag(const Common::String &name) const; bool fileFlagSystemFlagsContains(const Common::String &name) const; Common::Array fileFlagSystemPossibleFlags(); diff --git a/engines/tetraedge/te/te_image.cpp b/engines/tetraedge/te/te_image.cpp index b598d93e42bf..3b7e3c75eb39 100644 --- a/engines/tetraedge/te/te_image.cpp +++ b/engines/tetraedge/te/te_image.cpp @@ -94,7 +94,7 @@ bool TeImage::isExtensionSupported(const Common::Path &path) { bool TeImage::load(const Common::FSNode &node) { TeCore *core = g_engine->getCore(); - TeICodec *codec = core->createVideoCodec(node.getPath()); + TeICodec *codec = core->createVideoCodec(node); if (!node.isReadable() || !codec->load(node)) { warning("TeImage::load: Failed to load %s.", node.getPath().c_str()); delete codec; diff --git a/engines/tetraedge/te/te_tiled_surface.cpp b/engines/tetraedge/te/te_tiled_surface.cpp index c865f9763ea8..51180abb89a8 100644 --- a/engines/tetraedge/te/te_tiled_surface.cpp +++ b/engines/tetraedge/te/te_tiled_surface.cpp @@ -74,7 +74,7 @@ bool TeTiledSurface::load(const Common::FSNode &node) { if (!texture) { TeCore *core = g_engine->getCore(); - _codec = core->createVideoCodec(_loadedPath); + _codec = core->createVideoCodec(node); if (!_codec) return false; From 4f4c372a56628f916ba557c21dbc31c907d8f647 Mon Sep 17 00:00:00 2001 From: Lothar Serra Mari Date: Sun, 5 Feb 2023 11:50:20 +0100 Subject: [PATCH 033/412] MM: MM1: Fix compliation error due to missing c_str() call --- engines/mm/mm1/game/combat.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/engines/mm/mm1/game/combat.cpp b/engines/mm/mm1/game/combat.cpp index 130b8e68e358..9a6859088a45 100644 --- a/engines/mm/mm1/game/combat.cpp +++ b/engines/mm/mm1/game/combat.cpp @@ -1636,7 +1636,7 @@ Common::String Combat::subtractDamageFromChar() { c._condition |= UNCONSCIOUS; result = Common::String::format("%s %s", c._name, - STRING["monster_spellsState.goes_down"]); + STRING["monster_spellsState.goes_down"].c_str()); Sound::sound2(SOUND_8); } else { @@ -1644,7 +1644,7 @@ Common::String Combat::subtractDamageFromChar() { c._condition = BAD_CONDITION | DEAD; result = Common::String::format("%s %s", c._name, - STRING["monster_spellsState.dies"]); + STRING["monster_spellsState.dies"].c_str()); Sound::sound2(SOUND_8); } } From f6654b8b1f59673a4baf8a30bbcd6fb65def3b86 Mon Sep 17 00:00:00 2001 From: Roland van Laar Date: Sat, 4 Feb 2023 23:40:13 +0100 Subject: [PATCH 034/412] DIRECTOR: LINGO: Reset lingo parameters Reset a few lingo the keywords on goto events. the beepOn, 0 the keyDownScript, "" the mouseDownScript, "" the mouseUpScript, "" Director 4 Lingo Dictionary p.102 Fixes the menu on the clock in hhouse. Hhouse set some scripts to "dontPassEvent" and relied on Director to reset their values when 'go' was called. --- engines/director/lingo/lingo-builtins.cpp | 2 +- engines/director/lingo/lingo-funcs.cpp | 5 ++- engines/director/lingo/lingo.cpp | 37 ++++++++++++++--------- engines/director/lingo/lingo.h | 3 +- engines/director/lingo/tests/the.lingo | 6 ++++ 5 files changed, 35 insertions(+), 18 deletions(-) diff --git a/engines/director/lingo/lingo-builtins.cpp b/engines/director/lingo/lingo-builtins.cpp index cddf3619a59c..0402968ecb41 100644 --- a/engines/director/lingo/lingo-builtins.cpp +++ b/engines/director/lingo/lingo-builtins.cpp @@ -1391,7 +1391,7 @@ void LB::b_go(int nargs) { warning("b_go: frame arg should be of type STRING or INT, not %s", frame.type2str()); } - g_lingo->func_goto(frame, movie); + g_lingo->func_goto(frame, movie, true); } if (nargs > 0) { diff --git a/engines/director/lingo/lingo-funcs.cpp b/engines/director/lingo/lingo-funcs.cpp index 5a5724a39db0..12f2ddf08d2b 100644 --- a/engines/director/lingo/lingo-funcs.cpp +++ b/engines/director/lingo/lingo-funcs.cpp @@ -181,7 +181,7 @@ void Lingo::func_mciwait(const Common::String &name) { warning("STUB: MCI wait file: %s", name.c_str()); } -void Lingo::func_goto(Datum &frame, Datum &movie) { +void Lingo::func_goto(Datum &frame, Datum &movie, bool calledfromgo) { _vm->_playbackPaused = false; if (!_vm->getCurrentMovie()) @@ -199,6 +199,9 @@ void Lingo::func_goto(Datum &frame, Datum &movie) { // freeze this script context. We'll return to it after entering the next frame. g_lingo->_freezeState = true; + if (calledfromgo) + g_lingo->resetLingoGo(); + if (movie.type != VOID) { Common::String movieFilenameRaw = movie.asString(); diff --git a/engines/director/lingo/lingo.cpp b/engines/director/lingo/lingo.cpp index e305acf64d52..7aa9bcb2145a 100644 --- a/engines/director/lingo/lingo.cpp +++ b/engines/director/lingo/lingo.cpp @@ -39,6 +39,7 @@ #include "director/lingo/lingo-code.h" #include "director/lingo/lingo-codegen.h" #include "director/lingo/lingo-gr.h" +#include "director/lingo/lingo-the.h" #include "director/lingo/lingo-object.h" namespace Director { @@ -686,6 +687,26 @@ void Lingo::lingoError(const char *s, ...) { } } +void Lingo::resetLingoGo() { + // Reset lingo items that are reset on `go` command + // Director 4 Lingo Dictionary p.102 + Datum emptyDatum = Datum(""); + Datum dZero = Datum(0); + Datum nullId; + g_lingo->setTheEntity(kTheBeepOn, nullId, kTheNOField, dZero); + g_lingo->setTheEntity(kTheKeyDownScript, nullId, kTheNOField, emptyDatum); + g_lingo->setTheEntity(kTheMouseDownScript, nullId, kTheNOField, emptyDatum); + g_lingo->setTheEntity(kTheMouseUpScript, nullId, kTheNOField, emptyDatum); + + // TODO + // Should also be reset based on: Director 4 Lingo Dictionary p.102 + // the constraint properties + // cursor of sprite + // immediate of sprite + // cursor + // puppetSprite +} + void Lingo::resetLingo() { debugC(3, kDebugLingoExec, "Resetting Lingo!"); @@ -695,21 +716,7 @@ void Lingo::resetLingo() { popContext(true); } - // TODO - // - // reset the following: - // the keyDownScript - // the mouseUpScript - // the mouseDownScript - // the beepOn - // the constraint properties - // the cursor - // the immediate sprite properties - // the puppetSprite - // cursor commands - // - // NOTE: - // timeoutScript is not reset + resetLingoGo(); } int Lingo::getAlignedType(const Datum &d1, const Datum &d2, bool numsOnly) { diff --git a/engines/director/lingo/lingo.h b/engines/director/lingo/lingo.h index 12498e33b7cf..ddfbfb4d24d5 100644 --- a/engines/director/lingo/lingo.h +++ b/engines/director/lingo/lingo.h @@ -314,6 +314,7 @@ class Lingo { ~Lingo(); void resetLingo(); + void resetLingoGo(); int getMenuNum(); int getMenuItemsNum(Datum &d); @@ -402,7 +403,7 @@ class Lingo { void func_mci(const Common::String &name); void func_mciwait(const Common::String &name); void func_beep(int repeats); - void func_goto(Datum &frame, Datum &movie); + void func_goto(Datum &frame, Datum &movie, bool commandgo = false ); void func_gotoloop(); void func_gotonext(); void func_gotoprevious(); diff --git a/engines/director/lingo/tests/the.lingo b/engines/director/lingo/tests/the.lingo index 4a8f83899084..5d3db12dd185 100644 --- a/engines/director/lingo/tests/the.lingo +++ b/engines/director/lingo/tests/the.lingo @@ -87,3 +87,9 @@ scummvmAssertEqual(the number of items in chunkExpr, 1) set the itemDelimiter to ":" scummvmAssertEqual(the number of items in chunkExpr, 3) set the itemDelimiter to save + +-- test initialisation +scummvmAssertEqual(the beepOn, 0) +scummvmAssertEqual(the keyDownScript, "") +scummvmAssertEqual(the mouseDownScript, "") +scummvmAssertEqual(the mouseUpScript, "") From ecea1d5c396f51617ec4c55ae80d30979575e583 Mon Sep 17 00:00:00 2001 From: Le Philousophe Date: Sun, 5 Feb 2023 18:00:24 +0100 Subject: [PATCH 035/412] GUI: Fix width and height calculation _defaultW and _defaultH are already scaled and should not be scaled again --- gui/ThemeLayout.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gui/ThemeLayout.cpp b/gui/ThemeLayout.cpp index 66a3e2a05a82..41f0cbb8b4f5 100644 --- a/gui/ThemeLayout.cpp +++ b/gui/ThemeLayout.cpp @@ -229,8 +229,8 @@ void ThemeLayoutMain::reflowLayout(Widget *widgetChain) { } else if (_overlays == "screen_center") { _x = -1; _y = -1; - _w = _defaultW > 0 ? MIN(_defaultW, g_gui.getGUIWidth()) * g_gui.getScaleFactor() : -1; - _h = _defaultH > 0 ? MIN(_defaultH, g_gui.getGUIHeight()) * g_gui.getScaleFactor() : -1; + _w = _defaultW > 0 ? MIN(_defaultW, (int16)(g_gui.getGUIWidth() * g_gui.getScaleFactor())) : -1; + _h = _defaultH > 0 ? MIN(_defaultH, (int16)(g_gui.getGUIHeight() * g_gui.getScaleFactor())) : -1; } else { if (!g_gui.xmlEval()->getWidgetData(_overlays, _x, _y, _w, _h)) { warning("Unable to retrieve overlayed dialog position %s", _overlays.c_str()); From 0f9f46a55082e7445ab63d58073d47536399e69b Mon Sep 17 00:00:00 2001 From: neuromancer Date: Fri, 3 Feb 2023 15:01:06 +0100 Subject: [PATCH 036/412] FREESCAPE: refactor to use executeMovementConditions instead of executeLocalGlobalConditions directly --- engines/freescape/freescape.cpp | 5 ++++ engines/freescape/freescape.h | 8 ++++- engines/freescape/games/dark.cpp | 50 ++++++++++++++++++++++++++++++++ engines/freescape/movement.cpp | 6 ++-- 4 files changed, 65 insertions(+), 4 deletions(-) diff --git a/engines/freescape/freescape.cpp b/engines/freescape/freescape.cpp index d91f73ddc3cf..9c56b05a2374 100644 --- a/engines/freescape/freescape.cpp +++ b/engines/freescape/freescape.cpp @@ -498,6 +498,11 @@ void FreescapeEngine::processInput() { } } +void FreescapeEngine::executeMovementConditions() { + // Only execute "on collision" room/global conditions + executeLocalGlobalConditions(false, true); +} + void FreescapeEngine::updateTimeVariables() { int seconds, minutes, hours; getTimeFromCountdown(seconds, minutes, hours); diff --git a/engines/freescape/freescape.h b/engines/freescape/freescape.h index b4641f73912c..5747f2825aa7 100644 --- a/engines/freescape/freescape.h +++ b/engines/freescape/freescape.h @@ -237,6 +237,7 @@ class FreescapeEngine : public Engine { bool checkCollisions(bool executeCode); Math::Vector3d _objExecutingCodeSize; + virtual void executeMovementConditions(); void executeObjectConditions(GeometricObject *obj, bool shot, bool collided); void executeLocalGlobalConditions(bool shot, bool collided); void executeCode(FCLInstructionVector &code, bool shot, bool collided); @@ -356,7 +357,7 @@ class FreescapeEngine : public Engine { int _lastMinute; void getTimeFromCountdown(int &seconds, int &minutes, int &hours); - void updateTimeVariables(); + virtual void updateTimeVariables(); // Cheats bool _useExtendedTimer; @@ -438,11 +439,16 @@ class DarkEngine : public FreescapeEngine { DarkEngine(OSystem *syst, const ADGameDescription *gd); void loadAssets() override; + void initGameState() override; + void gotoArea(uint16 areaID, int entranceID) override; void pressedKey(const int keycode) override; void loadAssetsDemo(); void loadAssetsFullGame(); + int _lastTenSeconds; + void updateTimeVariables() override; + void executeMovementConditions() override; void drawUI() override; Common::Error saveGameStreamExtended(Common::WriteStream *stream, bool isAutosave = false) override; diff --git a/engines/freescape/games/dark.cpp b/engines/freescape/games/dark.cpp index cf338790f299..55d33f0bead6 100644 --- a/engines/freescape/games/dark.cpp +++ b/engines/freescape/games/dark.cpp @@ -35,6 +35,7 @@ DarkEngine::DarkEngine(OSystem *syst, const ADGameDescription *gd) : FreescapeEn _playerHeight = _playerHeights[_playerHeightNumber]; _playerWidth = 12; _playerDepth = 32; + _lastTenSeconds = -1; } void DarkEngine::loadAssets() { @@ -67,6 +68,31 @@ void DarkEngine::loadAssetsDemo() { error("Invalid or unsupported render mode %s for Dark Side", Common::getRenderModeDescription(_renderMode)); } +void DarkEngine::initGameState() { + _flyMode = false; + _noClipMode = false; + _shootingFrames = 0; + _underFireFrames = 0; + _yaw = 0; + _pitch = 0; + + for (int i = 0; i < k8bitMaxVariable; i++) // TODO: check maximum variable + _gameStateVars[i] = 0; + + for (auto &it : _areaMap) { + it._value->resetArea(); + _gameStateBits[it._key] = 0; + } + + _playerHeightNumber = 1; + _playerHeight = _playerHeights[_playerHeightNumber]; + removeTimers(); + startCountdown(_initialCountdown); + _lastMinute = 0; + _demoIndex = 0; + _demoEvents.clear(); +} + void DarkEngine::loadAssetsFullGame() { Common::File file; if (_renderMode == Common::kRenderEGA) { @@ -155,6 +181,30 @@ void DarkEngine::pressedKey(const int keycode) { } } +void DarkEngine::executeMovementConditions() { + // Only execute "on collision" room/global conditions + if (_currentArea->getAreaFlags() == 1) + executeLocalGlobalConditions(false, true); +} + +void DarkEngine::updateTimeVariables() { + // This function only executes "on collision" room/global conditions + int seconds, minutes, hours; + getTimeFromCountdown(seconds, minutes, hours); + if (_lastTenSeconds != seconds / 10) { + _lastTenSeconds = seconds / 10; + if (_currentArea->getAreaFlags() == 0) + executeLocalGlobalConditions(false, true); + } + + if (_lastMinute != minutes) { + _lastMinute = minutes; + _gameStateVars[0x1e] += 1; + _gameStateVars[0x1f] += 1; + executeLocalGlobalConditions(false, true); + } +} + void DarkEngine::drawUI() { uint32 gray = _gfx->_texturePixelFormat.ARGBToColor(0x00, 0xA0, 0xA0, 0xA0); uint32 yellow = _gfx->_texturePixelFormat.ARGBToColor(0xFF, 0xFF, 0xFF, 0x55); diff --git a/engines/freescape/movement.cpp b/engines/freescape/movement.cpp index d3db2059aaf9..69f7c3b1561a 100644 --- a/engines/freescape/movement.cpp +++ b/engines/freescape/movement.cpp @@ -149,7 +149,7 @@ void FreescapeEngine::rise() { _lastPosition = _position; debugC(1, kFreescapeDebugMove, "new player position: %f, %f, %f", _position.x(), _position.y(), _position.z()); - executeLocalGlobalConditions(false, true); // Only execute "on collision" room/global conditions + executeMovementConditions(); } void FreescapeEngine::lower() { @@ -174,7 +174,7 @@ void FreescapeEngine::lower() { _lastPosition = _position; debugC(1, kFreescapeDebugMove, "new player position: %f, %f, %f", _position.x(), _position.y(), _position.z()); - executeLocalGlobalConditions(false, true); // Only execute "on collision" room/global conditions + executeMovementConditions(); } void FreescapeEngine::move(CameraMovement direction, uint8 scale, float deltaTime) { @@ -267,7 +267,7 @@ void FreescapeEngine::move(CameraMovement direction, uint8 scale, float deltaTim debugC(1, kFreescapeDebugMove, "new player position: %f, %f, %f", _position.x(), _position.y(), _position.z()); //debugC(1, kFreescapeDebugMove, "player height: %f", _position.y() - areaScale * _playerHeight); if (_currentArea->getAreaID() == previousAreaID) - executeLocalGlobalConditions(false, true); // Only execute "on collision" room/global conditions + executeMovementConditions(); } bool FreescapeEngine::checkFloor(Math::Vector3d currentPosition) { From 8501ccc9c086143f9b4676ee3900966d907c735c Mon Sep 17 00:00:00 2001 From: neuromancer Date: Sat, 4 Feb 2023 12:45:29 +0100 Subject: [PATCH 037/412] FREESCAPE: read strings from dark EGA releases (and demo) --- engines/freescape/games/dark.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/engines/freescape/games/dark.cpp b/engines/freescape/games/dark.cpp index 55d33f0bead6..70307ccc1134 100644 --- a/engines/freescape/games/dark.cpp +++ b/engines/freescape/games/dark.cpp @@ -53,7 +53,7 @@ void DarkEngine::loadAssetsDemo() { if (!file.isOpen()) error("Failed to open DSIDEE.EXE"); - + loadMessagesFixedSize(&file, 0x4525, 16, 27); loadFonts(&file, 0xa598); load8bitBinary(&file, 0xa700, 16); } else if (isDOS() && _renderMode == Common::kRenderCGA) { @@ -103,6 +103,7 @@ void DarkEngine::loadAssetsFullGame() { error("Failed to open DSIDEE.EXE"); loadFonts(&file, 0xa113); + loadMessagesFixedSize(&file, 0x4525, 16, 27); load8bitBinary(&file, 0xa280, 16); } else if (_renderMode == Common::kRenderCGA) { loadBundledImages(); From 4e59cf8f8c6c54cef3b5a5b89aeb80b40b49a9c6 Mon Sep 17 00:00:00 2001 From: neuromancer Date: Sun, 5 Feb 2023 08:57:03 +0100 Subject: [PATCH 038/412] FREESCAPE: refactor game bits handling and set bit 31 when colliding --- engines/freescape/freescape.cpp | 13 +++++++++++++ engines/freescape/freescape.h | 4 ++++ engines/freescape/language/instruction.cpp | 18 +++++++++--------- engines/freescape/movement.cpp | 5 ++++- 4 files changed, 30 insertions(+), 10 deletions(-) diff --git a/engines/freescape/freescape.cpp b/engines/freescape/freescape.cpp index 9c56b05a2374..6481d0dc7ff8 100644 --- a/engines/freescape/freescape.cpp +++ b/engines/freescape/freescape.cpp @@ -626,6 +626,19 @@ bool FreescapeEngine::checkIfGameEnded() { return false; // TODO } +void FreescapeEngine::setGameBit(int index) { + _gameStateBits[_currentArea->getAreaID()] |= (1 << (index - 1)); +} + +void FreescapeEngine::clearGameBit(int index) { + _gameStateBits[_currentArea->getAreaID()] &= ~(1 << (index - 1)); +} + +void FreescapeEngine::toggleGameBit(int index) { + _gameStateBits[_currentArea->getAreaID()] ^= (1 << (index - 1)); +} + + void FreescapeEngine::initGameState() { for (int i = 0; i < k8bitMaxVariable; i++) // TODO: check maximum variable _gameStateVars[i] = 0; diff --git a/engines/freescape/freescape.h b/engines/freescape/freescape.h index 5747f2825aa7..8403333de225 100644 --- a/engines/freescape/freescape.h +++ b/engines/freescape/freescape.h @@ -325,6 +325,10 @@ class FreescapeEngine : public Engine { // Game state virtual void initGameState(); + void setGameBit(int index); + void clearGameBit(int index); + void toggleGameBit(int index); + StateVars _gameStateVars; StateBits _gameStateBits; virtual bool checkIfGameEnded(); diff --git a/engines/freescape/language/instruction.cpp b/engines/freescape/language/instruction.cpp index ef9e656ffa96..3389ca994938 100644 --- a/engines/freescape/language/instruction.cpp +++ b/engines/freescape/language/instruction.cpp @@ -446,23 +446,23 @@ void FreescapeEngine::executeGoto(FCLInstruction &instruction) { } void FreescapeEngine::executeSetBit(FCLInstruction &instruction) { - uint16 index = instruction._source - 1; // Starts in 1 - assert(index < 32); - _gameStateBits[_currentArea->getAreaID()] |= (1 << index); + uint16 index = instruction._source; // Starts at 1 + assert(index > 0 && index <= 32); + setGameBit(index); debugC(1, kFreescapeDebugCode, "Setting bit %d", index); - // debug("v: %d", (_gameStateBits[_currentArea->getAreaID()] & (1 << index))); } void FreescapeEngine::executeClearBit(FCLInstruction &instruction) { - uint16 index = instruction._source - 1; // Starts in 1 - assert(index < 32); - _gameStateBits[_currentArea->getAreaID()] &= ~(1 << index); + uint16 index = instruction._source; // Starts at 1 + assert(index > 0 && index <= 32); + clearGameBit(index); debugC(1, kFreescapeDebugCode, "Clearing bit %d", index); } void FreescapeEngine::executeToggleBit(FCLInstruction &instruction) { - uint16 index = instruction._source - 1; // Starts in 1 - _gameStateBits[_currentArea->getAreaID()] ^= (1 << index); + uint16 index = instruction._source; // Starts at 1 + assert(index > 0 && index <= 32); + toggleGameBit(index); debugC(1, kFreescapeDebugCode, "Toggling bit %d", index); } diff --git a/engines/freescape/movement.cpp b/engines/freescape/movement.cpp index 69f7c3b1561a..35e537ff8d2c 100644 --- a/engines/freescape/movement.cpp +++ b/engines/freescape/movement.cpp @@ -239,10 +239,12 @@ void FreescapeEngine::move(CameraMovement direction, uint8 scale, float deltaTim playSound(3, false); } debugC(1, kFreescapeDebugCode, "Runing effects:"); + if (_flyMode) + setGameBit(31); checkCollisions(true); // run the effects } else { debugC(1, kFreescapeDebugCode, "Runing effects: at: %f, %f, %f", _position.x(), _position.y(), _position.z()); - + setGameBit(31); checkCollisions(true); // run the effects if (_currentArea->getAreaID() == previousAreaID) { if (_flyMode) @@ -268,6 +270,7 @@ void FreescapeEngine::move(CameraMovement direction, uint8 scale, float deltaTim //debugC(1, kFreescapeDebugMove, "player height: %f", _position.y() - areaScale * _playerHeight); if (_currentArea->getAreaID() == previousAreaID) executeMovementConditions(); + clearGameBit(31); } bool FreescapeEngine::checkFloor(Math::Vector3d currentPosition) { From 7797331c955ff413a5239a71e818c5ecdaba6c40 Mon Sep 17 00:00:00 2001 From: neuromancer Date: Sun, 5 Feb 2023 11:14:52 +0100 Subject: [PATCH 039/412] FREESCAPE: improve dark UI for dos release and demo --- engines/freescape/freescape.h | 4 + engines/freescape/games/dark.cpp | 95 ++++++++++++++++--- .../freescape/loaders/8bitBinaryLoader.cpp | 9 ++ 3 files changed, 95 insertions(+), 13 deletions(-) diff --git a/engines/freescape/freescape.h b/engines/freescape/freescape.h index 8403333de225..1ac2e84d572e 100644 --- a/engines/freescape/freescape.h +++ b/engines/freescape/freescape.h @@ -442,6 +442,9 @@ class DarkEngine : public FreescapeEngine { public: DarkEngine(OSystem *syst, const ADGameDescription *gd); + uint32 _initialFuel; + uint32 _initialShield; + void loadAssets() override; void initGameState() override; @@ -455,6 +458,7 @@ class DarkEngine : public FreescapeEngine { void executeMovementConditions() override; void drawUI() override; + void drawDOSUI(Graphics::Surface *surface); Common::Error saveGameStreamExtended(Common::WriteStream *stream, bool isAutosave = false) override; Common::Error loadGameStreamExtended(Common::SeekableReadStream *stream) override; }; diff --git a/engines/freescape/games/dark.cpp b/engines/freescape/games/dark.cpp index 70307ccc1134..55dfb12d2a8d 100644 --- a/engines/freescape/games/dark.cpp +++ b/engines/freescape/games/dark.cpp @@ -36,6 +36,16 @@ DarkEngine::DarkEngine(OSystem *syst, const ADGameDescription *gd) : FreescapeEn _playerWidth = 12; _playerDepth = 32; _lastTenSeconds = -1; + + _angleRotations.push_back(5); + _angleRotations.push_back(10); + _angleRotations.push_back(15); + _angleRotations.push_back(30); + _angleRotations.push_back(45); + _angleRotations.push_back(90); + + _initialFuel = 11; + _initialShield = 15; } void DarkEngine::loadAssets() { @@ -84,6 +94,9 @@ void DarkEngine::initGameState() { _gameStateBits[it._key] = 0; } + _gameStateVars[k8bitVariableEnergy] = _initialFuel; + _gameStateVars[k8bitVariableShield] = _initialShield; + _playerHeightNumber = 1; _playerHeight = _playerHeights[_playerHeightNumber]; removeTimers(); @@ -206,13 +219,73 @@ void DarkEngine::updateTimeVariables() { } } -void DarkEngine::drawUI() { - uint32 gray = _gfx->_texturePixelFormat.ARGBToColor(0x00, 0xA0, 0xA0, 0xA0); - uint32 yellow = _gfx->_texturePixelFormat.ARGBToColor(0xFF, 0xFF, 0xFF, 0x55); - uint32 black = _gfx->_texturePixelFormat.ARGBToColor(0xFF, 0x00, 0x00, 0x00); +void DarkEngine::drawDOSUI(Graphics::Surface *surface) { + uint32 color = _renderMode == Common::kRenderCGA ? 1 : 14; + uint8 r, g, b; + + _gfx->readFromPalette(color, r, g, b); + uint32 front = _gfx->_texturePixelFormat.ARGBToColor(0xFF, r, g, b); + + color = _currentArea->_usualBackgroundColor; + if (_gfx->_colorRemaps && _gfx->_colorRemaps->contains(color)) { + color = (*_gfx->_colorRemaps)[color]; + } + + _gfx->readFromPalette(color, r, g, b); + uint32 back = _gfx->_texturePixelFormat.ARGBToColor(0xFF, r, g, b); + + int score = _gameStateVars[k8bitVariableScore]; + drawStringInSurface(Common::String::format("%04d", int(2 * _position.x())), 199, 137, front, back, surface); + drawStringInSurface(Common::String::format("%04d", int(2 * _position.z())), 199, 145, front, back, surface); + drawStringInSurface(Common::String::format("%04d", int(2 * _position.y())), 199, 153, front, back, surface); + + drawStringInSurface(Common::String::format("%02d", int(_angleRotations[_angleRotationIndex])), 71, 168, front, back, surface); + drawStringInSurface(Common::String::format("%3d", _playerSteps[_playerStepIndex]), 71, 177, front, back, surface); + drawStringInSurface(Common::String::format("%07d", score), 95, 8, front, back, surface); + + int seconds, minutes, hours; + getTimeFromCountdown(seconds, minutes, hours); + // TODO: implement binary clock + + Common::String message; + int deadline; + getLatestMessages(message, deadline); + if (deadline <= _countdown) { + drawStringInSurface(message, 112, 177, back, front, surface); + _temporaryMessages.push_back(message); + _temporaryMessageDeadlines.push_back(deadline); + } else + drawStringInSurface(_currentArea->_name, 112, 177, front, back, surface); + + int energy = _gameStateVars[k8bitVariableEnergy]; // called fuel in this game + int shield = _gameStateVars[k8bitVariableShield]; + + _gfx->readFromPalette(9, r, g, b); + uint32 blue = _gfx->_texturePixelFormat.ARGBToColor(0xFF, r, g, b); + + if (shield >= 0) { + Common::Rect shieldBar; + shieldBar = Common::Rect(72, 139, 151 - (k8bitMaxShield - shield), 146); + surface->fillRect(shieldBar, front); + + shieldBar = Common::Rect(72, 140, 151 - (k8bitMaxShield - shield), 145); + surface->fillRect(shieldBar, blue); + } + + if (energy >= 0) { + Common::Rect energyBar; + energyBar = Common::Rect(72, 147, 151 - (k8bitMaxEnergy - energy), 154); + surface->fillRect(energyBar, front); + energyBar = Common::Rect(72, 148, 151 - (k8bitMaxEnergy - energy), 153); + surface->fillRect(energyBar, blue); + } +} + +void DarkEngine::drawUI() { Graphics::Surface *surface = nullptr; - if (_border) { + if (_border) { // This can be removed when all the borders are loaded + uint32 gray = _gfx->_texturePixelFormat.ARGBToColor(0x00, 0xA0, 0xA0, 0xA0); surface = new Graphics::Surface(); surface->create(_screenW, _screenH, _gfx->_texturePixelFormat); surface->fillRect(_fullscreenViewArea, gray); @@ -220,14 +293,10 @@ void DarkEngine::drawUI() { } else return; - if (_currentAreaMessages.size() == 1) { - int score = _gameStateVars[k8bitVariableScore]; - drawStringInSurface(_currentAreaMessages[0], 112, 177, yellow, black, surface); - drawStringInSurface(Common::String::format("%04d", 2 * int(_position.x())), 199, 137, yellow, black, surface); - drawStringInSurface(Common::String::format("%04d", 2 * int(_position.z())), 199, 145, yellow, black, surface); - drawStringInSurface(Common::String::format("%04d", 2 * int(_position.y())), 199, 153, yellow, black, surface); - drawStringInSurface(Common::String::format("%07d", score), 95, 8, yellow, black, surface); - } + if (isDOS()) + drawDOSUI(surface); + else + error("UI not implemented yet"); if (!_uiTexture) _uiTexture = _gfx->createTexture(surface); diff --git a/engines/freescape/loaders/8bitBinaryLoader.cpp b/engines/freescape/loaders/8bitBinaryLoader.cpp index ff395a1a2ce5..80a5e6b6fbb7 100644 --- a/engines/freescape/loaders/8bitBinaryLoader.cpp +++ b/engines/freescape/loaders/8bitBinaryLoader.cpp @@ -438,6 +438,15 @@ void FreescapeEngine::load8bitBinary(Common::SeekableReadStream *file, int offse debugC(1, kFreescapeDebugParser, "Start area: %d", startArea); uint8 startEntrance = readField(file, 8); debugC(1, kFreescapeDebugParser, "Entrace area: %d", startEntrance); + readField(file, 8); // Unknown + + uint8 initialEnergy1 = readField(file, 8); + uint8 initialShield1 = readField(file, 8); + uint8 initialEnergy2 = readField(file, 8); + uint8 initialShield2 = readField(file, 8); + + debugC(1, kFreescapeDebugParser, "Initial levels of energy: %d and shield: %d", initialEnergy1, initialShield1); + debugC(1, kFreescapeDebugParser, "Initial levels of energy: %d and shield: %d", initialEnergy2, initialShield2); if (isAmiga() || isAtariST()) file->seek(offset + 0x14); From b67cf1234929c07e4224a5ac19ab955cfd0f81e4 Mon Sep 17 00:00:00 2001 From: neuromancer Date: Sun, 5 Feb 2023 18:11:50 +0100 Subject: [PATCH 040/412] FREESCAPE: implemented area connections in dark --- engines/freescape/freescape.h | 2 + engines/freescape/games/dark.cpp | 25 +++++++++++ .../freescape/loaders/8bitBinaryLoader.cpp | 16 +++++++ engines/freescape/movement.cpp | 22 +++++---- engines/freescape/objects/connections.h | 45 +++++++++++++++++++ 5 files changed, 102 insertions(+), 8 deletions(-) create mode 100644 engines/freescape/objects/connections.h diff --git a/engines/freescape/freescape.h b/engines/freescape/freescape.h index 1ac2e84d572e..a7ec3096b61f 100644 --- a/engines/freescape/freescape.h +++ b/engines/freescape/freescape.h @@ -187,6 +187,7 @@ class FreescapeEngine : public Engine { void generateDemoInput(); virtual void pressedKey(const int keycode); void move(CameraMovement direction, uint8 scale, float deltaTime); + virtual void checkIfStillInArea(); void changePlayerHeight(int index); void increaseStepSize(); void decreaseStepSize(); @@ -449,6 +450,7 @@ class DarkEngine : public FreescapeEngine { void initGameState() override; void gotoArea(uint16 areaID, int entranceID) override; + void checkIfStillInArea() override; void pressedKey(const int keycode) override; void loadAssetsDemo(); diff --git a/engines/freescape/games/dark.cpp b/engines/freescape/games/dark.cpp index 55dfb12d2a8d..60e1b86bfd01 100644 --- a/engines/freescape/games/dark.cpp +++ b/engines/freescape/games/dark.cpp @@ -23,6 +23,7 @@ #include "freescape/freescape.h" #include "freescape/language/8bitDetokeniser.h" +#include "freescape/objects/connections.h" namespace Freescape { @@ -195,6 +196,30 @@ void DarkEngine::pressedKey(const int keycode) { } } +void DarkEngine::checkIfStillInArea() { + AreaConnections *cons = (AreaConnections *)_currentArea->entranceWithID(254); + if (!cons) { + FreescapeEngine::checkIfStillInArea(); + return; + } + + int nextAreaID = 0; + + if (_position.z() >= 4064 - 16) + nextAreaID = cons->_connections[1]; + else if (_position.x() >= 4064 - 16) + nextAreaID = cons->_connections[3]; + else if (_position.z() <= 16) + nextAreaID = cons->_connections[5]; + else if (_position.x() <= 16) + nextAreaID = cons->_connections[7]; + + if (nextAreaID > 0) + gotoArea(nextAreaID, 0); + else + FreescapeEngine::checkIfStillInArea(); +} + void DarkEngine::executeMovementConditions() { // Only execute "on collision" room/global conditions if (_currentArea->getAreaFlags() == 1) diff --git a/engines/freescape/loaders/8bitBinaryLoader.cpp b/engines/freescape/loaders/8bitBinaryLoader.cpp index 80a5e6b6fbb7..b0b2edefc0cd 100644 --- a/engines/freescape/loaders/8bitBinaryLoader.cpp +++ b/engines/freescape/loaders/8bitBinaryLoader.cpp @@ -26,6 +26,7 @@ #include "freescape/freescape.h" #include "freescape/language/8bitDetokeniser.h" +#include "freescape/objects/connections.h" #include "freescape/objects/global.h" #include "freescape/objects/group.h" #include "freescape/objects/sensor.h" @@ -115,6 +116,21 @@ Object *FreescapeEngine::load8bitObject(Common::SeekableReadStream *file) { while(--byteSizeOfObject > 0) structureArray.push_back(file->readByte()); return new GlobalStructure(structureArray); + } else if (objectID == 254 && objectType == ObjectType::kEntranceType) { + debugC(1, kFreescapeDebugParser, "Found the area connections (objectID: 254 with size %d)", byteSizeOfObject + 6); + Common::Array connectionsArray; + connectionsArray.push_back(uint8(position.x())); + connectionsArray.push_back(uint8(position.y())); + connectionsArray.push_back(uint8(position.z())); + + connectionsArray.push_back(uint8(v.x())); + connectionsArray.push_back(uint8(v.y())); + connectionsArray.push_back(uint8(v.z())); + + byteSizeOfObject++; + while(--byteSizeOfObject > 0) + connectionsArray.push_back(file->readByte()); + return new AreaConnections(connectionsArray); } debugC(1, kFreescapeDebugParser, "Object %d ; type %d ; size %d", objectID, (int)objectType, byteSizeOfObject); diff --git a/engines/freescape/movement.cpp b/engines/freescape/movement.cpp index 35e537ff8d2c..c9055e80248b 100644 --- a/engines/freescape/movement.cpp +++ b/engines/freescape/movement.cpp @@ -177,6 +177,17 @@ void FreescapeEngine::lower() { executeMovementConditions(); } +void FreescapeEngine::checkIfStillInArea() { + for (int i = 0; i < 3; i++) { + if (_position.getValue(i) < 0) + _position.setValue(i, 0); + else if (_position.getValue(i) > 8128) + _position.setValue(i, 8128); + } + if (_position.y() >= 2016) + _position.y() = _lastPosition.z(); +} + void FreescapeEngine::move(CameraMovement direction, uint8 scale, float deltaTime) { debugC(1, kFreescapeDebugMove, "old player position: %f, %f, %f", _position.x(), _position.y(), _position.z()); int previousAreaID = _currentArea->getAreaID(); @@ -207,14 +218,9 @@ void FreescapeEngine::move(CameraMovement direction, uint8 scale, float deltaTim if (!_flyMode) _position.set(_position.x(), positionY, _position.z()); - for (int i = 0; i < 3; i++) { - if (_position.getValue(i) < 0) - _position.setValue(i, 0); - else if (_position.getValue(i) > 8128) - _position.setValue(i, 8128); - } - if (_position.y() >= 2016) - _position.y() = _lastPosition.z(); + checkIfStillInArea(); + if (_currentArea->getAreaID() != previousAreaID) + return; bool collided = checkCollisions(false); diff --git a/engines/freescape/objects/connections.h b/engines/freescape/objects/connections.h new file mode 100644 index 000000000000..75e705fcceb2 --- /dev/null +++ b/engines/freescape/objects/connections.h @@ -0,0 +1,45 @@ +/* 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 . + * + */ + +#ifndef FREESCAPE_CONNECTIONS_H +#define FREESCAPE_CONNECTIONS_H + +#include "freescape/objects/object.h" + +namespace Freescape { + +class AreaConnections : public Object { +public: + Common::Array _connections; + AreaConnections(const Common::Array connections_) { + _objectID = 254; + _connections = connections_; + } + + ObjectType getType() override { return ObjectType::kEntranceType; }; + void draw(Freescape::Renderer *gfx) override { error("cannot render AreaConnections"); }; + void scale(int factor) override { warning("cannot scale AreaConnections"); }; + Object *duplicate() override { error("cannot duplicate AreaConnections"); }; +}; + +} // End of namespace Freescape + +#endif // FREESCAPE_CONNECTIONS_H \ No newline at end of file From 8ae35291f164dee916b45d0ce3783bc32d6243ad Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Sun, 5 Feb 2023 11:19:38 -0800 Subject: [PATCH 041/412] MM: MM1: Fix calculating damage when monster attacks --- engines/mm/mm1/game/combat.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/engines/mm/mm1/game/combat.cpp b/engines/mm/mm1/game/combat.cpp index 9a6859088a45..98eeea5acd27 100644 --- a/engines/mm/mm1/game/combat.cpp +++ b/engines/mm/mm1/game/combat.cpp @@ -1514,6 +1514,8 @@ void Combat::monsterAttackInner() { _attackerLevel = (attackerLevel > 255) ? 192 : attackerLevel; } + // Calculate attack damage and set mode to display the result + addAttackDamage(); setMode(MONSTER_ATTACK); } From ed1a0cbd05a1cc7f0f27140221ac5b3a020b5037 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Sun, 5 Feb 2023 11:22:56 -0800 Subject: [PATCH 042/412] MM: MM1: Renaming of character HP fields --- engines/mm/mm1/data/character.cpp | 16 ++++++++-------- engines/mm/mm1/data/character.h | 2 +- engines/mm/mm1/data/trap.cpp | 18 +++++++++--------- engines/mm/mm1/data/trap.h | 2 +- engines/mm/mm1/game/combat.cpp | 12 ++++++------ engines/mm/mm1/game/spells_party.cpp | 10 +++++----- engines/mm/mm1/maps/map.cpp | 2 +- engines/mm/mm1/maps/map06.cpp | 4 ++-- engines/mm/mm1/maps/map09.cpp | 2 +- engines/mm/mm1/maps/map15.cpp | 2 +- engines/mm/mm1/maps/map27.cpp | 2 +- engines/mm/mm1/maps/map28.cpp | 2 +- engines/mm/mm1/maps/map33.cpp | 2 +- engines/mm/mm1/views/character_base.cpp | 2 +- engines/mm/mm1/views/create_characters.cpp | 2 +- engines/mm/mm1/views/locations/temple.cpp | 2 +- engines/mm/mm1/views_enh/locations/temple.cpp | 2 +- 17 files changed, 42 insertions(+), 42 deletions(-) diff --git a/engines/mm/mm1/data/character.cpp b/engines/mm/mm1/data/character.cpp index 7888d90a42e7..4b78296ec60d 100644 --- a/engines/mm/mm1/data/character.cpp +++ b/engines/mm/mm1/data/character.cpp @@ -182,7 +182,7 @@ void Character::synchronize(Common::Serializer &s) { _spellLevel.synchronize(s); s.syncAsUint16LE(_gems); - s.syncAsUint16LE(_hpBase); + s.syncAsUint16LE(_hpCurrent); s.syncAsUint16LE(_hp); s.syncAsUint16LE(_hpMax); @@ -230,7 +230,7 @@ void Character::clear() { _sp = 0; _spellLevel = 0; _gems = 0; - _hpBase = _hp = _hpMax = 0; + _hpCurrent = _hp = _hpMax = 0; _gold = 0; _ac = 0; _food = 0; @@ -317,8 +317,8 @@ Character::LevelIncrease Character::increaseLevel() { else newHP = MAX(newHP - 3, 1); - _hpBase += newHP; - _hp = _hpMax = _hpBase; + _hpCurrent += newHP; + _hp = _hpMax = _hpCurrent; int gainedSpells = 0; if (classNum < ARCHER) { @@ -538,8 +538,8 @@ void Character::rest() { _condition &= ~(ASLEEP | BLINDED | SILENCED | PARALYZED | UNCONSCIOUS); - if (_hpBase == 0) - _hpBase = 1; + if (_hpCurrent == 0) + _hpCurrent = 1; if (_age._current++ == 255) { _age._base = MIN((int)_age._base + 1, 255); @@ -582,7 +582,7 @@ void Character::rest() { } if (_condition & DISEASED) { - _hpBase = _hpMax; + _hpCurrent = _hpMax; _sp._current = _sp._base; } } @@ -620,7 +620,7 @@ size_t Character::getPerformanceTotal() const { + _sp.getPerformanceTotal() + _spellLevel.getPerformanceTotal() + PERF16(_gems) - + PERF16(_hpBase) + + PERF16(_hpCurrent) + PERF16(_hp) + PERF16(_hpMax) + PERF32(_gold) diff --git a/engines/mm/mm1/data/character.h b/engines/mm/mm1/data/character.h index 322fcf04512e..5d982e2da531 100644 --- a/engines/mm/mm1/data/character.h +++ b/engines/mm/mm1/data/character.h @@ -426,7 +426,7 @@ struct Character : public PrimaryAttributes { uint32 _exp = 0; uint16 _gems = 0; - uint16 _hpBase = 0, _hp = 0, _hpMax = 0; + uint16 _hpCurrent = 0, _hp = 0, _hpMax = 0; uint32 _gold = 0; uint8 _food = 0; uint8 _condition = 0; diff --git a/engines/mm/mm1/data/trap.cpp b/engines/mm/mm1/data/trap.cpp index 61de8d36aa19..6f694e5773ff 100644 --- a/engines/mm/mm1/data/trap.cpp +++ b/engines/mm/mm1/data/trap.cpp @@ -88,7 +88,7 @@ void TrapData::trap() { } for (uint i = 0; i < g_globals->_party.size(); ++i, _reduced = val4) { - _hp = maxVal; + _hpInitial = maxVal; damageChar(i); } } @@ -96,12 +96,12 @@ void TrapData::trap() { void TrapData::damageChar(uint partyIndex) { Character &c = g_globals->_party[partyIndex]; if (&c != g_globals->_currCharacter) - _hp >>= 1; + _hpInitial >>= 1; if (_resistanceIndex != -1 && c._resistances._arr[_resistanceIndex] != 0 && getRandomNumber(100) < c._resistances._arr[_resistanceIndex]) { - _hp >>= 1; + _hpInitial >>= 1; ++_reduced; } @@ -109,27 +109,27 @@ void TrapData::damageChar(uint partyIndex) { int luckLevel2 = getRandomNumber(luckLevel1 + 20); if (getRandomNumber(luckLevel2) < luckLevel1) { - _hp >>= 1; + _hpInitial >>= 1; ++_reduced; } if (c._condition & BAD_CONDITION) { - c._hpBase = 0; + c._hpCurrent = 0; } else if (c._condition & UNCONSCIOUS) { c._condition = BAD_CONDITION | DEAD; - c._hpBase = 0; + c._hpCurrent = 0; } else { - c._hpBase = MAX((int)c._hpBase - _hp, 0); + c._hpCurrent = MAX((int)c._hpCurrent - _hpInitial, 0); - if (c._hpBase == 0) { + if (c._hpCurrent == 0) { c._condition |= UNCONSCIOUS; } else if (!_reduced && _condition && getRandomNumber(luckLevel1 + 20) >= luckLevel1) { if (_condition >= UNCONSCIOUS) - c._hpBase = 0; + c._hpCurrent = 0; if (!(c._condition & BAD_CONDITION)) c._condition = _condition; diff --git a/engines/mm/mm1/data/trap.h b/engines/mm/mm1/data/trap.h index 8a86b9fc6c23..b36c9eae0dc7 100644 --- a/engines/mm/mm1/data/trap.h +++ b/engines/mm/mm1/data/trap.h @@ -43,7 +43,7 @@ class TrapData : public Game::GameLogic { static byte DAMAGE_TYPE[7]; int _trapType = 0; - int _hp = 0; + int _hpInitial = 0; int _reduced = 0; int _resistanceIndex = 0; byte _condition = 0; diff --git a/engines/mm/mm1/game/combat.cpp b/engines/mm/mm1/game/combat.cpp index 98eeea5acd27..f61918ca9ae5 100644 --- a/engines/mm/mm1/game/combat.cpp +++ b/engines/mm/mm1/game/combat.cpp @@ -728,7 +728,7 @@ void Combat::checkParty() { // Update the array for the party for (uint i = 0; i < g_globals->_combatParty.size(); ++i) { const Character &c = *g_globals->_combatParty[i]; - if ((c._condition & BAD_CONDITION) || !c._hpBase) + if ((c._condition & BAD_CONDITION) || !c._hpCurrent) g_globals->_combatParty[i]->_checked = true; } @@ -1232,8 +1232,8 @@ bool Combat::divineIntervention() { if (c._condition != ERADICATED) { c._condition = 0; - c._hpBase = c._hp; - c._hpMax = c._hpBase; + c._hpCurrent = c._hp; + c._hpMax = c._hpCurrent; } } @@ -1625,14 +1625,14 @@ void Combat::combatDone() { Common::String Combat::subtractDamageFromChar() { Character &c = *g_globals->_currCharacter; - int newHp = c._hpBase - _damage; + int newHp = c._hpCurrent - _damage; Common::String result; if (newHp > 0) { - c._hpBase = newHp; + c._hpCurrent = newHp; } else { - c._hpBase = 0; + c._hpCurrent = 0; if (!(c._condition & (BAD_CONDITION | UNCONSCIOUS))) { c._condition |= UNCONSCIOUS; diff --git a/engines/mm/mm1/game/spells_party.cpp b/engines/mm/mm1/game/spells_party.cpp index e678adce3fb4..52d18e038500 100644 --- a/engines/mm/mm1/game/spells_party.cpp +++ b/engines/mm/mm1/game/spells_party.cpp @@ -473,8 +473,8 @@ SpellResult SpellsParty::cleric54_removeCondition() { } else { _destChar->_condition = FINE; - if (!_destChar->_hpBase) - _destChar->_hpBase = 1; + if (!_destChar->_hpCurrent) + _destChar->_hpCurrent = 1; restoreHp(1); return SR_SUCCESS_DONE; @@ -534,7 +534,7 @@ SpellResult SpellsParty::cleric62_raiseDead() { else _destChar->_condition = FINE; - _destChar->_hpBase = 1; + _destChar->_hpCurrent = 1; return SR_SUCCESS_DONE; } @@ -561,7 +561,7 @@ SpellResult SpellsParty::cleric64_stoneToFlesh() { else _destChar->_condition = FINE; - _destChar->_hpBase = 1; + _destChar->_hpCurrent = 1; return SR_SUCCESS_DONE; } @@ -1022,7 +1022,7 @@ void SpellsParty::restoreHp(uint16 hp) { } void SpellsParty::restoreHp(Character &c, uint16 hp) { - c._hpBase = MIN((int)(c._hpBase + hp), (int)c._hpMax); + c._hpCurrent = MIN((int)(c._hpCurrent + hp), (int)c._hpMax); if (!(c._condition & BAD_CONDITION)) c._condition &= ~UNCONSCIOUS; } diff --git a/engines/mm/mm1/maps/map.cpp b/engines/mm/mm1/maps/map.cpp index 1cf2e24a4ff5..f821959ba530 100644 --- a/engines/mm/mm1/maps/map.cpp +++ b/engines/mm/mm1/maps/map.cpp @@ -93,7 +93,7 @@ void Map::dataWord(uint16 ofs, uint16 val) { void Map::reduceHP() { for (uint i = 0; i < g_globals->_party.size(); ++i) - g_globals->_party[i]._hpBase /= 2; + g_globals->_party[i]._hpCurrent /= 2; } void Map::updateGame() { diff --git a/engines/mm/mm1/maps/map06.cpp b/engines/mm/mm1/maps/map06.cpp index 87a04e5a04c0..6affcd21a061 100644 --- a/engines/mm/mm1/maps/map06.cpp +++ b/engines/mm/mm1/maps/map06.cpp @@ -137,8 +137,8 @@ void Map06::special04() { for (uint i = 0; i < g_globals->_party.size(); ++i) { Character &c = g_globals->_party[i]; - c._hpBase = MAX((int)c._hpBase - 15, 0); - if (!c._hpBase) { + c._hpCurrent = MAX((int)c._hpCurrent - 15, 0); + if (!c._hpCurrent) { if (!(c._condition & BAD_CONDITION)) c._condition = UNCONSCIOUS; } diff --git a/engines/mm/mm1/maps/map09.cpp b/engines/mm/mm1/maps/map09.cpp index 4a8fd4682396..e4536dce247f 100644 --- a/engines/mm/mm1/maps/map09.cpp +++ b/engines/mm/mm1/maps/map09.cpp @@ -172,7 +172,7 @@ void Map09::special14() { if (!g_globals->_activeSpells._s.poison && !(c._condition & BAD_CONDITION)) c._condition = POISONED; - c._hpBase /= 2; + c._hpCurrent /= 2; } SoundMessage msg( diff --git a/engines/mm/mm1/maps/map15.cpp b/engines/mm/mm1/maps/map15.cpp index de5393f670f1..e43cf70c7eee 100644 --- a/engines/mm/mm1/maps/map15.cpp +++ b/engines/mm/mm1/maps/map15.cpp @@ -73,7 +73,7 @@ void Map15::special() { if (!g_globals->_activeSpells._s.fire) { for (uint i = 0; i < g_globals->_party.size(); ++i) { Character &c = g_globals->_party[i]; - c._hpBase = MAX((int)c._hpBase - 15, 0); + c._hpCurrent = MAX((int)c._hpCurrent - 15, 0); } } } diff --git a/engines/mm/mm1/maps/map27.cpp b/engines/mm/mm1/maps/map27.cpp index c174e3356987..1c104807d907 100644 --- a/engines/mm/mm1/maps/map27.cpp +++ b/engines/mm/mm1/maps/map27.cpp @@ -81,7 +81,7 @@ void Map27::special02() { Character &c = g_globals->_party[i]; if (c._condition != ERADICATED) { c._condition = 0; - c._hpBase = c._hpMax = c._hp; + c._hpCurrent = c._hpMax = c._hp; } } diff --git a/engines/mm/mm1/maps/map28.cpp b/engines/mm/mm1/maps/map28.cpp index 2d148ee252c3..1416af8dacc2 100644 --- a/engines/mm/mm1/maps/map28.cpp +++ b/engines/mm/mm1/maps/map28.cpp @@ -201,7 +201,7 @@ void Map28::setCondition(byte condition) { void Map28::reduceHpBase() { for (uint i = 0; i < g_globals->_party.size(); ++i) { Character &c = g_globals->_party[i]; - c._hpBase /= 2; + c._hpCurrent /= 2; } } diff --git a/engines/mm/mm1/maps/map33.cpp b/engines/mm/mm1/maps/map33.cpp index 862a86216085..e63c2f3877bb 100644 --- a/engines/mm/mm1/maps/map33.cpp +++ b/engines/mm/mm1/maps/map33.cpp @@ -78,7 +78,7 @@ void Map33::special() { ]; if (!(c._condition & BAD_CONDITION)) { c._condition |= SILENCED | PARALYZED | UNCONSCIOUS; - c._hpBase = 0; + c._hpCurrent = 0; msg._lines.push_back(Line(0, 2, STRING["maps.map33.quicksand"])); Sound::sound(SOUND_3); } diff --git a/engines/mm/mm1/views/character_base.cpp b/engines/mm/mm1/views/character_base.cpp index 00df3e5e01c4..75b6f9bcdd88 100644 --- a/engines/mm/mm1/views/character_base.cpp +++ b/engines/mm/mm1/views/character_base.cpp @@ -73,7 +73,7 @@ void CharacterBase::printStats() { writeNumber(re._speed); _textPos.x = 8; writeString(STRING["stats.attributes.hp"]); - writeNumber(re._hp); + writeNumber(re._hpCurrent); _textPos.x = 16; writeChar('/'); writeNumber(re._hpMax); diff --git a/engines/mm/mm1/views/create_characters.cpp b/engines/mm/mm1/views/create_characters.cpp index 4c7c71db9c30..f29f9d36250f 100644 --- a/engines/mm/mm1/views/create_characters.cpp +++ b/engines/mm/mm1/views/create_characters.cpp @@ -147,7 +147,7 @@ void CreateCharacters::NewCharacter::setHP(int hp) { else if (_attribs1[ENDURANCE] < 8) hp -= 1; - re._hpBase = re._hp = re._hpMax = hp; + re._hpCurrent = re._hp = re._hpMax = hp; int ac = 0; if (_attribs1[SPEED] >= 19) diff --git a/engines/mm/mm1/views/locations/temple.cpp b/engines/mm/mm1/views/locations/temple.cpp index 05ff9f411d3a..40e152b952e3 100644 --- a/engines/mm/mm1/views/locations/temple.cpp +++ b/engines/mm/mm1/views/locations/temple.cpp @@ -161,7 +161,7 @@ void Temple::restoreHealth() { if (subtractGold(_healCost)) { Character &c = *g_globals->_currCharacter; c._condition = FINE; - c._hpBase = c._hp; + c._hpCurrent = c._hp; if (_isEradicated) { c._age._current += 10; diff --git a/engines/mm/mm1/views_enh/locations/temple.cpp b/engines/mm/mm1/views_enh/locations/temple.cpp index cc3fa2d73aba..f3cda000f181 100644 --- a/engines/mm/mm1/views_enh/locations/temple.cpp +++ b/engines/mm/mm1/views_enh/locations/temple.cpp @@ -159,7 +159,7 @@ void Temple::restoreHealth() { if (subtractGold(_healCost)) { Character &c = *g_globals->_currCharacter; c._condition = FINE; - c._hpBase = c._hp; + c._hpCurrent = c._hp; if (_isEradicated) { c._age._current += 10; From f71236806ee60d713ff86ede1e57376671f49f4b Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Sun, 5 Feb 2023 11:28:22 -0800 Subject: [PATCH 043/412] MM: MM1: Cleaned up calculating char defense adjusts damage --- engines/mm/mm1/game/combat.cpp | 14 +++++++++++++- engines/mm/mm1/game/spells_monsters.h | 2 +- engines/mm/mm1/views/combat.cpp | 13 ++----------- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/engines/mm/mm1/game/combat.cpp b/engines/mm/mm1/game/combat.cpp index f61918ca9ae5..5c12f4df4516 100644 --- a/engines/mm/mm1/game/combat.cpp +++ b/engines/mm/mm1/game/combat.cpp @@ -892,6 +892,8 @@ void Combat::addAttackDamage() { ++_timesHit; } } + + _displayedDamage = _damage; } void Combat::updateMonsterStatus() { @@ -1514,8 +1516,18 @@ void Combat::monsterAttackInner() { _attackerLevel = (attackerLevel > 255) ? 192 : attackerLevel; } - // Calculate attack damage and set mode to display the result + // Calculate attack damage addAttackDamage(); + + // Do some final damage adjustment which may reduce the + // actual damage from what gets displayed + if (g_globals->_activeSpells._s.power_shield) + _damage /= 2; + + if (_val10 && g_globals->_activeSpells._s.shield) + _damage = MAX((int)_damage - 8, 0); + + // Display the result setMode(MONSTER_ATTACK); } diff --git a/engines/mm/mm1/game/spells_monsters.h b/engines/mm/mm1/game/spells_monsters.h index 0352e3bfae02..83ac48832ff2 100644 --- a/engines/mm/mm1/game/spells_monsters.h +++ b/engines/mm/mm1/game/spells_monsters.h @@ -133,7 +133,7 @@ class SpellsMonsters : public GameLogic { protected: Common::Array _remainingMonsters; LineArray _lines; - int _damage = 0; + int _damage = 0, _displayedDamage = 0; virtual bool canMonsterCast() const = 0; virtual int getMonsterIndex() const = 0; diff --git a/engines/mm/mm1/views/combat.cpp b/engines/mm/mm1/views/combat.cpp index 90128917a6cd..3bcae10595c1 100644 --- a/engines/mm/mm1/views/combat.cpp +++ b/engines/mm/mm1/views/combat.cpp @@ -655,15 +655,6 @@ void Combat::writeMonsterAttack() { writeString(0, 20, line); writeString(0, 21, getAttackString()); - // It's not ideal, but we have to do some final minor damage - // adjustment here after we've written the basic damage the - // character will receive - if (g_globals->_activeSpells._s.power_shield) - _damage /= 2; - - if (_val10 && g_globals->_activeSpells._s.shield) - _damage = MAX((int)_damage - 8, 0); - if (_damage) { // Attacks wake up sleeping characters if (!(c._condition & BAD_CONDITION)) @@ -806,7 +797,7 @@ Common::String Combat::getAttackString() { line1 += Common::String::format(" %s ", STRING["dialogs.combat.and"].c_str()); - if (_damage == 0) { + if (_displayedDamage == 0) { line1 += STRING["dialogs.combat.misses"]; } else { line1 += STRING["dialogs.combat.hit"]; @@ -823,7 +814,7 @@ Common::String Combat::getAttackString() { } line1 += Common::String::format(" %s %d %s", - STRING["dialogs.combat.for"].c_str(), _damage, + STRING["dialogs.combat.for"].c_str(), _displayedDamage, STRING[_damage == 1 ? "dialogs.combat.point" : "dialogs.combat.points"].c_str()); if (line1.size() < 30) { From 2dca8d872888e494c129cde604b966feaa6244e9 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Sun, 5 Feb 2023 11:34:01 -0800 Subject: [PATCH 044/412] MM: MM1: Fix indexing of attack type messages --- devtools/create_mm/files/mm1/strings_en.yml | 30 ++++++++++----------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/devtools/create_mm/files/mm1/strings_en.yml b/devtools/create_mm/files/mm1/strings_en.yml index 22c98afa0cc1..10cd46e8237f 100644 --- a/devtools/create_mm/files/mm1/strings_en.yml +++ b/devtools/create_mm/files/mm1/strings_en.yml @@ -404,21 +404,21 @@ dialogs: 8: "(dead) " wounded: "(wounded) " attack_types: - 0: "attacks" - 1: "fights" - 2: "charges" - 3: "assaults" - 4: "battles" - 5: "stabs at" - 6: "flails at" - 7: "lunges at" - 8: "swings at" - 9: "chops at" - 10: "hacks at" - 11: "thrusts at" - 12: "slashes at" - 13: "strikes at" - 14: "thrashes at" + 1: "attacks" + 2: "fights" + 3: "charges" + 4: "assaults" + 5: "battles" + 6: "stabs at" + 7: "flails at" + 8: "lunges at" + 9: "swings at" + 10: "chops at" + 11: "hacks at" + 12: "thrusts at" + 13: "slashes at" + 14: "strikes at" + 15: "thrashes at" 99: "shoots at" enhdialogs: map: From 97c8746d2e3a889d529eb1a7349c4cce69c49f54 Mon Sep 17 00:00:00 2001 From: Le Philousophe Date: Sun, 5 Feb 2023 20:44:01 +0100 Subject: [PATCH 045/412] BACKENDS: OPENGL: Use a floating point cursor size When scaler shaders are used, cursor size is adapted to scale on the game screen texture and not on the back buffer so the size is scaled twice and is imprecise. Using a float gives more precision without any performance impact as the OpenGL code already expects floats. --- backends/graphics/opengl/opengl-graphics.cpp | 17 ++++++++++------- backends/graphics/opengl/opengl-graphics.h | 4 ++-- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/backends/graphics/opengl/opengl-graphics.cpp b/backends/graphics/opengl/opengl-graphics.cpp index 15c536b7fb7c..19078c46e760 100644 --- a/backends/graphics/opengl/opengl-graphics.cpp +++ b/backends/graphics/opengl/opengl-graphics.cpp @@ -667,9 +667,9 @@ void OpenGLGraphicsManager::updateScreen() { _backBuffer.enableBlend(Framebuffer::kBlendModePremultipliedTransparency); _pipeline->drawTexture(_cursor->getGLTexture(), - _cursorX - _cursorHotspotXScaled + _shakeOffsetScaled.x, - _cursorY - _cursorHotspotYScaled + _shakeOffsetScaled.y, - _cursorWidthScaled, _cursorHeightScaled); + _cursorX - _cursorHotspotXScaled + _shakeOffsetScaled.x, + _cursorY - _cursorHotspotYScaled + _shakeOffsetScaled.y, + _cursorWidthScaled, _cursorHeightScaled); drawCursor = false; // Everything we need to clip has been clipped @@ -1518,11 +1518,14 @@ void OpenGLGraphicsManager::recalculateCursorScaling() { return; } + uint cursorWidth = _cursor->getWidth(); + uint cursorHeight = _cursor->getHeight(); + // By default we use the unscaled versions. _cursorHotspotXScaled = _cursorHotspotX; _cursorHotspotYScaled = _cursorHotspotY; - _cursorWidthScaled = _cursor->getWidth(); - _cursorHeightScaled = _cursor->getHeight(); + _cursorWidthScaled = cursorWidth; + _cursorHeightScaled = cursorHeight; // In case scaling is actually enabled we will scale the cursor according // to the game screen. @@ -1531,10 +1534,10 @@ void OpenGLGraphicsManager::recalculateCursorScaling() { const frac_t screenScaleFactorY = intToFrac(_gameDrawRect.height()) / _gameScreen->getHeight(); _cursorHotspotXScaled = fracToInt(_cursorHotspotXScaled * screenScaleFactorX); - _cursorWidthScaled = fracToInt(_cursorWidthScaled * screenScaleFactorX); + _cursorWidthScaled = fracToDouble(cursorWidth * screenScaleFactorX); _cursorHotspotYScaled = fracToInt(_cursorHotspotYScaled * screenScaleFactorY); - _cursorHeightScaled = fracToInt(_cursorHeightScaled * screenScaleFactorY); + _cursorHeightScaled = fracToDouble(cursorHeight * screenScaleFactorY); } } diff --git a/backends/graphics/opengl/opengl-graphics.h b/backends/graphics/opengl/opengl-graphics.h index 3b27c6e33cf9..4cd3c1f45f7d 100644 --- a/backends/graphics/opengl/opengl-graphics.h +++ b/backends/graphics/opengl/opengl-graphics.h @@ -405,12 +405,12 @@ class OpenGLGraphicsManager : virtual public WindowedGraphicsManager { /** * The width of the cursor in scaled game display area coordinates. */ - uint _cursorWidthScaled; + float _cursorWidthScaled; /** * The height of the cursor in scaled game display area coordinates. */ - uint _cursorHeightScaled; + float _cursorHeightScaled; /** * The key color. From 582bf7c05acb05242645ca5d5cdc6ed14360481f Mon Sep 17 00:00:00 2001 From: Walter Agazzi Date: Sun, 5 Feb 2023 21:00:59 +0100 Subject: [PATCH 046/412] AGS: Add detection for various old games From TRAC reports --- engines/ags/detection_tables.h | 40 ++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/engines/ags/detection_tables.h b/engines/ags/detection_tables.h index 30669afa0ba4..483ccb81901a 100644 --- a/engines/ags/detection_tables.h +++ b/engines/ags/detection_tables.h @@ -370,16 +370,19 @@ const PlainGameDescriptor GAME_NAMES[] = { { "12hoursslave", "12 Hours a Slave" }, { "15minutes", "15 Minutes" }, { "1dayamosquito", "1 day a mosquito" }, + { "2000ways", "2000 Ways To Play Badmington" }, { "2034acaftercanada1", "2034 A.C. (After Canada)" }, { "2034acaftercanada2", "2034 A.C. (After Canada) II" }, { "24hourgame", "The 24 Hour Game" }, { "24hours", "24 Hours" }, { "30minutes", "30 minutes" }, + { "3minfart", "3 Minutes a Fart" }, { "3pigsandawolf", "Three Little Pigs and a Wolf" }, { "46memorylane", "46 Memory Lane" }, { "4lungboy", "4-Lung Boy" }, { "4ofclubs", "4 of Clubs" }, { "5daysastranger", "5 Days A Stranger" }, + { "5dragons", "5 Dragons" }, { "5oclocklock", "5-O'clock Lock" }, { "6174solitaire", "6174 Solitaire" }, { "6daysasacrifice", "6 Days A Sacrifice" }, @@ -463,6 +466,7 @@ const PlainGameDescriptor GAME_NAMES[] = { { "agsmastermind", "AGS Mastermind" }, { "agsmittensshooter", "AGS Mittens Shooter" }, { "agsmoduletester", "AGS Module Tester" }, + { "agstechsupport", "AGS Tech Support Game" }, { "agswerewolf", "AGS Werewolf" }, { "agsyahtzee", "AGS Yahtzee" }, { "agsyahtzee2", "AGS Yahtzee 2" }, @@ -488,6 +492,7 @@ const PlainGameDescriptor GAME_NAMES[] = { { "allgonesoon", "All Gone Soon" }, { "allgonesoon2", "All Gone Soon 2" }, { "allhallowseve", "All Hallows' Eve" }, + { "alloweisland", "Al Lowe's Secret Island" }, { "allpigs", "All Pigs Deserve To Burn In Hell" }, { "allthewaydown", "All The Way Down" }, { "alluminum", "P.I. Al Luminum: Haunted House" }, @@ -592,6 +597,7 @@ const PlainGameDescriptor GAME_NAMES[] = { { "bakeoffitalia", "Bake Off Italia - The Graphic Adventure" }, { "baldysadventure", "Baldy's Adventure" }, { "balloonface", "Balloon Face" }, + { "balls", "Balls" }, { "baltazarthefamiliar", "Baltazar the Familiar" }, { "bananaman", "Banana Man" }, { "bananaracer", "Banana Racer" }, @@ -617,6 +623,7 @@ const PlainGameDescriptor GAME_NAMES[] = { { "barrunner", "Ed Watts: Bar Runner" }, { "bartolomeo", "Bartolomeo, misled by circumstances, learns that appearances can be deceptive" }, { "bartsquestfortv", "Bart's Quest For TV" }, + { "basedon", "Basedon - The Game" }, { "battlewarriorsrt", "Battle Warriors: Rovendale Tactics" }, { "bbcscreensaver", "Background Blitz Collection Screensaver" }, { "bcremake", "Black Cauldron Remake" }, @@ -627,6 +634,7 @@ const PlainGameDescriptor GAME_NAMES[] = { { "beasts", "Beasts" }, { "beatthebuzzer", "Beat the Buzzer" }, { "beautiesandbeasts", "Beauties and Beasts" }, + { "beforethedarkcrystal", "Before the Dark Crystal" }, { "beforethedarkcrystal2", "Before the Dark Crystal II" }, { "beforeww2", "Before WW2" }, { "bellyofthebeast", "Belly of the Beast" }, @@ -1304,8 +1312,9 @@ const PlainGameDescriptor GAME_NAMES[] = { { "hawkmanor", "Terror Within Hawk Manor" }, { "headbangerheaven", "Headbanger's Heaven - A Rock & Roll Adventure" }, { "headoverheels", "Head over Heels" }, - { "heartofabraxas", "Heart of Abraxas" }, { "heartland", "Heartland" }, + { "heartofabraxas", "Heart of Abraxas" }, + { "heartpart", "A Heart between Parts" }, { "heatwave", "Heatwave" }, { "heavenhell", "Heaven, Hell and the Neitherworld" }, { "heavymetalnannulf", "Heavy Metal Nannulf: The Strange Stage" }, @@ -1517,6 +1526,7 @@ const PlainGameDescriptor GAME_NAMES[] = { { "kiselyova", "Kiselyova Unleashed!" }, { "kittenadv", "Kitten Adventures" }, { "kittyquest", "Kitty Quest" }, + { "knightpursuit", "A Knight's Pursuit" }, { "knightquestforgoldenring", "Knight Quest for the Golden Ring" }, { "knightsquest3", "Knight's Quest III - Tides of Merania" }, { "knightsquest4", "Knight's Quest IV - Here Today, Gone to Yesterday" }, @@ -1581,6 +1591,7 @@ const PlainGameDescriptor GAME_NAMES[] = { { "lifeinabox", "Life in a Box" }, { "lifeofdduck", "Life of D. Duck" }, { "lifeofdduck2", "Life of D. Duck II" }, + { "lifeworthlosing", "A Life Worth Losing" }, { "liftreasureofthetanones", "Lif and the Treasure of the Tanones" }, { "lightcycles", "AGS Cycles" }, { "lightningmaster", "Lightning Master" }, @@ -1639,6 +1650,7 @@ const PlainGameDescriptor GAME_NAMES[] = { { "lostinthenightmare2", "Lost In The Nightmare 2: Unforgettable Memories" }, { "lostinthewoods", "Lost In The Woods" }, { "lotto", "Lottó" }, + { "lowequest", "Lowe Quest" }, { "lucasmaniac", "Lucas Maniac!" }, { "lucasmendoza", "Lucas Mendoza, Amateur Detective: The Searchers of The Beginning" }, { "lucidlucy", "LUCID LUCY" }, @@ -2191,6 +2203,7 @@ const PlainGameDescriptor GAME_NAMES[] = { { "pimpinonparakuss", "Pimpin On Parakuss IV" }, { "pinkcult", "Rex and Sissi in Pink Cult" }, { "pinksky", "Pink Sky" }, + { "pinkyalien", "Pinky the Silly Alien" }, { "piratefry2", "Pirate Fry 2: The Hand of Anturus" }, { "piratefry3", "Pirate Fry 3: The Isle of the Dead" }, { "pirates", "Pirates!" }, @@ -2378,6 +2391,7 @@ const PlainGameDescriptor GAME_NAMES[] = { { "rockabillykid", "Rockabilly Kid" }, { "rockatruestory", "Rock - A True Story" }, { "rockburgerstreehouses", "Rock Burgers & Tree Houses" }, + { "rockpaperscissors", "AGS Rock, Paper, Scissors" }, { "rockpaperscissors2", "Rock, Paper, Scissors! Reboot" }, { "rockrockrock", "Rock Rock Rock" }, { "rocktravis", "Rock Travis - Camilla's case" }, @@ -3952,6 +3966,7 @@ const AGSGameDescription GAME_DESCRIPTIONS[] = { DEMO_ENTRY_EN("afrojones", "afrojones.exe", "f3a13b2d6c2e0fe04c6f466062920e23", 4739799), DEMO_ENTRY_EN("agscolosseum", "AGS coliseum.exe", "6d65fa76ae212c9bbfa868698f47e921", 86449242), DEMO_ENTRY_EN("agsfootballer", "AgsFootballer.exe", "a01a9639ce30bdcd5bf82e528b51fa06", 11169151), + DEMO_ENTRY_EN("agsfootballer", "AgsFootballer.exe", "a01a9639ce30bdcd5bf82e528b51fa06", 11169923), //v1.0 DEMO_ENTRY_EN("agsmoduletester", "v1.0 source.exe", "95b7dd55f6e15c8a2118856ed9fe8ff9", 2020344), DEMO_ENTRY_EN("alemmo", "al-emmo.exe", "9661b29821fdc7f93d286f25c195fc22", 8932837), // Steam DEMO_ENTRY_EN("alemmo", "emmo_demo.exe", "2fb17c4382f2f54ef6d040b6493fec4b", 8943213), // Official website @@ -4394,7 +4409,9 @@ const AGSGameDescription GAME_DESCRIPTIONS[] = { GAME_ENTRY_EN("15minutes", "15 minutes.exe", "615e73fc1874e92d60a1996c2330ea36", 24136635), // v1.01 GAME_ENTRY_EN_PLATFORM("15minutes", "15 minutes.exe", "615e73fc1874e92d60a1996c2330ea36", 24124810, "MAGS"), // v1.0 GAME_ENTRY_EN("30minutes", "30minutes.exe", "18f5fd85de78efca16c7bafce54e3f63", 17930417), + GAME_ENTRY_EN("3minfart", "3DAF.exe", "e88fd6a23a5e498d7b0d50e3bb914085", 745733), GAME_ENTRY_EN("1dayamosquito", "mosquito.exe", "465f972675db2da6040518221af5b0ba", 2178983), + GAME_ENTRY_EN("2000ways", "hourgame.exe", "4d17844029d8910fbaae1bdc99e250f2", 1707319), GAME_ENTRY_EN("2034acaftercanada1", "MAGS_01_13.exe", "1280ba7c269a68a9505871516319db0c", 14123278), GAME_ENTRY_EN("2034acaftercanada2", "2034 ac ii.exe", "1280ba7c269a68a9505871516319db0c", 35207006), GAME_ENTRY_EN("24hours", "24.exe", "f120690b506dd63cd7d1112ea6af2f77", 1932370), @@ -4406,6 +4423,7 @@ const AGSGameDescription GAME_DESCRIPTIONS[] = { GAME_ENTRY_EN("5daysastranger", "5days.exe", "e88fd6a23a5e498d7b0d50e3bb914085", 4440143), // v1.3 GAME_ENTRY_EN_PLATFORM("5daysastranger", "5days.exe", "3b7cceb3e4bdb031dc5d8f290936e94b", 4614351, "Special Edition"), GAME_ENTRY_PLATFORM("5daysastranger", "5daysorig.exe", "3b7cceb3e4bdb031dc5d8f290936e94b", 4593115, "Alt/Multilanguage"), + GAME_ENTRY_EN("5dragons", "5drag.exe", "e80586fdc2db32f65658b235d8cbc159", 4741670), GAME_ENTRY_EN("5oclocklock", "dadgame.exe", "3018c5443291aec823bc63342ce4c58b", 6073887), GAME_ENTRY_EN("6174solitaire", "Game6174.exe", "01534b6a57fcdb1a57486f5c24120124", 5863226), // Windows GAME_ENTRY_EN("6174solitaire", "Game6174.ags", "fedabeeb5a70acafd4f46b73238c9ec6", 2401062), // Linux @@ -4492,6 +4510,7 @@ const AGSGameDescription GAME_DESCRIPTIONS[] = { GAME_ENTRY_EN("agsmagus", "AGS Wizard.exe", "434c43a5e1ba2a11c1bde723ffeae719", 21177588), GAME_ENTRY_EN("agsmastermind", "AGS Mastermind.exe", "519c0d37ab893d95f5add495355e460c", 30196465), GAME_ENTRY_EN("agsmittensshooter", "clex.exe", "e88fd6a23a5e498d7b0d50e3bb914085", 1381575), + GAME_ENTRY_EN("agstechsupport", "agsgame.exe", "88cf59aad15ca331ab0f854e16c84df3", 1229972), GAME_ENTRY_EN("agswerewolf", "mags0722.exe", "0e4ddc9893796a9f39395d0e0220a37b", 6214215), GAME_ENTRY_EN("agswerewolf", "mags0722.ags", "0f36bc83671ce002addf7bfa2d748747", 3073587), GAME_ENTRY_EN("agsyahtzee", "ags yathzee.exe", "434c43a5e1ba2a11c1bde723ffeae719", 37295758), @@ -4522,6 +4541,7 @@ const AGSGameDescription GAME_DESCRIPTIONS[] = { GAME_ENTRY_EN("alientimezone", "atz.exe", "0710e2ec71042617f565c01824f0cf3c", 2911858), GAME_ENTRY_EN("allgonesoon", "All_Gone_Soon.exe", "618d7dce9631229b4579340b964c6810", 8858991), GAME_ENTRY_EN("allgonesoon2", "AGS2.exe", "618d7dce9631229b4579340b964c6810", 11140718), + GAME_ENTRY_EN("alloweisland", "asland.exe", "88cf59aad15ca331ab0f854e16c84df3", 1281427), GAME_ENTRY_EN("allpigs", "All pigs deserve to burn in hell.exe", "973f6b65820ca1f4e19704a49be99d76", 20836147), GAME_ENTRY_EN("alluminum", "mags_october.exe", "f120690b506dd63cd7d1112ea6af2f77", 1772481), GAME_ENTRY("almostblue", "Almost Blue.exe", "2cb5f4d0914d1b1f0638c65da6689050", 231366019), // Eng-Ita @@ -4580,7 +4600,8 @@ const AGSGameDescription GAME_DESCRIPTIONS[] = { GAME_ENTRY_EN("apprentice2", "app2.exe", "465f972675db2da6040518221af5b0ba", 34159191), GAME_ENTRY_EN("aprofoundjourney", "apj.exe", "e88fd6a23a5e498d7b0d50e3bb914085", 920131), GAME_ENTRY_EN("apunkwithwheels", "A punk with wheels.exe", "d90cd956022235ed9b272fb0b2ab5792", 17924043), - GAME_ENTRY_EN("aractaur", "aractaur.exe", "aecd482222ff54206e43a029b5f0b170", 5318963), + GAME_ENTRY_EN_PLATFORM("aractaur", "aractaur.exe", "aecd482222ff54206e43a029b5f0b170", 5318963, "MAGS"), + GAME_ENTRY_EN("aractaur", "aractaur.exe", "6b4ceb9e327ac99479c08d825461f4cb", 5543430), GAME_ENTRY_EN("araindogstory", "Raindog.exe", "09cf8b451781575fa3ba1a0e31f5fc66", 96888573), GAME_ENTRY_EN("archeos", "archeos.exe", "2ff048659aaefd20d342db6428a5f1a0", 6659974), GAME_ENTRY_EN("archeos", "archeos.exe", "2ff048659aaefd20d342db6428a5f1a0", 6661410), @@ -4652,6 +4673,7 @@ const AGSGameDescription GAME_DESCRIPTIONS[] = { GAME_ENTRY_EN("baltazarthefamiliar", "baltazar.exe", "9cb3c8dc7a8ab9c44815955696be2677", 2867294), GAME_ENTRY_EN_PLATFORM("baltazarthefamiliar", "baltazar.exe", "9cb3c8dc7a8ab9c44815955696be2677", 2749185, "OROW"), GAME_ENTRY_EN("balloonface", "hg.exe", "0710e2ec71042617f565c01824f0cf3c", 2189438), + GAME_ENTRY_EN("balls", "Balls.exe", "0710e2ec71042617f565c01824f0cf3c", 765814), GAME_ENTRY_EN("bananaracer", "bananaracer.exe", "e93f9dfa8405f1ca9f881d160ab31dc2", 10452233), GAME_ENTRY_EN("bananaracer", "bananaracer.exe", "e93f9dfa8405f1ca9f881d160ab31dc2", 10454173), GAME_ENTRY_EN("barahir", "Barahir.exe", "5677656386de765e72b7400f1e631eed", 40520601), // v1.2 Windows @@ -4662,13 +4684,18 @@ const AGSGameDescription GAME_DESCRIPTIONS[] = { GAME_ENTRY_EN("barnrunner1p1", "eclair 1.exe", "f3a13b2d6c2e0fe04c6f466062920e23", 13202017), GAME_ENTRY_EN("barnrunner1p2", "eclair 2.exe", "465f972675db2da6040518221af5b0ba", 34193929), GAME_ENTRY_EN("barnrunner3", "Mini Game 3.exe", "465f972675db2da6040518221af5b0ba", 3455484), + GAME_ENTRY_EN("barnrunner3", "Barn Runner 3.exe", "465f972675db2da6040518221af5b0ba", 3452579), // v2.0 GAME_ENTRY_EN("barnrunner4", "Barn Runner 4.exe", "465f972675db2da6040518221af5b0ba", 4954262), GAME_ENTRY_EN("barnrunner4", "Mini Game 4.exe", "465f972675db2da6040518221af5b0ba", 4954264), GAME_ENTRY_EN("barnrunner5p1", "barn runner 5-1.exe", "6cddccb3744ec5c6af7c398fb7b3b11c", 104073543), + GAME_ENTRY_EN("barnrunner5p1", "barn runner 5-1.exe", "6cddccb3744ec5c6af7c398fb7b3b11c", 104071015), // v1.1 GAME_ENTRY_EN("barnrunner5p2", "barn runner 5-2.exe", "6cddccb3744ec5c6af7c398fb7b3b11c", 200879890), + GAME_ENTRY_EN("barnrunner5p2", "barn runner 5-2.exe", "6cddccb3744ec5c6af7c398fb7b3b11c", 200696384), // v1.2 GAME_ENTRY_EN("barnrunner5p3", "Barn Runner 5-3.exe", "6cddccb3744ec5c6af7c398fb7b3b11c", 236158866), + GAME_ENTRY_EN("barnrunner5p3", "Barn Runner 5-3.exe", "6cddccb3744ec5c6af7c398fb7b3b11c", 236159803), // v1.2 GAME_ENTRY_EN("barnrunnerbake1", "BR Bake Sale 1.exe", "18b284c22010850f79bc5c20054a70c4", 29716432), GAME_ENTRY_EN("barnrunnerhall1", "BR Halloween 1.exe", "18b284c22010850f79bc5c20054a70c4", 52243988), + GAME_ENTRY_EN("barnrunnerhall1", "BR Halloween 1.exe", "18b284c22010850f79bc5c20054a70c4", 52252562), //v1.3 GAME_ENTRY_EN("barnrunnervalentine1", "BR Valentine 1.exe", "6cddccb3744ec5c6af7c398fb7b3b11c", 101774857), GAME_ENTRY_EN("barnrunnervn1", "BR VN1.exe", "809418706c429cee5d88e8d483c906cc", 26857313), GAME_ENTRY_EN("barnrunnerxmas0", "BR Xmas 0.exe", "615e806856b7730afadf1fea9a756b70", 13689876), @@ -4679,6 +4706,7 @@ const AGSGameDescription GAME_DESCRIPTIONS[] = { GAME_ENTRY_EN("barrunner", "Bar Runner.exe", "615e73fc1874e92d60a1996c2330ea36", 3642405), //v1.1 GAME_ENTRY_EN("bartolomeo", "Bartolomeo.exe", "f604f7f3a12da5d3bcf7a7814a14e43b", 42261079), GAME_ENTRY_EN("bartsquestfortv", "simpsons.exe", "0500aacb6c176d47ac0f8158f055db83", 794013), + GAME_ENTRY_EN("basedon", "basedon.exe", "0500aacb6c176d47ac0f8158f055db83", 5775388), GAME_ENTRY_EN("bbcscreensaver", "BBC-Screensaver.exe", "0e6d6f3c19f5ca250b7b7ee03cdb2083", 131195371), GAME_ENTRY_EN("bcremake", "bc.exe", "0710e2ec71042617f565c01824f0cf3c", 7683255), GAME_ENTRY_EN("beacon", "beacon.exe", "af0d268193a9220891e983d03141ec58", 24671086), @@ -4691,6 +4719,7 @@ const AGSGameDescription GAME_DESCRIPTIONS[] = { GAME_ENTRY_EN("beatthebuzzer", "Beat the Buzzer.exe", "4d5d25446373d4df71c6bda77a15230a", 227179876), // v1.1 Post-Jam GAME_ENTRY_EN_PLATFORM("beautiesandbeasts", "beautiesandbeasts.exe", "089fab88e6e1075a2f5b271f6f5b3c57", 6506966, "OROW"), //v1.00 GAME_ENTRY_EN("beautiesandbeasts", "beautiesandbeasts.exe", "089fab88e6e1075a2f5b271f6f5b3c57", 6507202), //v1.01 + GAME_ENTRY("beforethedarkcrystal", "DarkCrystal.exe", "f120690b506dd63cd7d1112ea6af2f77", 15194282), // En-Fr GAME_ENTRY("beforethedarkcrystal2", "Before the Dark Crystal II.exe", "23a67b6de10ec35e9f5a4dfc7d928222", 59569723), // En-Fr GAME_ENTRY_EN("bellyofthebeast", "Belly of the beast.exe", "9f8a9d74c09f188af9af3e263f8b59bc", 22461502), // Windows GAME_ENTRY_EN("bellyofthebeast", "Belly of the beast.ags", "5b086e038c7bf4eada977f52f1d22cd7", 19425322), // Linux @@ -5476,6 +5505,7 @@ const AGSGameDescription GAME_DESCRIPTIONS[] = { GAME_ENTRY_EN_PLATFORM("heartland", "Heartland.exe", "0829f8e184ed6a4bf36b14ba42003a67", 6702004, "Deluxe"), GAME_ENTRY_EN_PLATFORM("heartland", "Heartland.exe", "0829f8e184ed6a4bf36b14ba42003a67", 6701875, "Deluxe"), // v1.1 GAME_ENTRY_EN("heartofabraxas", "orowgame.exe", "0710e2ec71042617f565c01824f0cf3c", 15632750), + GAME_ENTRY_EN("heartpart", "HeartPart.exe", "e257b5a3b300568570c4af5e71b20e88", 3565232), GAME_ENTRY_EN("heatwave", "Heatwave.exe", "e2f7df57d111e57e3cf1e229088c6947", 3638644), GAME_ENTRY_EN("heavenhell", "Limbo Adventure.exe", "9ecb923d5169ded48d5fd2c6ed4befa4", 31138864), GAME_ENTRY_EN_PLATFORM("heavenhell", "Limbo Adventure.exe", "7c10efb8990fb48ded51fbcd88a6bf17", 30800724, "AKA Limbo - The Adventure Game"), @@ -5728,6 +5758,7 @@ const AGSGameDescription GAME_DESCRIPTIONS[] = { GAME_ENTRY_EN("kiselyova", "innah.exe", "0710e2ec71042617f565c01824f0cf3c", 1236053), GAME_ENTRY_EN("kittenadv", "Kitten.exe", "9973fbc73cce23867246d3a5e3c86d01", 5423637), GAME_ENTRY_EN("kittyquest", "multiverbtemplate.exe", "6e861b1f476ff7cdf036082abb271329", 78650122), + GAME_ENTRY_EN("knightpursuit", "Knight.exe", "0710e2ec71042617f565c01824f0cf3c", 1613627), GAME_ENTRY_EN("knightquestforgoldenring", "KQuestGoldRing.exe", "f120690b506dd63cd7d1112ea6af2f77", 2582542), GAME_ENTRY_EN("knightsquest3", "KQ3TOM.exe", "0710e2ec71042617f565c01824f0cf3c", 8405513), //v1.0 GAME_ENTRY_EN("knightsquest3", "KQ3TOM.exe", "0710e2ec71042617f565c01824f0cf3c", 8408641), @@ -5812,6 +5843,7 @@ const AGSGameDescription GAME_DESCRIPTIONS[] = { GAME_ENTRY_EN("lifeinabox", "box.exe", "0500aacb6c176d47ac0f8158f055db83", 890794), GAME_ENTRY_EN("lifeofdduck", "D Duck.exe", "0710e2ec71042617f565c01824f0cf3c", 49461615), GAME_ENTRY_EN("lifeofdduck2", "D. Duck II.exe", "6cddccb3744ec5c6af7c398fb7b3b11c", 135923689), + GAME_ENTRY_EN("lifeworthlosing", "lwl.exe", "a524cbb1c51589903c4043b98917f1d9", 89591505), GAME_ENTRY_EN("liftreasureofthetanones", "Lif.exe", "18b284c22010850f79bc5c20054a70c4", 3946641), GAME_ENTRY_EN("lightcycles", "LightCycles.exe", "495d45fb8adfd49690ae3b97921feec6", 3415108), GAME_ENTRY_EN("lightningmaster", "Master.exe", "27343924ddad3be0b97bdcaa71858b1b", 231301393), @@ -5879,6 +5911,7 @@ const AGSGameDescription GAME_DESCRIPTIONS[] = { GAME_ENTRY_EN("lostinthewoods", "LITW.exe", "00328f4f1e7729144483107b96b11df8", 55203461), GAME_ENTRY_PLATFORM("lotto", "Lott.exe", "0564de07d3fd5c16e6947a647061913c", 6585796, "Icelandic"), GAME_ENTRY_PLATFORM("lotto", "Lott.ags", "1578011383e302e787d3ff906776483f", 3553200, "Icelandic"), + GAME_ENTRY_EN("lowequest", "lowe.exe", "97d700529f5cc826f230c27acf81adfd", 1046425), GAME_ENTRY("lucasmaniac", "LucasManiac !.exe", "f120690b506dd63cd7d1112ea6af2f77", 28361487), // En-Fr GAME_ENTRY_EN("lucidlucy", "LUCID LUCY.exe", "655363c390c7ae7225c237108edf50b7", 182038828), GAME_ENTRY_EN("lucylavender", "Lucy.exe", "c87aa6377abc18c1a1b2968ae6db08eb", 7944054), @@ -6489,6 +6522,7 @@ const AGSGameDescription GAME_DESCRIPTIONS[] = { GAME_ENTRY_EN("pimpinonparakuss", "Squest2.exe", "f3a13b2d6c2e0fe04c6f466062920e23", 3717277), GAME_ENTRY("pinkcult", "Pink Cult.exe", "615e73fc1874e92d60a1996c2330ea36", 2731074), // En-Fr GAME_ENTRY_EN("pinksky", "Pink_Sky.exe", "79077a68e53562082494933a21e2714f", 43597805), + GAME_ENTRY_EN("pinkyalien", "alien.exe", "ba27688a81119b49a550f3bbd8d6d003", 778228), GAME_ENTRY_EN("piratefry2", "FryTworedo.exe", "f3a13b2d6c2e0fe04c6f466062920e23", 8492745), GAME_ENTRY_EN("piratefry3", "tryout.exe", "f3a13b2d6c2e0fe04c6f466062920e23", 2318881), GAME_ENTRY_EN("pirates", "Pirates!.exe", "0564de07d3fd5c16e6947a647061913c", 81574110), @@ -6698,6 +6732,7 @@ const AGSGameDescription GAME_DESCRIPTIONS[] = { GAME_ENTRY_EN("rockabillykid", "Rockabilly Kid.exe", "ff3358d8f2726d544aadfde4f1ec8407", 2650305), GAME_ENTRY_EN("rockatruestory", "RON-Rock.exe", "6cddccb3744ec5c6af7c398fb7b3b11c", 3917056), GAME_ENTRY_EN("rockburgerstreehouses", "RBTH.exe", "88cf59aad15ca331ab0f854e16c84df3", 1876674), + GAME_ENTRY_EN("rockpaperscissors", "Rock, Paper, Scissors.exe", "615e73fc1874e92d60a1996c2330ea36", 2030667), GAME_ENTRY_EN("rockpaperscissors2", "Rock, Paper, Scissors 2.exe", "89a94326c8afd9e0234e269bd7330130", 2926218), GAME_ENTRY_EN("rockrockrock", "rrr.exe", "7dd36aa863ed40ede1b09ae505e478cc", 9362761), GAME_ENTRY_EN("rocktravis", "rock travis - camilla's case.exe", "17009da9820f5aa86d0588023d497db8", 126975468), @@ -6743,6 +6778,7 @@ const AGSGameDescription GAME_DESCRIPTIONS[] = { GAME_ENTRY_LANG("sandmen", "sandmen.exe", "0b7529a76f38283d6e850b8d56526fc1", 3578745, Common::DE_DEU), GAME_ENTRY_EN("santaclausdown", "scdown.exe", "f120690b506dd63cd7d1112ea6af2f77", 14385095), GAME_ENTRY_EN("santaflight", "A Flight To Remember.exe", "2569c8f271dc356e32483d40ee16b3e9", 112461458), + GAME_ENTRY_EN_PLATFORM("santaflight", "A Flight To Remember Remastered.exe", "5ba6c10d5b499a1d0fef84d0947a52d5", 123138210, "Remastered"), GAME_ENTRY_EN("santaorphanage", "Santa and the orphanage.exe", "099a8b752cba39bb76552e94197edbf4", 163644553), GAME_ENTRY_EN("santaquest", "Santaquest.exe", "0564de07d3fd5c16e6947a647061913c", 5318615), GAME_ENTRY_EN("santassidekick", "Xmas.exe", "0710e2ec71042617f565c01824f0cf3c", 1921077), From dea9cdb37a1befc29e50d2ba2246349a6e52b0a9 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Sun, 5 Feb 2023 11:36:39 -0800 Subject: [PATCH 047/412] MM: MM1: Combat field renaming --- engines/mm/mm1/game/combat.cpp | 14 +++++++------- engines/mm/mm1/game/combat.h | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/engines/mm/mm1/game/combat.cpp b/engines/mm/mm1/game/combat.cpp index 5c12f4df4516..8a150b2d4d33 100644 --- a/engines/mm/mm1/game/combat.cpp +++ b/engines/mm/mm1/game/combat.cpp @@ -54,7 +54,7 @@ void Combat::clear() { _val1 = 0; _val6 = _val7 = 0; _partyIndex = _val9 = 0; - _val10 = _destCharCtr = 0; + _monsterShootingCtr = _destCharCtr = 0; _activeMonsterNum = 0; _destAC = 0; _numberOfTimes = 0; @@ -720,7 +720,7 @@ void Combat::removeDeadMonsters() { } void Combat::checkParty() { - _val10 = 0; + _monsterShootingCtr = 0; if (g_globals->_party.checkPartyIncapacitated()) return; @@ -912,7 +912,7 @@ void Combat::updateMonsterStatus() { bool Combat::monsterTouch(Common::String &line) { line.clear(); - if (_val10 || !_monsterP->_bonusOnTouch) + if (_monsterShootingCtr || !_monsterP->_bonusOnTouch) return false; if (_monsterP->_bonusOnTouch & 0x80) { proc9(); @@ -1473,13 +1473,13 @@ void Combat::monsterAttackRandom() { size_t monsterNameSize = enc._monsterList[getMonsterIndex()]._name.size() + 1; _monsterAttackStyle = getRandomNumber((monsterNameSize < 13) ? 15 : 11); - _val10 = 0; + _monsterShootingCtr = 0; monsterAttackInner(); } void Combat::monsterAttackShooting() { - ++_val10; + ++_monsterShootingCtr; _monsterAttackStyle = 99; // shooting monsterAttackInner(); @@ -1497,7 +1497,7 @@ void Combat::monsterAttackInner() { if (c._condition & (ASLEEP | BLINDED | PARALYZED)) _attackerLevel += 5; - if (_val10) { + if (_monsterShootingCtr) { _attackAttr2._base = _monsterP->_specialAbility & 0x7f; _numberOfTimes = 1; @@ -1524,7 +1524,7 @@ void Combat::monsterAttackInner() { if (g_globals->_activeSpells._s.power_shield) _damage /= 2; - if (_val10 && g_globals->_activeSpells._s.shield) + if (_monsterShootingCtr && g_globals->_activeSpells._s.shield) _damage = MAX((int)_damage - 8, 0); // Display the result diff --git a/engines/mm/mm1/game/combat.h b/engines/mm/mm1/game/combat.h index d5e85d9bb084..5d7ee271b426 100644 --- a/engines/mm/mm1/game/combat.h +++ b/engines/mm/mm1/game/combat.h @@ -44,7 +44,7 @@ class Combat : public MonsterTouch { int _monsterIndex, _currentChar; bool _allowFight, _allowShoot, _allowCast, _allowAttack; byte _val6, _val7; - int _partyIndex, _val9, _val10; + int _partyIndex, _val9, _monsterShootingCtr; int _activeMonsterNum; int _destCharCtr; int _destAC; From 46f69af4a56117f1193b103ae82fec7d688abc47 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Sun, 5 Feb 2023 12:10:47 -0800 Subject: [PATCH 048/412] MM: MM1: Fix QuickRef in combat to show remaining comobat party --- engines/mm/mm1/views/combat.cpp | 1 - engines/mm/mm1/views/quick_ref.cpp | 29 ++++++++++++++++++++++++----- engines/mm/mm1/views/quick_ref.h | 3 +++ 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/engines/mm/mm1/views/combat.cpp b/engines/mm/mm1/views/combat.cpp index 3bcae10595c1..ae0a58f5781d 100644 --- a/engines/mm/mm1/views/combat.cpp +++ b/engines/mm/mm1/views/combat.cpp @@ -343,7 +343,6 @@ bool Combat::msgAction(const ActionMessage &msg) { } break; default: - // TODO: Character and quickref views break; } diff --git a/engines/mm/mm1/views/quick_ref.cpp b/engines/mm/mm1/views/quick_ref.cpp index 0fa678cf4326..41d9bdaea08d 100644 --- a/engines/mm/mm1/views/quick_ref.cpp +++ b/engines/mm/mm1/views/quick_ref.cpp @@ -41,8 +41,12 @@ void QuickRef::draw() { writeString(STRING["dialogs.quick_ref.title"]); // Print list of characters, hit pts, spell pts, and ac - for (uint idx = 0; idx < g_globals->_party.size(); ++idx) { - Character &c = g_globals->_party[idx]; + size_t partySize = getPartySize(); + bool inCombat = isInCombat(); + + for (uint idx = 0; idx < partySize; ++idx) { + Character &c = inCombat ? *g_globals->_combatParty[idx] : + g_globals->_party[idx]; // Number and name writeNumber(0, 2 + idx, idx + 1); @@ -108,9 +112,14 @@ bool QuickRef::msgAction(const ActionMessage &msg) { case KEYBIND_VIEW_PARTY5: case KEYBIND_VIEW_PARTY6: { uint charNum = msg._action - KEYBIND_VIEW_PARTY1; - if (charNum < g_globals->_party.size()) { - g_globals->_currCharacter = &g_globals->_party[charNum]; - replaceView("CharacterInfo"); + if (charNum < getPartySize()) { + if (isInCombat()) { + g_globals->_currCharacter = g_globals->_combatParty[charNum]; + replaceView("CharacterViewCombat"); + } else { + g_globals->_currCharacter = &g_globals->_party[charNum]; + replaceView("CharacterInfo"); + } } break; } @@ -121,6 +130,16 @@ bool QuickRef::msgAction(const ActionMessage &msg) { return false; } +bool QuickRef::isInCombat() const { + return g_events->isPresent("Combat"); +} + +size_t QuickRef::getPartySize() const { + bool inCombat = isInCombat(); + return inCombat ? g_globals->_combatParty.size() : + g_globals->_party.size(); +} + } // namespace Views } // namespace MM1 } // namespace MM diff --git a/engines/mm/mm1/views/quick_ref.h b/engines/mm/mm1/views/quick_ref.h index 85d3519c85ef..3bf01603abca 100644 --- a/engines/mm/mm1/views/quick_ref.h +++ b/engines/mm/mm1/views/quick_ref.h @@ -32,6 +32,9 @@ namespace Views { * Quick reference list of all the characters. */ class QuickRef : public CharacterBase { +private: + bool isInCombat() const; + size_t getPartySize() const; public: QuickRef() : CharacterBase("QuickRef") {} virtual ~QuickRef() {} From 4e6c72b975b9d627e3d48a908b0dd111b404937b Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sun, 7 Nov 2021 09:33:18 +0100 Subject: [PATCH 049/412] EFH: Add skeleton engine --- engines/efh/configure.engine | 3 + engines/efh/detection.cpp | 80 ++++++++++++++ engines/efh/detection.h | 42 ++++++++ engines/efh/efh.cpp | 105 ++++++++++++++++++ engines/efh/efh.h | 104 ++++++++++++++++++ engines/efh/metaengine.cpp | 204 +++++++++++++++++++++++++++++++++++ engines/efh/module.mk | 19 ++++ 7 files changed, 557 insertions(+) create mode 100644 engines/efh/configure.engine create mode 100644 engines/efh/detection.cpp create mode 100644 engines/efh/detection.h create mode 100644 engines/efh/efh.cpp create mode 100644 engines/efh/efh.h create mode 100644 engines/efh/metaengine.cpp create mode 100644 engines/efh/module.mk diff --git a/engines/efh/configure.engine b/engines/efh/configure.engine new file mode 100644 index 000000000000..523cdfaa00c2 --- /dev/null +++ b/engines/efh/configure.engine @@ -0,0 +1,3 @@ +# This file is included from the main "configure" script +# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] +add_engine efh "Escape From Hell" no diff --git a/engines/efh/detection.cpp b/engines/efh/detection.cpp new file mode 100644 index 000000000000..7f570bd78e0a --- /dev/null +++ b/engines/efh/detection.cpp @@ -0,0 +1,80 @@ +/* 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "base/plugins.h" +#include "engines/advancedDetector.h" +#include "common/textconsole.h" + +#include "efh/detection.h" + +namespace Efh { + +static const PlainGameDescriptor efhGames[] = { + // Games + {"efh", "Escape From Hell"}, + {nullptr, nullptr} +}; + +static const EfhGameDescription gameDescriptions[] = { + + // Escape From Hell English - Unpacked version + { + {"efh", nullptr, AD_ENTRY1s("escape.exe", "2702f8f713e113a853a925d29aecc709", 147312), + Common::EN_ANY, + Common::kPlatformDOS, + ADGF_UNSTABLE, + GUIO0() + }, + kGameTypeEfh + }, + // Escape From Hell English + { + {"efh", nullptr, AD_ENTRY1s("escape.exe", "1ca4ae3f2ea66c30d1ef3e257a86cd05", 141487), + Common::EN_ANY, + Common::kPlatformDOS, + ADGF_UNSTABLE, + GUIO0()}, + kGameTypeEfh}, + {AD_TABLE_END_MARKER, kGameTypeNone} +}; + +class EfhMetaEngineDetection : public AdvancedMetaEngineDetection { +public: + EfhMetaEngineDetection() : AdvancedMetaEngineDetection(gameDescriptions, sizeof(EfhGameDescription), efhGames) { + } + + const char *getEngineId() const override { + return "efh"; + } + + const char *getName() const override { + return "Efh"; + } + + const char *getOriginalCopyright() const override { + return "Escape From Hell (C) Electronic Arts, 1990"; + } +}; + +} // End of namespace efh + +REGISTER_PLUGIN_STATIC(EFH_DETECTION, PLUGIN_TYPE_ENGINE_DETECTION, Efh::EfhMetaEngineDetection); diff --git a/engines/efh/detection.h b/engines/efh/detection.h new file mode 100644 index 000000000000..9c4a40452b83 --- /dev/null +++ b/engines/efh/detection.h @@ -0,0 +1,42 @@ +/* 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef EFH_DETECTION_H +#define EFH_DETECTION_H + +#include "engines/advancedDetector.h" + +namespace Efh { + +enum GameType { + kGameTypeNone = 0, + kGameTypeEfh +}; + +struct EfhGameDescription { + ADGameDescription desc; + GameType gameType; +}; + +} // End of namespace Efh + +#endif // EFH_DETECTION_H diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp new file mode 100644 index 000000000000..3747ec438e47 --- /dev/null +++ b/engines/efh/efh.cpp @@ -0,0 +1,105 @@ +/* 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/system.h" +#include "common/random.h" +#include "common/error.h" +#include "common/config-manager.h" +#include "common/events.h" +#include "engines/util.h" +#include "graphics/cursorman.h" + +#include "efh/efh.h" +#include "engines/util.h" + +namespace Efh { + +EfhEngine *EfhEngine::s_Engine = 0; + +EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst), _gameDescription(gd) { + _system = syst; + _rnd = nullptr; + + _shouldQuit = false; + _eventMan = nullptr; + _lastTime = 0; + _gameType = kGameTypeNone; + _platform = Common::kPlatformUnknown; + _mainSurface = nullptr; +} + +EfhEngine::~EfhEngine() { + delete _rnd; +} + +bool EfhEngine::hasFeature(EngineFeature f) const { + return (f == kSupportsReturnToLauncher) || (f == kSupportsLoadingDuringRuntime) || (f == kSupportsSavingDuringRuntime); +} + +const char *EfhEngine::getCopyrightString() const { + return "Escape From Hell (C) Electronic Arts, 1991"; +} + +GameType EfhEngine::getGameType() const { + return _gameType; +} + +Common::Platform EfhEngine::getPlatform() const { + return _platform; +} + +Common::Error EfhEngine::run() { + s_Engine = this; + initialize(); + initGraphics(320, 200); + + _mainSurface = new Graphics::Surface(); + _mainSurface->create(320, 200, Graphics::PixelFormat::createFormatCLUT8()); +/* + // Setup mixer + syncSoundSettings(); + _soundHandler->init(); + + CursorMan.replaceCursor(_normalCursor, 16, 16, 0, 0, 0); + CursorMan.showMouse(true); +*/ + return Common::kNoError; +} + +void EfhEngine::initialize() { + _rnd = new Common::RandomSource("efh"); + _rnd->setSeed(42); // Kick random number generator + _shouldQuit = false; +} + + +void EfhEngine::syncSoundSettings() { + Engine::syncSoundSettings(); + +// _sound->syncVolume(); +} + +Common::String EfhEngine::getSavegameFilename(int slot) { + return _targetName + Common::String::format("-%02d.SAV", slot); +} + +} // End of namespace Efh diff --git a/engines/efh/efh.h b/engines/efh/efh.h new file mode 100644 index 000000000000..22b6ceac8d70 --- /dev/null +++ b/engines/efh/efh.h @@ -0,0 +1,104 @@ +/* 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef EFH_EFH_H +#define EFH_EFH_H + +#include "efh/detection.h" + +#include "common/file.h" +#include "common/rect.h" +#include "common/events.h" + +#include "engines/engine.h" +#include "graphics/palette.h" +#include "graphics/surface.h" + +namespace Common { +class RandomSource; +} + +/** + * This is the namespace of the Efh engine. + * + * Status of this engine: + * - Skeletton + * + * Games using this engine: + * - Escape From Hell + * + * Escape From Hell is based on a modified Wasteland engine, so this engine could eventually, one day, also support: + * - Wasteland + * - Fountain of Dreams + */ +namespace Efh { + +static const int kSavegameVersion = 1; + +struct EfhGameDescription; + +class EfhEngine : public Engine { +public: + EfhEngine(OSystem *syst, const EfhGameDescription *gd); + ~EfhEngine() override; + + OSystem *_system; + Graphics::Surface *_mainSurface; + Common::RandomSource *_rnd; + + + const EfhGameDescription *_gameDescription; + uint32 getFeatures() const; + const char *getGameId() const; + + void initGame(const EfhGameDescription *gd); + GameType getGameType() const; + Common::Platform getPlatform() const; + + bool hasFeature(EngineFeature f) const override; + const char *getCopyrightString() const; + + Common::String getSavegameFilename(int slot); + void syncSoundSettings() override; + + bool _shouldQuit; + +protected: + Common::EventManager *_eventMan; + int _lastTime; + + // Engine APIs + Common::Error run() override; + void handleMenu(); + +private: + static EfhEngine *s_Engine; + + GameType _gameType; + Common::Platform _platform; + + void initialize(); +}; + +} // End of namespace Efh + +#endif diff --git a/engines/efh/metaengine.cpp b/engines/efh/metaengine.cpp new file mode 100644 index 000000000000..9857fb0bee7d --- /dev/null +++ b/engines/efh/metaengine.cpp @@ -0,0 +1,204 @@ +/* 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "engines/advancedDetector.h" +#include "common/system.h" +#include "common/savefile.h" +#include "common/textconsole.h" +#include "graphics/thumbnail.h" +#include "graphics/surface.h" + +#include "efh/efh.h" +#include "efh/detection.h" + +namespace Efh { + +uint32 EfhEngine::getFeatures() const { + return _gameDescription->desc.flags; +} + +const char *EfhEngine::getGameId() const { + return _gameDescription->desc.gameId; +} + +} // End of namespace Efh + +namespace Efh { + +class EfhMetaEngine : public AdvancedMetaEngine { +public: + const char *getName() const override { + return "efh"; + } + + Common::Error createInstance(OSystem *syst, Engine **engine, const ADGameDescription *gd) const override; + bool hasFeature(MetaEngineFeature f) const override; + + int getMaximumSaveSlot() const override; + SaveStateList listSaves(const char *target) const override; + SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const override; + void removeSaveState(const char *target, int slot) const override; +}; + +Common::Error EfhMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *gd) const { + *engine = new EfhEngine(syst, (const EfhGameDescription *)gd); + ((EfhEngine *)*engine)->initGame((const EfhGameDescription *)gd); + return Common::kNoError; +} + +bool EfhMetaEngine::hasFeature(MetaEngineFeature f) const { + return + (f == kSupportsListSaves) || + (f == kSupportsLoadingDuringStartup) || + (f == kSupportsDeleteSave) || + (f == kSavesSupportMetaInfo) || + (f == kSavesSupportThumbnail) || + (f == kSavesSupportCreationDate); +} + +int EfhMetaEngine::getMaximumSaveSlot() const { + return 99; +} + +SaveStateList EfhMetaEngine::listSaves(const char *target) const { + Common::SaveFileManager *saveFileMan = g_system->getSavefileManager(); + Common::StringArray filenames; + Common::String pattern = target; + pattern += "-##.SAV"; + + filenames = saveFileMan->listSavefiles(pattern); + + SaveStateList saveList; + char slot[3]; + int slotNum = 0; + for (Common::StringArray::const_iterator filename = filenames.begin(); filename != filenames.end(); ++filename) { + slot[0] = filename->c_str()[filename->size() - 6]; + slot[1] = filename->c_str()[filename->size() - 5]; + slot[2] = '\0'; + // Obtain the last 2 digits of the filename (without extension), since they correspond to the save slot + slotNum = atoi(slot); + if (slotNum >= 0 && slotNum <= getMaximumSaveSlot()) { + Common::InSaveFile *file = saveFileMan->openForLoading(*filename); + if (file) { + int saveVersion = file->readByte(); + + if (saveVersion != kSavegameVersion) { + warning("Savegame of incompatible version"); + delete file; + continue; + } + + // read name + uint16 nameSize = file->readUint16BE(); + if (nameSize >= 255) { + delete file; + continue; + } + char name[256]; + file->read(name, nameSize); + name[nameSize] = 0; + + saveList.push_back(SaveStateDescriptor(this, slotNum, name)); + delete file; + } + } + } + + Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator()); + return saveList; +} + +SaveStateDescriptor EfhMetaEngine::querySaveMetaInfos(const char *target, int slot) const { + Common::String fileName = Common::String::format("%s-%02d.SAV", target, slot); + Common::InSaveFile *file = g_system->getSavefileManager()->openForLoading(fileName); + + if (file) { + int saveVersion = file->readByte(); + + if (saveVersion != kSavegameVersion) { + warning("Savegame of incompatible version"); + delete file; + return SaveStateDescriptor(); + } + + uint32 saveNameLength = file->readUint16BE(); + Common::String saveName; + for (uint32 i = 0; i < saveNameLength; ++i) { + char curChr = file->readByte(); + saveName += curChr; + } + + SaveStateDescriptor desc(this, slot, saveName); + + Graphics::Surface *thumbnail; + if (!Graphics::loadThumbnail(*file, thumbnail)) { + delete file; + return SaveStateDescriptor(); + } + desc.setThumbnail(thumbnail); + + desc.setDeletableFlag(true); + desc.setWriteProtectedFlag(false); + + uint32 saveDate = file->readUint32BE(); + uint16 saveTime = file->readUint16BE(); + + int day = (saveDate >> 24) & 0xFF; + int month = (saveDate >> 16) & 0xFF; + int year = saveDate & 0xFFFF; + + desc.setSaveDate(year, month, day); + + int hour = (saveTime >> 8) & 0xFF; + int minutes = saveTime & 0xFF; + + desc.setSaveTime(hour, minutes); + desc.setDeletableFlag(slot != 0); + desc.setWriteProtectedFlag(slot == 0); + + delete file; + return desc; + } + return SaveStateDescriptor(); +} + +void EfhMetaEngine::removeSaveState(const char *target, int slot) const { + Common::String fileName = Common::String::format("%s-%02d.SAV", target, slot); + g_system->getSavefileManager()->removeSavefile(fileName); +} + +} // End of namespace Efh + +#if PLUGIN_ENABLED_DYNAMIC(EFH) + REGISTER_PLUGIN_DYNAMIC(EFH, PLUGIN_TYPE_ENGINE, Efh::EfhMetaEngine); +#else +REGISTER_PLUGIN_STATIC(EFH, PLUGIN_TYPE_ENGINE, Efh::EfhMetaEngine); +#endif + +namespace Efh { + +void EfhEngine::initGame(const EfhGameDescription *gd) { + _gameType = gd->gameType; + _platform = gd->desc.platform; +} + +} // End of namespace Efh diff --git a/engines/efh/module.mk b/engines/efh/module.mk new file mode 100644 index 000000000000..6b8f7bdee6ca --- /dev/null +++ b/engines/efh/module.mk @@ -0,0 +1,19 @@ +MODULE := engines/efh + +MODULE_OBJS = \ + efh.o \ + metaengine.o + +MODULE_DIRS += \ + engines/efh + +# This module can be built as a plugin +ifeq ($(ENABLE_EFH), DYNAMIC_PLUGIN) +PLUGIN := 1 +endif + +# Include common rules +include $(srcdir)/rules.mk + +# Detection objects +DETECT_OBJS += $(MODULE)/detection.o From 76f7fad096a257fbaf21bfaa14a60eddec7182a8 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Thu, 11 Nov 2021 10:55:16 +0100 Subject: [PATCH 050/412] EFH: Partial implementation of initEngine() --- engines/efh/efh.cpp | 342 ++++++++++++++++++++++++++++++++++++++++++++ engines/efh/efh.h | 91 ++++++++++++ 2 files changed, 433 insertions(+) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 3747ec438e47..5af49384ee3e 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -45,10 +45,45 @@ EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst) _gameType = kGameTypeNone; _platform = Common::kPlatformUnknown; _mainSurface = nullptr; + + _videoMode = 0; + _graphicsStruct = nullptr; + _mapBitmapRef = nullptr; + _mapUnknownPtr = nullptr; + _mapMonstersPtr = nullptr; + _mapGameMapPtr = nullptr; + + _defaultBoxColor = 0; + + _fontDescr._widthArray = nullptr; + _fontDescr._extraLines = nullptr; + _fontDescr._fontData = nullptr; + _fontDescr._charHeight = 0; + _fontDescr._extraHorizontalSpace = _fontDescr._extraVerticalSpace = 0; + + _word31E9E = 0; + _oldAnimImageSetId = -1; + _animImageSetId = 254; + _paletteTransformationConstant = 10; + + for (int i = 0; i < 12; ++i) + _circleImageSubFileArray[i] = nullptr; + + _imageDataPtr._dataPtr = nullptr; + _imageDataPtr._width = 0; + _imageDataPtr._startX = _imageDataPtr._startY = 0; + _imageDataPtr._height = 0; + _imageDataPtr._fieldA = 0; + _imageDataPtr._paletteTransformation = 0; + _imageDataPtr._fieldD = 0; + + for (int i = 0; i < 3; ++i) + _currentTileBankImageSetId[i] = -1; } EfhEngine::~EfhEngine() { delete _rnd; + delete _graphicsStruct; } bool EfhEngine::hasFeature(EngineFeature f) const { @@ -82,6 +117,13 @@ Common::Error EfhEngine::run() { CursorMan.replaceCursor(_normalCursor, 16, 16, 0, 0, 0); CursorMan.showMouse(true); */ + initEngine(); + sub15150(-1); + sub12A7F(); + displayLowStatusScreen(-1); + + warning("STUB - Main loop"); + return Common::kNoError; } @@ -91,6 +133,35 @@ void EfhEngine::initialize() { _shouldQuit = false; } +int32 EfhEngine::readFileToBuffer(Common::String &filename, uint8 *destBuffer) { + Common::File f; + if (!f.open(filename)) + error("Unable to find file %s", filename.c_str()); + + int size = f.size(); + + return f.read(destBuffer, size); +} + +void EfhEngine::readAnimInfo() { + warning("STUB - readAnimInfo"); +} + +void EfhEngine::displayAnimFrames(int16 animId, bool displayMenuBoxFl) { + warning("STUB - displayAnimFrames"); +} + +void EfhEngine::readTileFact() { + warning("STUB - readTileFact"); +} + +void EfhEngine::readItems() { + warning("STUB - readItems"); +} + +void EfhEngine::loadNPCS() { + warning("STUB - loadNPCS"); +} void EfhEngine::syncSoundSettings() { Engine::syncSoundSettings(); @@ -102,4 +173,275 @@ Common::String EfhEngine::getSavegameFilename(int slot) { return _targetName + Common::String::format("-%02d.SAV", slot); } +void EfhEngine::initEngine() { + _videoMode = 2; // In the original, 2 = VGA/MCGA, EGA = 4, Tandy = 6, cga = 8. + memset(_bufferCharBM, 0, sizeof(_bufferCharBM)); + _graphicsStruct = new EfhGraphicsStruct; + memset(_graphicsStruct->_vgaLineBuffer, 0, sizeof(_graphicsStruct->_vgaLineBuffer)); + _graphicsStruct->_shiftValue = 0; + _graphicsStruct->_width = 320; + _graphicsStruct->_height = 200; + _graphicsStruct->_area = Common::Rect(0, 0, 319, 199); + + for (int i = 0; i < 3; ++i) { + memset(_tileBank[i], 0, sizeof(_tileBank[i])); + } + + memset(_circleImageBuf, 0, sizeof(_circleImageBuf)); + memset(_portraitBuf, 0, sizeof(_portraitBuf)); + memset(_hiResImageBuf, 0, sizeof(_hiResImageBuf)); + memset(_loResImageBuf, 0, sizeof(_loResImageBuf)); + memset(_menuBuf, 0, sizeof(_menuBuf)); + memset(_windowWithBorderBuf, 0, sizeof(_windowWithBorderBuf)); + memset(_map, 0, sizeof(_map)); + memset(_places, 0, sizeof(_places)); + memset(_curPlace, 0, sizeof(_curPlace)); + memset(_npcBuf, 0, sizeof(_npcBuf)); + memset(_imp1, 0, sizeof(_imp1)); + memset(_imp2, 0, sizeof(_imp2)); + memset(_titleSong, 0, sizeof(_titleSong)); + memset(_items, 0, sizeof(_items)); + memset(_tileFact, 0, sizeof(_tileFact)); + memset(_animInfo, 0, sizeof(_animInfo)); + memset(_history, 0, sizeof(_history)); + memset(_techData, 0, sizeof(_techData)); + + _mapBitmapRef = &_map[0]; + _mapUnknownPtr = &_map[2]; + _mapMonstersPtr = &_map[902]; + _mapGameMapPtr = &_map[2758]; + + _graphicsStruct->_shiftValue = 0x2000; + + _defaultBoxColor = 7; + + // Init Font + static uint8 fontWidthArray[96] = { + 3, 2, 3, 5, 5, 5, 5, 2, 3, 3, 5, 5, 3, 3, 2, 7, 4, 3, 4, 4, 5, 4, 4, 4, 4, 4, 3, 4, 4, 5, 4, 5, 1, 4, 4, 4, + 4, 4, 4, 4, 4, 3, 4, 4, 4, 7, 5, 4, 4, 4, 4, 4, 5, 4, 5, 7, 5, 5, 5, 3, 7, 3, 5, 0, 2, 4, 4, 4, 4, 4, 4, 4, + 4, 1, 2, 4, 1, 7, 4, 4, 4, 4, 4, 4, 3, 4, 5, 7, 4, 4, 5, 3, 0, 3, 0, 0 + }; + + static uint8 fontExtraLinesArray[96] = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 3, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 0, 1, 0, 0 + }; + + static Font fontData[96] = { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x80, 0x00}, + {0xA0, 0xA0, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x50, 0xF8, 0x50, 0xF8, 0x50, 0x00, 0x00}, + {0x20, 0x78, 0xA0, 0x70, 0x28, 0xF0, 0x20, 0x00}, + {0xC8, 0xC8, 0x10, 0x20, 0x40, 0x98, 0x98, 0x00}, + {0x20, 0x50, 0x20, 0x40, 0xA8, 0x90, 0x68, 0x00}, + {0x40, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x40, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x40}, + {0x40, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x40}, + {0x00, 0xA8, 0x70, 0xF8, 0x70, 0xA8, 0x00, 0x00}, + {0x00, 0x20, 0x20, 0xF8, 0x20, 0x20, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x40}, + {0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00}, + {0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00}, + {0x60, 0x90, 0x90, 0x90, 0x90, 0x90, 0x60, 0x00}, + {0x40, 0xC0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00}, + {0x60, 0x90, 0x10, 0x20, 0x40, 0x80, 0xF0, 0x00}, + {0x60, 0x90, 0x10, 0x20, 0x10, 0x90, 0x60, 0x00}, + {0x10, 0x30, 0x50, 0x90, 0xF8, 0x10, 0x10, 0x00}, + {0xF0, 0x80, 0xE0, 0x10, 0x10, 0x90, 0x60, 0x00}, + {0x60, 0x90, 0x80, 0xE0, 0x90, 0x90, 0x60, 0x00}, + {0xF0, 0x10, 0x20, 0x20, 0x40, 0x40, 0x40, 0x00}, + {0x60, 0x90, 0x90, 0x60, 0x90, 0x90, 0x60, 0x00}, + {0x60, 0x90, 0x90, 0x70, 0x10, 0x90, 0x60, 0x00}, + {0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00}, + {0x00, 0x00, 0x20, 0x00, 0x00, 0x20, 0x40, 0x00}, + {0x10, 0x20, 0x40, 0x80, 0x40, 0x20, 0x10, 0x00}, + {0x00, 0x00, 0xF8, 0x00, 0x00, 0xF8, 0x00, 0x00}, + {0x80, 0x40, 0x20, 0x10, 0x20, 0x40, 0x80, 0x00}, + {0x70, 0x88, 0x08, 0x10, 0x20, 0x00, 0x20, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x60, 0x90, 0x90, 0xF0, 0x90, 0x90, 0x90, 0x00}, + {0xE0, 0x90, 0x90, 0xE0, 0x90, 0x90, 0xE0, 0x00}, + {0x60, 0x90, 0x80, 0x80, 0x80, 0x90, 0x60, 0x00}, + {0xE0, 0x90, 0x90, 0x90, 0x90, 0x90, 0xE0, 0x00}, + {0xF0, 0x80, 0x80, 0xE0, 0x80, 0x80, 0xF0, 0x00}, + {0xF0, 0x80, 0x80, 0xE0, 0x80, 0x80, 0x80, 0x00}, + {0x60, 0x90, 0x80, 0xB0, 0x90, 0x90, 0x70, 0x00}, + {0x90, 0x90, 0x90, 0xF0, 0x90, 0x90, 0x90, 0x00}, + {0xE0, 0x40, 0x40, 0x40, 0x40, 0x40, 0xE0, 0x00}, + {0x10, 0x10, 0x10, 0x10, 0x10, 0x90, 0x60, 0x00}, + {0x90, 0x90, 0x90, 0xE0, 0x90, 0x90, 0x90, 0x00}, + {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xF0, 0x00}, + {0x82, 0xC6, 0xAA, 0x92, 0x82, 0x82, 0x82, 0x00}, + {0x88, 0x88, 0xC8, 0xA8, 0x98, 0x88, 0x88, 0x00}, + {0x60, 0x90, 0x90, 0x90, 0x90, 0x90, 0x60, 0x00}, + {0xE0, 0x90, 0x90, 0xE0, 0x80, 0x80, 0x80, 0x00}, + {0x60, 0x90, 0x90, 0x90, 0x90, 0x90, 0x60, 0x10}, + {0xE0, 0x90, 0x90, 0xE0, 0x90, 0x90, 0x90, 0x00}, + {0x60, 0x90, 0x80, 0x60, 0x10, 0x90, 0x60, 0x00}, + {0xF8, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00}, + {0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x60, 0x00}, + {0x88, 0x88, 0x88, 0x50, 0x50, 0x20, 0x20, 0x00}, + {0x82, 0x82, 0x82, 0x92, 0xAA, 0xC6, 0x82, 0x00}, + {0x88, 0x88, 0x50, 0x20, 0x50, 0x88, 0x88, 0x00}, + {0x88, 0x88, 0x50, 0x20, 0x20, 0x20, 0x20, 0x00}, + {0xF8, 0x08, 0x10, 0x20, 0x40, 0x80, 0xF8, 0x00}, + {0xC0, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xC0}, + {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x00}, + {0x60, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x60}, + {0x20, 0x50, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x80, 0x80, 0x40, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x60, 0x10, 0x70, 0x90, 0x70, 0x00}, + {0x80, 0x80, 0xE0, 0x90, 0x90, 0x90, 0xE0, 0x00}, + {0x00, 0x00, 0x60, 0x90, 0x80, 0x90, 0x60, 0x00}, + {0x10, 0x10, 0x70, 0x90, 0x90, 0x90, 0x70, 0x00}, + {0x00, 0x00, 0x60, 0x90, 0xF0, 0x80, 0x60, 0x00}, + {0x30, 0x40, 0xE0, 0x40, 0x40, 0x40, 0x40, 0x00}, + {0x70, 0x90, 0x90, 0x90, 0x70, 0x10, 0xE0, 0x00}, + {0x80, 0x80, 0xE0, 0x90, 0x90, 0x90, 0x90, 0x00}, + {0x80, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00}, + {0x40, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x80}, + {0x80, 0x80, 0x90, 0x90, 0xE0, 0x90, 0x90, 0x00}, + {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00}, + {0x00, 0x00, 0xEC, 0x92, 0x92, 0x92, 0x92, 0x00}, + {0x00, 0x00, 0xE0, 0x90, 0x90, 0x90, 0x90, 0x00}, + {0x00, 0x00, 0x60, 0x90, 0x90, 0x90, 0x60, 0x00}, + {0x00, 0xE0, 0x90, 0x90, 0x90, 0xE0, 0x80, 0x80}, + {0x00, 0x70, 0x90, 0x90, 0x90, 0x70, 0x10, 0x10}, + {0x00, 0x00, 0xB0, 0xC0, 0x80, 0x80, 0x80, 0x00}, + {0x00, 0x00, 0x70, 0x80, 0x60, 0x10, 0xE0, 0x00}, + {0x40, 0x40, 0xE0, 0x40, 0x40, 0x40, 0x40, 0x00}, + {0x00, 0x00, 0x90, 0x90, 0x90, 0x90, 0x70, 0x00}, + {0x00, 0x00, 0x88, 0x50, 0x50, 0x20, 0x20, 0x00}, + {0x00, 0x00, 0x92, 0x92, 0x92, 0x92, 0x6E, 0x00}, + {0x00, 0x00, 0x90, 0x90, 0x60, 0x90, 0x90, 0x00}, + {0x00, 0x90, 0x90, 0x90, 0x90, 0x70, 0x10, 0xE0}, + {0x00, 0x00, 0xF8, 0x10, 0x20, 0x40, 0xF8, 0x00}, + {0x20, 0x40, 0x40, 0x80, 0x40, 0x40, 0x20, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x80, 0x40, 0x40, 0x20, 0x40, 0x40, 0x80, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} + }; + + _fontDescr._widthArray = fontWidthArray; + _fontDescr._extraLines = fontExtraLinesArray; + _fontDescr._fontData = fontData; + _fontDescr._charHeight = 8; + _fontDescr._extraVerticalSpace = 3; + _fontDescr._extraHorizontalSpace = 1; + _word31E9E = 0; + + saveAnimImageSetId(); + + // Save int 1C + // Set new int 1C: + // TODO: Implement that in the main loop + // static uint8 counter = 0; + // ++counter; + // if (counter == 4) { + // counter = 0; + // tick220Fl = 1; + // } + + // Load Title Screen + loadImageSet(11, (uint8 *)_circleImageBuf, (uint8 **)_circleImageSubFileArray, 0, _paletteTransformationConstant, (uint8 *)_hiResImageBuf, (uint8 *)_loResImageBuf); + displayFctFullScreen(); + sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 0, _paletteTransformationConstant); + displayFctFullScreen(); + sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 0, _paletteTransformationConstant); + + // Load map tiles bitmaps + loadImageSetToTileBank(1, 1); + loadImageSetToTileBank(2, 2); + + // Load characters bitmaps + loadImageSetToTileBank(3, 6); + + // Load 320*200 Menu screen + Common::String fileName = Common::String::format("images\\imageset.%d", 10); + readFileToBuffer(fileName, _menuBuf); + + // Load 96*64 Window with pink border and yellow bottom + fileName = Common::String::format("images\\imageset.%d", 12); + readFileToBuffer(fileName, _windowWithBorderBuf); + + readAnimInfo(); + + displayAnimFrames(254, 0); + saveAnimImageSetId(); + readTileFact(); + readItems(); + loadNPCS(); + + warning("STUB - initEngine"); +} + +void EfhEngine::saveAnimImageSetId() { + _oldAnimImageSetId = _animImageSetId; + _animImageSetId = 255; +} + +void EfhEngine::sub15150(int i) { + warning("STUB - sub15150"); +} + +void EfhEngine::sub12A7F() { + warning("STUB - sub12A7F"); +} + +void EfhEngine::displayLowStatusScreen(int i) { + warning("STUB - displayLowStatusScreen"); +} + +void EfhEngine::loadImageSet(int imageSetId, uint8 *buffer, uint8 **subFilesArray, char CGAVal, char EGAVal, uint8 *destBuffer, uint8 *transfBuffer) { + warning("STUB - loadImageSet"); +} + +void EfhEngine::displayFctFullScreen() { + // CHECKME: 200 is in the original but looks suspicious. + displayBitmapAtPos(0, 0, 319, 200); +} + +void EfhEngine::displayBitmapAtPos(int16 minX, int16 minY, int16 maxX, int16 maxY) { + warning("STUB - displayBitmapAtPos"); +} + +void EfhEngine::sub24D92(BufferBM *bufferBM, int16 posX, int16 posY) { + warning("STUB - sub24D92"); +} + +void EfhEngine::loadImageSetToTileBank(int16 tileBankId, int16 imageSetId) { + // TODO: all the values of titleBankId and imageSetId are hardcoded. When all the calls are implemented, fix the values to avoid to have to decrease them + int16 bankId = tileBankId - 1; + int16 setId = imageSetId - 1; + + if (_currentTileBankImageSetId[bankId] == setId) + return; + + _currentTileBankImageSetId[bankId] = setId; + + if (bankId == 0 || bankId == 1) + _mapBitmapRef[bankId] = setId; + + int16 ptrIndex = bankId * 72; + loadImageSet(setId, _tileBank[bankId], &_imageSetSubFilesArray[ptrIndex], 0, _paletteTransformationConstant, _hiResImageBuf, _loResImageBuf); +} + +void EfhEngine::sub10B77_unkDisplayFct1(uint8 *imagePtr, int16 posX, int16 posY, uint8 guess_paletteTransformation) { + uint16 height = READ_LE_INT16(imagePtr); + uint16 width = READ_LE_INT16(imagePtr + 2); + uint8 *imageData = imagePtr + 4; + + _imageDataPtr._fieldA = width; + _imageDataPtr._dataPtr = imageData; + _imageDataPtr._height = height; + _imageDataPtr._width = width * 2; + _imageDataPtr._startX = _imageDataPtr._startY = 0; + + sub24D92(&_imageDataPtr, posX, posY); +} } // End of namespace Efh diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 22b6ceac8d70..3692e6fe0b86 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -56,6 +56,38 @@ static const int kSavegameVersion = 1; struct EfhGameDescription; +struct EfhGraphicsStruct { + uint16 _vgaLineBuffer[200]; + uint16 _shiftValue; + uint16 _width; + uint16 _height; + Common::Rect _area; +}; + +struct Font { + uint8 _lines[8]; +}; + +struct FontDescr { + uint8 *_widthArray; + uint8 *_extraLines; + Font *_fontData; + uint8 _charHeight; + uint8 _extraVerticalSpace; + uint8 _extraHorizontalSpace; +}; + +struct BufferBM { + uint8 *_dataPtr; + uint16 _width; + uint16 _startX; + uint16 _startY; + uint16 _height; + uint16 _fieldA; + uint8 _paletteTransformation; + uint16 _fieldD; +}; + class EfhEngine : public Engine { public: EfhEngine(OSystem *syst, const EfhGameDescription *gd); @@ -97,6 +129,65 @@ class EfhEngine : public Engine { Common::Platform _platform; void initialize(); + int32 readFileToBuffer(Common::String &filename, uint8 *destBuffer); + void readAnimInfo(); + void displayAnimFrames(int16 animId, bool displayMenuBoxFl); + void readTileFact(); + void readItems(); + void loadNPCS(); + void initEngine(); + void saveAnimImageSetId(); + void sub15150(int i); + void sub12A7F(); + void displayLowStatusScreen(int i); + void loadImageSet(int imageSetId, uint8 *buffer, uint8 **subFilesArray, char CGAVal, char EGAVal, uint8 *destBuffer, uint8 *transfBuffer); + void displayFctFullScreen(); + void displayBitmapAtPos(int16 minX, int16 minY, int16 maxX, int16 maxY); + void sub10B77_unkDisplayFct1(uint8 *imagePtr, int16 posX, int16 posY, uint8 guess_paletteTransformation); + void sub24D92(BufferBM *bufferBM, int16 posX, int16 posY); + void loadImageSetToTileBank(int16 tileBankId, int16 imageSetId); + + uint8 _videoMode; + uint8 _bufferCharBM[128]; + EfhGraphicsStruct *_graphicsStruct; + uint8 _tileBank[3][12000]; + uint8 _circleImageBuf[40100]; + uint8 _portraitBuf[25000]; + uint8 _hiResImageBuf[40100]; + uint8 _loResImageBuf[40100]; + uint8 _menuBuf[12500]; + uint8 _windowWithBorderBuf[1500]; + uint8 _map[7000]; + uint8 _places[12000]; + uint8 _curPlace[600]; + uint8 _npcBuf[13400]; + uint8 _imp1[13000]; + uint8 _imp2[10000]; + uint8 _titleSong[1024]; + uint8 _items[8100]; + uint8 _tileFact[864]; + uint8 _animInfo[9000]; + uint8 _history[256]; + uint8 _techData[4096]; + + uint8 *_mapBitmapRef; + uint8 *_mapUnknownPtr; + uint8 *_mapMonstersPtr; + uint8 *_mapGameMapPtr; + + uint8 _defaultBoxColor; + FontDescr _fontDescr; + + uint8 _word31E9E; + + int16 _oldAnimImageSetId; + int16 _animImageSetId; + uint8 _paletteTransformationConstant; + uint8 *_circleImageSubFileArray[12]; + uint8 *_imageSetSubFilesArray[214]; // CHECKME : logically it should be 216 + BufferBM _imageDataPtr; + int16 _currentTileBankImageSetId[3]; + }; } // End of namespace Efh From 01fb53ec98c8a4dbd46a93cc745febf4b0069d56 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Fri, 12 Nov 2021 07:16:18 +0100 Subject: [PATCH 051/412] EFH: Implement some functions loading files --- engines/efh/efh.cpp | 134 +++++++++++++++++++++++++++++++++++++++----- engines/efh/efh.h | 23 +++++++- 2 files changed, 139 insertions(+), 18 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 5af49384ee3e..88b0997a34d0 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -33,7 +33,31 @@ namespace Efh { -EfhEngine *EfhEngine::s_Engine = 0; +EfhEngine *EfhEngine::s_Engine = nullptr; + +EfhGraphicsStruct::EfhGraphicsStruct() { + _vgaLineBuffer = nullptr; + _shiftValue = 0; + _width = 0; + _height = 0; + _area = Common::Rect(0, 0, 0, 0); +} +EfhGraphicsStruct::EfhGraphicsStruct(int16 *lineBuf, int16 x, int16 y, int16 width, int16 height) { + _vgaLineBuffer = lineBuf; + _shiftValue = 0; + _width = width; + _height = height; + _area = Common::Rect(x, y, x + width - 1, y + height - 1); +} + +void EfhGraphicsStruct::copy(EfhGraphicsStruct *src) { + // Same buffer address + _vgaLineBuffer = src->_vgaLineBuffer; + _shiftValue = src->_shiftValue; + _width = src->_width; + _height = src->_height; + _area = src->_area; +} EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst), _gameDescription(gd) { _system = syst; @@ -46,6 +70,8 @@ EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst) _platform = Common::kPlatformUnknown; _mainSurface = nullptr; + _vgaGraphicsStruct = new EfhGraphicsStruct(_vgaLineBuffer, 0, 0, 320, 200); + _videoMode = 0; _graphicsStruct = nullptr; _mapBitmapRef = nullptr; @@ -79,11 +105,21 @@ EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst) for (int i = 0; i < 3; ++i) _currentTileBankImageSetId[i] = -1; + + _unkRelatedToAnimImageSetId = 0; + _techId = 0; + _currentAnimImageSetId = 0xFF; + + for (int i = 0; i < 20; ++i) + _portraitSubFilesArray[i] = nullptr; + + _unkAnimRelatedIndex = -1; } EfhEngine::~EfhEngine() { delete _rnd; delete _graphicsStruct; + delete _vgaGraphicsStruct; } bool EfhEngine::hasFeature(EngineFeature f) const { @@ -91,7 +127,7 @@ bool EfhEngine::hasFeature(EngineFeature f) const { } const char *EfhEngine::getCopyrightString() const { - return "Escape From Hell (C) Electronic Arts, 1991"; + return "Escape From Hell (C) Electronic Arts, 1990"; } GameType EfhEngine::getGameType() const { @@ -128,8 +164,8 @@ Common::Error EfhEngine::run() { } void EfhEngine::initialize() { - _rnd = new Common::RandomSource("efh"); - _rnd->setSeed(42); // Kick random number generator + _rnd = new Common::RandomSource("Hell"); + _rnd->setSeed(666); // Kick random number generator _shouldQuit = false; } @@ -144,23 +180,94 @@ int32 EfhEngine::readFileToBuffer(Common::String &filename, uint8 *destBuffer) { } void EfhEngine::readAnimInfo() { - warning("STUB - readAnimInfo"); + Common::String fileName = "gendata\\animinfo"; + readFileToBuffer(fileName, _animInfo); +} + +void EfhEngine::findMapFile(int16 mapId) { + if (_word31E9E == 0) + return; + + Common::String fileName = Common::String::format("map\\map.%d", mapId); + Common::File f; + // The original was checking for the file and eventually asking to change floppies + if (!f.open(fileName)) + error("File not found: %s", fileName.c_str()); + + f.close(); +} + +void EfhEngine::loadNewPortrait() { + static int16 unkConstRelatedToAnimImageSetId[19] = {0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2}; + _unkRelatedToAnimImageSetId = unkConstRelatedToAnimImageSetId[_techId]; + + if (_currentAnimImageSetId == 200 + _unkRelatedToAnimImageSetId) + return; + + findMapFile(_techId); + _currentAnimImageSetId = 200 + _unkRelatedToAnimImageSetId; + int imageSetId = _unkRelatedToAnimImageSetId + 13; + loadImageSet(imageSetId, _portraitBuf, _portraitSubFilesArray, 0, _paletteTransformationConstant, _hiResImageBuf, _loResImageBuf); +} + +void EfhEngine::loadAnimImageSet() { + warning("STUB - loadAnimImageSet"); + if (_currentAnimImageSetId == _animImageSetId || _animImageSetId == 0xFF) + return; + + findMapFile(_techId); + + _unkAnimRelatedIndex = 0; + _currentAnimImageSetId = _animImageSetId; + + int16 animSetId = _animImageSetId + 17; + loadImageSet(animSetId, _portraitBuf, _portraitSubFilesArray, 0, _paletteTransformationConstant, _hiResImageBuf, _loResImageBuf); +} + +void EfhEngine::drawUnknownMenuBox() { + warning("STUB - drawUnknownMenuBox"); +} + +void EfhEngine::displayAnimFrame() { + // The original had a parameter. As it was always equal to zero, it was removed in ScummVM + warning("STUB - displayAnimFrame"); } void EfhEngine::displayAnimFrames(int16 animId, bool displayMenuBoxFl) { - warning("STUB - displayAnimFrames"); + if (animId == 0xFF) + return; + + _animImageSetId = animId; + if (_animImageSetId == 0xFE) + loadNewPortrait(); + else + loadAnimImageSet(); + + if (!displayMenuBoxFl) + return; + + for (int i = 0; i < 2; ++i) { + drawUnknownMenuBox(); + displayAnimFrame(); + + if (i == 0) + displayFctFullScreen(); + } } void EfhEngine::readTileFact() { - warning("STUB - readTileFact"); + Common::String fileName = "gendata\\tilefact"; + readFileToBuffer(fileName, _tileFact); } void EfhEngine::readItems() { - warning("STUB - readItems"); + Common::String fileName = "gendata\\items"; + readFileToBuffer(fileName, _items); } void EfhEngine::loadNPCS() { - warning("STUB - loadNPCS"); + Common::String fileName = "gendata\\npcs"; + readFileToBuffer(fileName, _npcBuf); } void EfhEngine::syncSoundSettings() { @@ -177,11 +284,7 @@ void EfhEngine::initEngine() { _videoMode = 2; // In the original, 2 = VGA/MCGA, EGA = 4, Tandy = 6, cga = 8. memset(_bufferCharBM, 0, sizeof(_bufferCharBM)); _graphicsStruct = new EfhGraphicsStruct; - memset(_graphicsStruct->_vgaLineBuffer, 0, sizeof(_graphicsStruct->_vgaLineBuffer)); - _graphicsStruct->_shiftValue = 0; - _graphicsStruct->_width = 320; - _graphicsStruct->_height = 200; - _graphicsStruct->_area = Common::Rect(0, 0, 319, 199); + _graphicsStruct->copy(_vgaGraphicsStruct); for (int i = 0; i < 3; ++i) { memset(_tileBank[i], 0, sizeof(_tileBank[i])); @@ -371,7 +474,7 @@ void EfhEngine::initEngine() { readAnimInfo(); - displayAnimFrames(254, 0); + displayAnimFrames(0xFE, false); saveAnimImageSetId(); readTileFact(); readItems(); @@ -408,6 +511,7 @@ void EfhEngine::displayFctFullScreen() { void EfhEngine::displayBitmapAtPos(int16 minX, int16 minY, int16 maxX, int16 maxY) { warning("STUB - displayBitmapAtPos"); + _graphicsStruct->copy(_vgaGraphicsStruct); } void EfhEngine::sub24D92(BufferBM *bufferBM, int16 posX, int16 posY) { diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 3692e6fe0b86..c6f137cd143a 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -56,12 +56,18 @@ static const int kSavegameVersion = 1; struct EfhGameDescription; -struct EfhGraphicsStruct { - uint16 _vgaLineBuffer[200]; +class EfhGraphicsStruct { +public: + EfhGraphicsStruct(); + EfhGraphicsStruct(int16 *lineBuf, int16 x, int16 y, int16 width, int16 height); + + int16 *_vgaLineBuffer; uint16 _shiftValue; uint16 _width; uint16 _height; Common::Rect _area; + + void copy(EfhGraphicsStruct *src); }; struct Font { @@ -131,6 +137,11 @@ class EfhEngine : public Engine { void initialize(); int32 readFileToBuffer(Common::String &filename, uint8 *destBuffer); void readAnimInfo(); + void findMapFile(int16 mapId); + void loadNewPortrait(); + void loadAnimImageSet(); + void drawUnknownMenuBox(); + void displayAnimFrame(); void displayAnimFrames(int16 animId, bool displayMenuBoxFl); void readTileFact(); void readItems(); @@ -149,6 +160,8 @@ class EfhEngine : public Engine { uint8 _videoMode; uint8 _bufferCharBM[128]; + int16 _vgaLineBuffer[200]; + EfhGraphicsStruct *_vgaGraphicsStruct; EfhGraphicsStruct *_graphicsStruct; uint8 _tileBank[3][12000]; uint8 _circleImageBuf[40100]; @@ -187,7 +200,11 @@ class EfhEngine : public Engine { uint8 *_imageSetSubFilesArray[214]; // CHECKME : logically it should be 216 BufferBM _imageDataPtr; int16 _currentTileBankImageSetId[3]; - + int16 _unkRelatedToAnimImageSetId; + int16 _techId; + int16 _currentAnimImageSetId; + uint8 *_portraitSubFilesArray[20]; + int16 _unkAnimRelatedIndex; }; } // End of namespace Efh From d679199d67e7ddcc8ab7ccb34085e0d6a504613f Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sun, 14 Nov 2021 15:02:25 +0100 Subject: [PATCH 052/412] EFH: More work on initEngine --- engines/efh/efh.cpp | 314 ++++++++++++++++++++++++++++++++++++++++++-- engines/efh/efh.h | 58 +++++++- 2 files changed, 358 insertions(+), 14 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 88b0997a34d0..f521d8906787 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -70,7 +70,8 @@ EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst) _platform = Common::kPlatformUnknown; _mainSurface = nullptr; - _vgaGraphicsStruct = new EfhGraphicsStruct(_vgaLineBuffer, 0, 0, 320, 200); + _vgaGraphicsStruct1 = new EfhGraphicsStruct(_vgaLineBuffer, 0, 0, 320, 200); + _vgaGraphicsStruct2 = new EfhGraphicsStruct(); _videoMode = 0; _graphicsStruct = nullptr; @@ -113,13 +114,48 @@ EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst) for (int i = 0; i < 20; ++i) _portraitSubFilesArray[i] = nullptr; + for (int i = 0; i < 100; ++i) + _imp1PtrArray[i] = nullptr; + + for (int i = 0; i < 432; ++i) + _imp2PtrArray[i] = nullptr; + _unkAnimRelatedIndex = -1; + + _initRect = Common::Rect(0, 0, 0, 0); + _engineInitPending = true; + _unkVideoRelatedWord1 = 0x0E; + _protectionPassed = false; + _fullPlaceId = 0xFF; + _guessAnimationAmount = 9; + _largeMapFlag = 0xFFFF; + _teamCharIdArray = 0; + _charId = -1; + _word2C8B8 = -1; + + for (int i = 0; i < 3; ++i) { + _teamCharStatus[i]._status = 0; + _teamCharStatus[i]._duration = 0; + _unkArray2C8AA[i] = 0; + } + + _unkArray2C8AA[2] = 1; + _teamSize = 1; + _word2C872 = 0; + _imageSetSubFilesIdx = 144; + + _mapPosX = _mapPosY = 31; + _oldMapPosX = _oldMapPosY = 31; + _techDataId_MapPosX = _techDataId_MapPosY = 31; + + _lastMainPlaceId = 0; } EfhEngine::~EfhEngine() { delete _rnd; delete _graphicsStruct; - delete _vgaGraphicsStruct; + delete _vgaGraphicsStruct1; + delete _vgaGraphicsStruct2; } bool EfhEngine::hasFeature(EngineFeature f) const { @@ -154,10 +190,13 @@ Common::Error EfhEngine::run() { CursorMan.showMouse(true); */ initEngine(); - sub15150(-1); + sub15150(true); sub12A7F(); displayLowStatusScreen(-1); + if (!_protectionPassed) + return Common::kNoError; + warning("STUB - Main loop"); return Common::kNoError; @@ -224,6 +263,54 @@ void EfhEngine::loadAnimImageSet() { loadImageSet(animSetId, _portraitBuf, _portraitSubFilesArray, 0, _paletteTransformationConstant, _hiResImageBuf, _loResImageBuf); } +void EfhEngine::loadHistory() { + Common::String fileName = "gendata\\history"; + readFileToBuffer(fileName, _history); +} + +void EfhEngine::loadTechMapImp(int16 fileId) { + if (fileId == 0xFF) + return; + + _techId = fileId; + findMapFile(_techId); + + Common::String fileName = Common::String::format("maps\\tech.%d", _techId); + readFileToBuffer(fileName, _hiResImageBuf); + uncompressBuffer(_hiResImageBuf, _techData); + + fileName = Common::String::format("maps\\map.%d", _techId); + readFileToBuffer(fileName, _hiResImageBuf); + uncompressBuffer(_hiResImageBuf, _map); + + loadImageSetToTileBank(1, _mapBitmapRef[0]); + loadImageSetToTileBank(1, _mapBitmapRef[1]); + + initMapMonsters(); + readImpFile(_techId, true); + displayAnimFrames(0xFE, false); + +} + +void EfhEngine::loadPlacesFile(uint16 fullPlaceId, int16 unused, bool forceReloadFl) { + //TODO : Remove unused parameter when all the calls are implemented + if (fullPlaceId == 0xFF) + return; + + findMapFile(_techId); + _fullPlaceId = fullPlaceId; + uint16 minPlace = _lastMainPlaceId * 20; + uint16 maxPlace = minPlace + 19; + + if (_fullPlaceId < minPlace || _fullPlaceId > maxPlace || forceReloadFl) { + _lastMainPlaceId = _fullPlaceId / 20; + Common::String fileName = Common::String::format("maps\\places.%d", _lastMainPlaceId); + readFileToBuffer(fileName, _hiResImageBuf); + uncompressBuffer(_hiResImageBuf, _places); + } + copyCurrentPlaceToBuffer(_fullPlaceId / 20); +} + void EfhEngine::drawUnknownMenuBox() { warning("STUB - drawUnknownMenuBox"); } @@ -270,6 +357,40 @@ void EfhEngine::loadNPCS() { readFileToBuffer(fileName, _npcBuf); } +void EfhEngine::setDefaultNoteDuration() { + // Original implementation is based on the int1C, which is triggered at 18.2065Hz. + // Every 4 times, it sets a flag (thus, approx every 220ms) + // The function was checking the keyboard in a loop, incrementing a counter and setting the last character read + // The "_defaultNoteDuration" was then set to 7 times this counter + // + // No implementation required in ScummVM +} + +Common::KeyCode EfhEngine::playSong(uint8 *buffer) { + warning("STUB: playSong"); + return Common::KEYCODE_INVALID; +} + +void EfhEngine::decryptImpFile(bool techMapFl) { + warning("STUB - decryptImpFile"); +} + +void EfhEngine::readImpFile(int16 id, bool techMapFl) { + Common::String fileName = Common::String::format("imp\\imp.%d", id); + + if (techMapFl) + readFileToBuffer(fileName, _imp1); + else + readFileToBuffer(fileName, _imp2); + + decryptImpFile(techMapFl); +} + +Common::KeyCode EfhEngine::getLastCharAfterAnimCount(int16 delay) { + warning("STUB - getLastCharAfterAnimCount"); + return Common::KEYCODE_INVALID; +} + void EfhEngine::syncSoundSettings() { Engine::syncSoundSettings(); @@ -284,7 +405,7 @@ void EfhEngine::initEngine() { _videoMode = 2; // In the original, 2 = VGA/MCGA, EGA = 4, Tandy = 6, cga = 8. memset(_bufferCharBM, 0, sizeof(_bufferCharBM)); _graphicsStruct = new EfhGraphicsStruct; - _graphicsStruct->copy(_vgaGraphicsStruct); + _graphicsStruct->copy(_vgaGraphicsStruct1); for (int i = 0; i < 3; ++i) { memset(_tileBank[i], 0, sizeof(_tileBank[i])); @@ -314,7 +435,10 @@ void EfhEngine::initEngine() { _mapMonstersPtr = &_map[902]; _mapGameMapPtr = &_map[2758]; - _graphicsStruct->_shiftValue = 0x2000; + _vgaGraphicsStruct2->copy(_vgaGraphicsStruct1); + _vgaGraphicsStruct2->_shiftValue = 0x2000; + + _graphicsStruct->copy(_vgaGraphicsStruct2); _defaultBoxColor = 7; @@ -480,7 +604,90 @@ void EfhEngine::initEngine() { readItems(); loadNPCS(); - warning("STUB - initEngine"); + // Load picture room with girlfriend + loadImageSet(62, _circleImageBuf, _circleImageSubFileArray, 0, _paletteTransformationConstant, _hiResImageBuf, _loResImageBuf); + fileName = "gendata\\titlsong"; + readFileToBuffer(fileName, _titleSong); + setDefaultNoteDuration(); + Common::KeyCode lastInput = playSong(_titleSong); + + if (lastInput != Common::KEYCODE_ESCAPE) { + sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 0, _paletteTransformationConstant); + displayFctFullScreen(); + sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 0, _paletteTransformationConstant); + + // Load animations on previous picture with GF + loadImageSet(63, _circleImageBuf, _circleImageSubFileArray, 0, _paletteTransformationConstant, _hiResImageBuf, _loResImageBuf); + readImpFile(100, 0); + lastInput = getLastCharAfterAnimCount(8); + + if (lastInput != Common::KEYCODE_ESCAPE) { + sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 144, _paletteTransformationConstant); + sub133E5(_imp2PtrArray[0], 6, 150, 268, 186, 0); + displayFctFullScreen(); + sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 144, _paletteTransformationConstant); + sub133E5(_imp2PtrArray[0], 6, 150, 268, 186, 0); + lastInput = getLastCharAfterAnimCount(80); + if (lastInput != Common::KEYCODE_ESCAPE) { + sub10B77_unkDisplayFct1(_circleImageSubFileArray[1], 110, 16, _paletteTransformationConstant); + sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 144, _paletteTransformationConstant); + sub133E5(_imp2PtrArray[1], 6, 150, 268, 186, 0); + displayFctFullScreen(); + sub10B77_unkDisplayFct1(_circleImageSubFileArray[1], 110, 16, _paletteTransformationConstant); + sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 144, _paletteTransformationConstant); + sub133E5(_imp2PtrArray[1], 6, 150, 268, 186, 0); + lastInput = getLastCharAfterAnimCount(80); + if (lastInput != Common::KEYCODE_ESCAPE) { + sub10B77_unkDisplayFct1(_circleImageSubFileArray[2], 110, 16, _paletteTransformationConstant); + sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 144, _paletteTransformationConstant); + sub133E5(_imp2PtrArray[2], 6, 150, 268, 186, 0); + displayFctFullScreen(); + sub10B77_unkDisplayFct1(_circleImageSubFileArray[2], 110, 16, _paletteTransformationConstant); + sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 144, _paletteTransformationConstant); + sub133E5(_imp2PtrArray[2], 6, 150, 268, 186, 0); + lastInput = getLastCharAfterAnimCount(80); + if (lastInput != Common::KEYCODE_ESCAPE) { + sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 144, _paletteTransformationConstant); + sub133E5(_imp2PtrArray[3], 6, 150, 268, 186, 0); + displayFctFullScreen(); + sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 144, _paletteTransformationConstant); + sub133E5(_imp2PtrArray[3], 6, 150, 268, 186, 0); + lastInput = getLastCharAfterAnimCount(80); + if (lastInput != Common::KEYCODE_ESCAPE) { + sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 144, _paletteTransformationConstant); + sub133E5(_imp2PtrArray[4], 6, 150, 268, 186, 0); + displayFctFullScreen(); + sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 144, _paletteTransformationConstant); + sub133E5(_imp2PtrArray[4], 6, 150, 268, 186, 0); + lastInput = getLastCharAfterAnimCount(80); + if (lastInput != Common::KEYCODE_ESCAPE) { + sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 144, _paletteTransformationConstant); + sub133E5(_imp2PtrArray[5], 6, 150, 268, 186, 0); + displayFctFullScreen(); + sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 144, _paletteTransformationConstant); + sub133E5(_imp2PtrArray[5], 6, 150, 268, 186, 0); + lastInput = getLastCharAfterAnimCount(80); + } + } + } + } + } + } + } + + loadImageSet(6, _circleImageBuf, _circleImageSubFileArray, 0, _paletteTransformationConstant, _hiResImageBuf, _loResImageBuf); + readImpFile(99, 0); + _word31E9E = 0xFFFF; + restoreAnimImageSetId(); + + // Save int 24h, set new int24 to handle fatal failure + checkProtection(); + loadGame(); + _engineInitPending = false; + } + +void EfhEngine::initMapMonsters() { + warning("STUB - initMapMonsters"); } void EfhEngine::saveAnimImageSetId() { @@ -488,7 +695,7 @@ void EfhEngine::saveAnimImageSetId() { _animImageSetId = 255; } -void EfhEngine::sub15150(int i) { +void EfhEngine::sub15150(bool flag) { warning("STUB - sub15150"); } @@ -511,13 +718,23 @@ void EfhEngine::displayFctFullScreen() { void EfhEngine::displayBitmapAtPos(int16 minX, int16 minY, int16 maxX, int16 maxY) { warning("STUB - displayBitmapAtPos"); - _graphicsStruct->copy(_vgaGraphicsStruct); + _graphicsStruct->copy(_vgaGraphicsStruct2); + _initRect = Common::Rect(minX, minY, maxX, maxY); + displayBitmap(_vgaGraphicsStruct2, _vgaGraphicsStruct1, _initRect, minX, minY); +} + +void EfhEngine::displayBitmap(EfhGraphicsStruct *efh_graphics_struct, EfhGraphicsStruct *efh_graphics_struct1, const Common::Rect &rect, int16 min_x, int16 min_y) { + warning("STUB - displayBitmap"); } void EfhEngine::sub24D92(BufferBM *bufferBM, int16 posX, int16 posY) { warning("STUB - sub24D92"); } +void EfhEngine::sub133E5(uint8 *impPtr, int posX, int posY, int maxX, int maxY, int argC) { + warning("STUB - sub133E5"); +} + void EfhEngine::loadImageSetToTileBank(int16 tileBankId, int16 imageSetId) { // TODO: all the values of titleBankId and imageSetId are hardcoded. When all the calls are implemented, fix the values to avoid to have to decrease them int16 bankId = tileBankId - 1; @@ -535,6 +752,87 @@ void EfhEngine::loadImageSetToTileBank(int16 tileBankId, int16 imageSetId) { loadImageSet(setId, _tileBank[bankId], &_imageSetSubFilesArray[ptrIndex], 0, _paletteTransformationConstant, _hiResImageBuf, _loResImageBuf); } +void EfhEngine::restoreAnimImageSetId() { + _animImageSetId = _oldAnimImageSetId; +} + +void EfhEngine::checkProtection() { + bool successfulCheck = false; + uint protectionItemId = _rnd->getRandomNumber(5); + uint ProtectionArrayId = _rnd->getRandomNumber(14); + _unkVideoRelatedWord1 = 0xE; + + //CHECKME : Well, yeah, some code may be missing there. Who knows. + + _protectionPassed = true; + sub15150(true); +} + +void EfhEngine::loadGame() { + // The original used a loop to check for the presence of the savegame on the current floppy. + // When the savegame wasn't found, it was displaying a screen asking for Disk 1 and was setting a flag used + // to call a function after loading right before returning. + // + // The savegame is used to initialize the engine, so this part is reimplemented. + // The check for existence is replaced by an error. + // + // Fun fact : it was therefore expected to overwrite the original savegame on the floppy each time you saved. What could possibly go wrong? + + Common::String fileName = "gendata\\savegame"; + Common::File f; + + if (!f.open(fileName)) + error("Missing file %s", fileName.c_str()); + + _techId = f.readSint16LE(); + _fullPlaceId = f.readUint16LE(); + _guessAnimationAmount = f.readSint16LE(); + _largeMapFlag = f.readUint16LE(); + _teamCharIdArray = f.readSint16LE(); + _charId = f.readSint16LE(); + _word2C8B8 = f.readSint16LE(); + + for (int i = 0; i < 3; ++i) { + _teamCharStatus[i]._status = f.readSint16LE(); + _teamCharStatus[i]._duration = f.readSint16LE(); + } + + _teamSize = f.readSint16LE(); + + for (int i = 0; i < 3; ++i) { + _unkArray2C8AA[i] = f.readSint16LE(); + } + + _word2C872 = f.readSint16LE(); + + _imageSetSubFilesIdx = f.readSint16LE(); + _mapPosX = f.readSint16LE(); + _mapPosY = f.readSint16LE(); + _techDataId_MapPosX = f.readSint16LE(); + _techDataId_MapPosY = f.readSint16LE(); + + f.close(); + + _oldMapPosX = _mapPosX; + _oldMapPosY = _mapPosY; + _unkRelatedToAnimImageSetId = 0; + loadNPCS(); + + loadHistory(); + loadTechMapImp(_techId); + + _lastMainPlaceId = 0xFFFF; + loadPlacesFile(_fullPlaceId, 0, true); +} + +void EfhEngine::uncompressBuffer(uint8 *compressedBuf, uint8 *destBuf) { + warning("TODO: uncompressBuffer"); +} + +void EfhEngine::copyCurrentPlaceToBuffer(int id) { + warning("STUB - copyCurrentPlaceToBuffer"); +} + void EfhEngine::sub10B77_unkDisplayFct1(uint8 *imagePtr, int16 posX, int16 posY, uint8 guess_paletteTransformation) { uint16 height = READ_LE_INT16(imagePtr); uint16 width = READ_LE_INT16(imagePtr + 2); diff --git a/engines/efh/efh.h b/engines/efh/efh.h index c6f137cd143a..40a1b612b148 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -94,6 +94,11 @@ struct BufferBM { uint16 _fieldD; }; +struct CharStatus { + int16 _status; + int16 _duration; +}; + class EfhEngine : public Engine { public: EfhEngine(OSystem *syst, const EfhGameDescription *gd); @@ -103,7 +108,6 @@ class EfhEngine : public Engine { Graphics::Surface *_mainSurface; Common::RandomSource *_rnd; - const EfhGameDescription *_gameDescription; uint32 getFeatures() const; const char *getGameId() const; @@ -140,28 +144,46 @@ class EfhEngine : public Engine { void findMapFile(int16 mapId); void loadNewPortrait(); void loadAnimImageSet(); + void loadHistory(); + void loadTechMapImp(int16 fileId); + void loadPlacesFile(uint16 fullPlaceId, int16 unused, bool forceReloadFl); void drawUnknownMenuBox(); void displayAnimFrame(); void displayAnimFrames(int16 animId, bool displayMenuBoxFl); void readTileFact(); void readItems(); void loadNPCS(); + void setDefaultNoteDuration(); + Common::KeyCode playSong(uint8 *buffer); + void decryptImpFile(bool techMapFl); + void readImpFile(int16 id, bool techMapFl); + Common::KeyCode getLastCharAfterAnimCount(int16 delay); void initEngine(); + void initMapMonsters(); void saveAnimImageSetId(); - void sub15150(int i); - void sub12A7F(); void displayLowStatusScreen(int i); void loadImageSet(int imageSetId, uint8 *buffer, uint8 **subFilesArray, char CGAVal, char EGAVal, uint8 *destBuffer, uint8 *transfBuffer); void displayFctFullScreen(); void displayBitmapAtPos(int16 minX, int16 minY, int16 maxX, int16 maxY); + void displayBitmap(EfhGraphicsStruct *efh_graphics_struct, EfhGraphicsStruct *efh_graphics_struct1, const Common::Rect &rect, int16 min_x, int16 min_y); + void loadImageSetToTileBank(int16 tileBankId, int16 imageSetId); + void restoreAnimImageSetId(); + void checkProtection(); + void loadGame(); + void uncompressBuffer(uint8 *compressedBuf, uint8 *destBuf); + void copyCurrentPlaceToBuffer(int id); + + void sub15150(bool flag); + void sub12A7F(); void sub10B77_unkDisplayFct1(uint8 *imagePtr, int16 posX, int16 posY, uint8 guess_paletteTransformation); void sub24D92(BufferBM *bufferBM, int16 posX, int16 posY); - void loadImageSetToTileBank(int16 tileBankId, int16 imageSetId); + void sub133E5(uint8 *impPtr, int posX, int posY, int maxX, int maxY, int argC); uint8 _videoMode; uint8 _bufferCharBM[128]; int16 _vgaLineBuffer[200]; - EfhGraphicsStruct *_vgaGraphicsStruct; + EfhGraphicsStruct *_vgaGraphicsStruct1; + EfhGraphicsStruct *_vgaGraphicsStruct2; EfhGraphicsStruct *_graphicsStruct; uint8 _tileBank[3][12000]; uint8 _circleImageBuf[40100]; @@ -191,7 +213,8 @@ class EfhEngine : public Engine { uint8 _defaultBoxColor; FontDescr _fontDescr; - uint8 _word31E9E; + uint16 _word31E9E; + uint16 _unkVideoRelatedWord1; int16 _oldAnimImageSetId; int16 _animImageSetId; @@ -205,6 +228,29 @@ class EfhEngine : public Engine { int16 _currentAnimImageSetId; uint8 *_portraitSubFilesArray[20]; int16 _unkAnimRelatedIndex; + uint8 *_imp1PtrArray[100]; + uint8 *_imp2PtrArray[432]; + uint16 _fullPlaceId; + int16 _guessAnimationAmount; + uint16 _largeMapFlag; // CHECKME: bool? + int16 _teamCharIdArray; + int16 _charId; + int16 _word2C8B8; + + Common::Rect _initRect; + bool _engineInitPending; + bool _protectionPassed; + + CharStatus _teamCharStatus[3]; + int16 _unkArray2C8AA[3]; + int16 _teamSize; + int16 _word2C872; + int16 _imageSetSubFilesIdx; + + int16 _mapPosX, _mapPosY; + int16 _oldMapPosX, _oldMapPosY; + int16 _techDataId_MapPosX, _techDataId_MapPosY; + uint16 _lastMainPlaceId; }; } // End of namespace Efh From acec83040bf2815d918debec8bd308d371ee7248 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Mon, 15 Nov 2021 09:12:49 +0100 Subject: [PATCH 053/412] EFH: Implement decompression, add searchman directories --- engines/efh/efh.cpp | 92 ++++++++++++++++++++++++++++++++++++++++----- engines/efh/efh.h | 1 + 2 files changed, 84 insertions(+), 9 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index f521d8906787..b684bebd7055 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -60,6 +60,13 @@ void EfhGraphicsStruct::copy(EfhGraphicsStruct *src) { } EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst), _gameDescription(gd) { + const Common::FSNode gameDataDir(ConfMan.get("path")); + + SearchMan.addSubDirectoryMatching(gameDataDir, "gendata"); + SearchMan.addSubDirectoryMatching(gameDataDir, "images"); + SearchMan.addSubDirectoryMatching(gameDataDir, "imp"); + SearchMan.addSubDirectoryMatching(gameDataDir, "maps"); + _system = syst; _rnd = nullptr; @@ -575,7 +582,7 @@ void EfhEngine::initEngine() { // } // Load Title Screen - loadImageSet(11, (uint8 *)_circleImageBuf, (uint8 **)_circleImageSubFileArray, 0, _paletteTransformationConstant, (uint8 *)_hiResImageBuf, (uint8 *)_loResImageBuf); + loadImageSet(11, _circleImageBuf, _circleImageSubFileArray, 0, _paletteTransformationConstant, _hiResImageBuf, _loResImageBuf); displayFctFullScreen(); sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 0, _paletteTransformationConstant); displayFctFullScreen(); @@ -589,11 +596,11 @@ void EfhEngine::initEngine() { loadImageSetToTileBank(3, 6); // Load 320*200 Menu screen - Common::String fileName = Common::String::format("images\\imageset.%d", 10); + Common::String fileName = Common::String::format("imageset.%d", 10); readFileToBuffer(fileName, _menuBuf); // Load 96*64 Window with pink border and yellow bottom - fileName = Common::String::format("images\\imageset.%d", 12); + fileName = Common::String::format("imageset.%d", 12); readFileToBuffer(fileName, _windowWithBorderBuf); readAnimInfo(); @@ -676,7 +683,7 @@ void EfhEngine::initEngine() { } loadImageSet(6, _circleImageBuf, _circleImageSubFileArray, 0, _paletteTransformationConstant, _hiResImageBuf, _loResImageBuf); - readImpFile(99, 0); + readImpFile(99, false); _word31E9E = 0xFFFF; restoreAnimImageSetId(); @@ -708,7 +715,27 @@ void EfhEngine::displayLowStatusScreen(int i) { } void EfhEngine::loadImageSet(int imageSetId, uint8 *buffer, uint8 **subFilesArray, char CGAVal, char EGAVal, uint8 *destBuffer, uint8 *transfBuffer) { - warning("STUB - loadImageSet"); + Common::String fileName = Common::String::format("imageset.%d", imageSetId); + rImageFile(fileName, buffer, subFilesArray, CGAVal, EGAVal, destBuffer, transfBuffer); +} + +void EfhEngine::rImageFile(Common::String filename, uint8 *buffer, uint8 **subFilesArray, char CGAVal, char EGAVal, uint8 *packedBuffer, uint8 *targetBuffer) { + readFileToBuffer(filename, packedBuffer); + uncompressBuffer(packedBuffer, targetBuffer); + + // TODO: Refactoring: once uncompressed, the container contains for each image its width, its height, and raw data (1 Bpp) + // => Write a class to handle that more properly + uint8 *ptr = targetBuffer; + uint16 counter = 0; + while (READ_LE_INT16(ptr) != 0) { + subFilesArray[counter] = ptr; + ++counter; + int16 imageWidth = READ_LE_INT16(ptr); + ptr += 2; + int16 imageHeight = READ_LE_INT16(ptr); + ptr += 2; + ptr += (imageWidth * imageHeight); + } } void EfhEngine::displayFctFullScreen() { @@ -757,9 +784,9 @@ void EfhEngine::restoreAnimImageSetId() { } void EfhEngine::checkProtection() { - bool successfulCheck = false; - uint protectionItemId = _rnd->getRandomNumber(5); - uint ProtectionArrayId = _rnd->getRandomNumber(14); + // bool successfulCheck = false; + // uint8 protectionItemId = _rnd->getRandomNumber(5); + // uint8 ProtectionArrayId = _rnd->getRandomNumber(14); _unkVideoRelatedWord1 = 0xE; //CHECKME : Well, yeah, some code may be missing there. Who knows. @@ -826,7 +853,54 @@ void EfhEngine::loadGame() { } void EfhEngine::uncompressBuffer(uint8 *compressedBuf, uint8 *destBuf) { - warning("TODO: uncompressBuffer"); + if (compressedBuf == nullptr || destBuf == nullptr) + error("uncompressBuffer - Invalid pointer used in parameter list"); + + uint8 *curPtrDest = destBuf; + + uint16 compSize = READ_LE_UINT16(compressedBuf) + 1; + uint8 *curPtrCompressed = compressedBuf + 2; + + for (;;) { + uint8 next = *curPtrCompressed; + ++curPtrCompressed; + --compSize; + if (compSize == 0) + break; + + if (next != 0xC3) { + *curPtrDest = next; + ++curPtrDest; + continue; + } + + next = *curPtrCompressed; + ++curPtrCompressed; + --compSize; + if (compSize == 0) + break; + + if (next == 0) { + *curPtrDest = 0xC3; + ++curPtrDest; + continue; + } + + uint8 loopVal = next; + next = *curPtrCompressed; + ++curPtrCompressed; + + for (int i = 0; i < loopVal; ++i) { + *curPtrDest = next; + ++curPtrDest; + } + + --compSize; + if (compSize == 0) + break; + } + + curPtrDest[0] = curPtrDest[1] = 0; } void EfhEngine::copyCurrentPlaceToBuffer(int id) { diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 40a1b612b148..4e71f618b423 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -163,6 +163,7 @@ class EfhEngine : public Engine { void saveAnimImageSetId(); void displayLowStatusScreen(int i); void loadImageSet(int imageSetId, uint8 *buffer, uint8 **subFilesArray, char CGAVal, char EGAVal, uint8 *destBuffer, uint8 *transfBuffer); + void rImageFile(Common::String filename, uint8 *buffer, uint8 **subFilesArray, char CGAVal, char EGAVal, uint8 *packedBuffer, uint8 *targetBuffer); void displayFctFullScreen(); void displayBitmapAtPos(int16 minX, int16 minY, int16 maxX, int16 maxY); void displayBitmap(EfhGraphicsStruct *efh_graphics_struct, EfhGraphicsStruct *efh_graphics_struct1, const Common::Rect &rect, int16 min_x, int16 min_y); From ed94879a48ca8bfd50ee5c756e5dd0313b8cc91e Mon Sep 17 00:00:00 2001 From: Strangerke Date: Tue, 16 Nov 2021 08:09:10 +0100 Subject: [PATCH 054/412] EFH: Clean decompression code, add DumpFile, fix some uselessly specified paths --- engines/efh/efh.cpp | 70 ++++++++++++++++++++++++--------------------- engines/efh/efh.h | 2 +- 2 files changed, 39 insertions(+), 33 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index b684bebd7055..b9ea836fe5ff 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -226,7 +226,7 @@ int32 EfhEngine::readFileToBuffer(Common::String &filename, uint8 *destBuffer) { } void EfhEngine::readAnimInfo() { - Common::String fileName = "gendata\\animinfo"; + Common::String fileName = "animinfo"; readFileToBuffer(fileName, _animInfo); } @@ -234,7 +234,7 @@ void EfhEngine::findMapFile(int16 mapId) { if (_word31E9E == 0) return; - Common::String fileName = Common::String::format("map\\map.%d", mapId); + Common::String fileName = Common::String::format("map.%d", mapId); Common::File f; // The original was checking for the file and eventually asking to change floppies if (!f.open(fileName)) @@ -271,7 +271,7 @@ void EfhEngine::loadAnimImageSet() { } void EfhEngine::loadHistory() { - Common::String fileName = "gendata\\history"; + Common::String fileName = "history"; readFileToBuffer(fileName, _history); } @@ -282,11 +282,11 @@ void EfhEngine::loadTechMapImp(int16 fileId) { _techId = fileId; findMapFile(_techId); - Common::String fileName = Common::String::format("maps\\tech.%d", _techId); + Common::String fileName = Common::String::format("tech.%d", _techId); readFileToBuffer(fileName, _hiResImageBuf); uncompressBuffer(_hiResImageBuf, _techData); - fileName = Common::String::format("maps\\map.%d", _techId); + fileName = Common::String::format("map.%d", _techId); readFileToBuffer(fileName, _hiResImageBuf); uncompressBuffer(_hiResImageBuf, _map); @@ -311,7 +311,7 @@ void EfhEngine::loadPlacesFile(uint16 fullPlaceId, int16 unused, bool forceReloa if (_fullPlaceId < minPlace || _fullPlaceId > maxPlace || forceReloadFl) { _lastMainPlaceId = _fullPlaceId / 20; - Common::String fileName = Common::String::format("maps\\places.%d", _lastMainPlaceId); + Common::String fileName = Common::String::format("places.%d", _lastMainPlaceId); readFileToBuffer(fileName, _hiResImageBuf); uncompressBuffer(_hiResImageBuf, _places); } @@ -350,17 +350,17 @@ void EfhEngine::displayAnimFrames(int16 animId, bool displayMenuBoxFl) { } void EfhEngine::readTileFact() { - Common::String fileName = "gendata\\tilefact"; + Common::String fileName = "tilefact"; readFileToBuffer(fileName, _tileFact); } void EfhEngine::readItems() { - Common::String fileName = "gendata\\items"; + Common::String fileName = "items"; readFileToBuffer(fileName, _items); } void EfhEngine::loadNPCS() { - Common::String fileName = "gendata\\npcs"; + Common::String fileName = "npcs"; readFileToBuffer(fileName, _npcBuf); } @@ -383,7 +383,7 @@ void EfhEngine::decryptImpFile(bool techMapFl) { } void EfhEngine::readImpFile(int16 id, bool techMapFl) { - Common::String fileName = Common::String::format("imp\\imp.%d", id); + Common::String fileName = Common::String::format("imp.%d", id); if (techMapFl) readFileToBuffer(fileName, _imp1); @@ -613,7 +613,7 @@ void EfhEngine::initEngine() { // Load picture room with girlfriend loadImageSet(62, _circleImageBuf, _circleImageSubFileArray, 0, _paletteTransformationConstant, _hiResImageBuf, _loResImageBuf); - fileName = "gendata\\titlsong"; + fileName = "titlsong"; readFileToBuffer(fileName, _titleSong); setDefaultNoteDuration(); Common::KeyCode lastInput = playSong(_titleSong); @@ -721,8 +721,13 @@ void EfhEngine::loadImageSet(int imageSetId, uint8 *buffer, uint8 **subFilesArra void EfhEngine::rImageFile(Common::String filename, uint8 *buffer, uint8 **subFilesArray, char CGAVal, char EGAVal, uint8 *packedBuffer, uint8 *targetBuffer) { readFileToBuffer(filename, packedBuffer); - uncompressBuffer(packedBuffer, targetBuffer); - + uint32 size = uncompressBuffer(packedBuffer, targetBuffer); + // TODO: Keep this dump for debug purposes only + Common::DumpFile dump; + dump.open(filename + ".dump"); + dump.write(targetBuffer, size); + // End of dump + // TODO: Refactoring: once uncompressed, the container contains for each image its width, its height, and raw data (1 Bpp) // => Write a class to handle that more properly uint8 *ptr = targetBuffer; @@ -805,7 +810,7 @@ void EfhEngine::loadGame() { // // Fun fact : it was therefore expected to overwrite the original savegame on the floppy each time you saved. What could possibly go wrong? - Common::String fileName = "gendata\\savegame"; + Common::String fileName = "savegame"; Common::File f; if (!f.open(fileName)) @@ -852,7 +857,7 @@ void EfhEngine::loadGame() { loadPlacesFile(_fullPlaceId, 0, true); } -void EfhEngine::uncompressBuffer(uint8 *compressedBuf, uint8 *destBuf) { +uint32 EfhEngine::uncompressBuffer(uint8 *compressedBuf, uint8 *destBuf) { if (compressedBuf == nullptr || destBuf == nullptr) error("uncompressBuffer - Invalid pointer used in parameter list"); @@ -861,38 +866,36 @@ void EfhEngine::uncompressBuffer(uint8 *compressedBuf, uint8 *destBuf) { uint16 compSize = READ_LE_UINT16(compressedBuf) + 1; uint8 *curPtrCompressed = compressedBuf + 2; + // Not in the original. This has been added for debug purposes (the original function doesn't return a value) + uint32 decompSize = 0; + for (;;) { - uint8 next = *curPtrCompressed; - ++curPtrCompressed; - --compSize; - if (compSize == 0) + uint8 next = *curPtrCompressed++; + if (--compSize <= 0) break; if (next != 0xC3) { - *curPtrDest = next; - ++curPtrDest; + *curPtrDest++ = next; + ++decompSize; continue; } - next = *curPtrCompressed; - ++curPtrCompressed; - --compSize; - if (compSize == 0) + next = *curPtrCompressed++; + if (--compSize <= 0) break; if (next == 0) { - *curPtrDest = 0xC3; - ++curPtrDest; + *curPtrDest++ = 0xC3; + ++decompSize; continue; } - + uint8 loopVal = next; - next = *curPtrCompressed; - ++curPtrCompressed; + next = *curPtrCompressed++; for (int i = 0; i < loopVal; ++i) { - *curPtrDest = next; - ++curPtrDest; + *curPtrDest++ = next; + ++decompSize; } --compSize; @@ -901,6 +904,9 @@ void EfhEngine::uncompressBuffer(uint8 *compressedBuf, uint8 *destBuf) { } curPtrDest[0] = curPtrDest[1] = 0; + decompSize += 2; + + return decompSize; } void EfhEngine::copyCurrentPlaceToBuffer(int id) { diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 4e71f618b423..22b5263e67f5 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -171,7 +171,7 @@ class EfhEngine : public Engine { void restoreAnimImageSetId(); void checkProtection(); void loadGame(); - void uncompressBuffer(uint8 *compressedBuf, uint8 *destBuf); + uint32 uncompressBuffer(uint8 *compressedBuf, uint8 *destBuf); void copyCurrentPlaceToBuffer(int id); void sub15150(bool flag); From 0ba647297900d8be40330a8842af3539b034308f Mon Sep 17 00:00:00 2001 From: Strangerke Date: Tue, 16 Nov 2021 09:14:40 +0100 Subject: [PATCH 055/412] EFH : Add some more functions --- engines/efh/efh.cpp | 91 +++++++++++++++++++++++++++++++++++++++++++-- engines/efh/efh.h | 12 ++++++ 2 files changed, 100 insertions(+), 3 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index b9ea836fe5ff..2849ff1c98ef 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -156,6 +156,8 @@ EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst) _techDataId_MapPosX = _techDataId_MapPosY = 31; _lastMainPlaceId = 0; + _word2C86E = 0; + _dword2C856 = nullptr; } EfhEngine::~EfhEngine() { @@ -687,11 +689,12 @@ void EfhEngine::initEngine() { _word31E9E = 0xFFFF; restoreAnimImageSetId(); - // Save int 24h, set new int24 to handle fatal failure + // Note: The original at this point saves int 24h and sets a new int24 to handle fatal failure + checkProtection(); loadGame(); _engineInitPending = false; - } +} void EfhEngine::initMapMonsters() { warning("STUB - initMapMonsters"); @@ -703,7 +706,28 @@ void EfhEngine::saveAnimImageSetId() { } void EfhEngine::sub15150(bool flag) { - warning("STUB - sub15150"); + uint8 mapTileInfo = getMapTileInfo(_mapPosX, _mapPosY); + int16 imageSetId = _currentTileBankImageSetId[mapTileInfo / 72]; + + int16 mapImageSetId = (imageSetId * 72) + (mapTileInfo % 72); + // CHECKME : Why do we compute this Id if we don't use it? + + for (int counter = 0; counter < 2; ++counter) { + if (counter == 0 || flag) { + sub1512B(); + // TODO: _word2C86E is some kind of counter + if (_word2C86E != 0) { + // TODO: _dword2C856 is most likely an "Imp" Array + // Note: the original was doing the check in the opposite order, which looks really suspicious + if ((_dword2C856 != nullptr) && (_dword2C856[0] != 0x30)) { + sub221FA(_dword2C856, false); + } + } + } + + if (counter == 0 && flag) + displayFctFullScreen(); + } } void EfhEngine::sub12A7F() { @@ -767,6 +791,46 @@ void EfhEngine::sub133E5(uint8 *impPtr, int posX, int posY, int maxX, int maxY, warning("STUB - sub133E5"); } +void EfhEngine::sub1512B() { + displayFullScreenColoredMenuBox(0); + sub15094(); + sub150EE(); + sub15018(); + displayAnimFrame(); + displayLowStatusScreen(0); +} + +void EfhEngine::sub221FA(uint8 *impArray, bool flag) { + for (uint8 counter = 0; counter < 2; ++counter) { + if (counter == 0 || flag) { + drawMenuBox(16, 115, 111, 133, 0); + if (impArray != nullptr) { + _word2C86E = 4; + _dword2C856 = impArray; + sub133E5(impArray, 17, 115, 110, 133, 0); + } + } + } +} + +void EfhEngine::sub15094() { + sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 0, _paletteTransformationConstant); + sub10B77_unkDisplayFct1(_circleImageSubFileArray[1], 112, 0, _paletteTransformationConstant); + sub10B77_unkDisplayFct1(_circleImageSubFileArray[3], 16, 0, _paletteTransformationConstant); +} + +void EfhEngine::sub150EE() { + sub10B77_unkDisplayFct1(_circleImageSubFileArray[2], 304, 0, _paletteTransformationConstant); + sub10B77_unkDisplayFct1(_circleImageSubFileArray[4], 128, 0, _paletteTransformationConstant); +} + +void EfhEngine::sub15018() { + sub10B77_unkDisplayFct1(_circleImageSubFileArray[7], 16, 136, _paletteTransformationConstant); + sub10B77_unkDisplayFct1(_circleImageSubFileArray[8], 16, 192, _paletteTransformationConstant); + sub10B77_unkDisplayFct1(_circleImageSubFileArray[5], 0, 136, _paletteTransformationConstant); + sub10B77_unkDisplayFct1(_circleImageSubFileArray[6], 304, 136, _paletteTransformationConstant); +} + void EfhEngine::loadImageSetToTileBank(int16 tileBankId, int16 imageSetId) { // TODO: all the values of titleBankId and imageSetId are hardcoded. When all the calls are implemented, fix the values to avoid to have to decrease them int16 bankId = tileBankId - 1; @@ -909,6 +973,27 @@ uint32 EfhEngine::uncompressBuffer(uint8 *compressedBuf, uint8 *destBuf) { return decompSize; } +uint8 EfhEngine::getMapTileInfo(int16 mapPosX, int16 mapPosY) { + int size = _largeMapFlag ? 32 : 24; + + return _mapGameMapPtr[mapPosX * size + mapPosY]; +} + +void EfhEngine::drawBox(int minX, int minY, int maxX, int maxY) { + warning("STUB - drawBox"); +} + +void EfhEngine::drawMenuBox(int minX, int minY, int maxX, int maxY, int color) { + uint8 oldValue = _defaultBoxColor; + _defaultBoxColor = color; + drawBox(minX, minY, maxX, maxY); + _defaultBoxColor = oldValue; +} + +void EfhEngine::displayFullScreenColoredMenuBox(int color) { + drawMenuBox(0, 0, 320, 200, color); +} + void EfhEngine::copyCurrentPlaceToBuffer(int id) { warning("STUB - copyCurrentPlaceToBuffer"); } diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 22b5263e67f5..40c8a9873e1f 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -173,12 +173,21 @@ class EfhEngine : public Engine { void loadGame(); uint32 uncompressBuffer(uint8 *compressedBuf, uint8 *destBuf); void copyCurrentPlaceToBuffer(int id); + uint8 getMapTileInfo(int16 mapPosX, int16 mapPosY); + void drawBox(int minX, int minY, int maxX, int maxY); + void drawMenuBox(int minX, int minY, int maxX, int maxY, int color); + void displayFullScreenColoredMenuBox(int color); void sub15150(bool flag); void sub12A7F(); void sub10B77_unkDisplayFct1(uint8 *imagePtr, int16 posX, int16 posY, uint8 guess_paletteTransformation); void sub24D92(BufferBM *bufferBM, int16 posX, int16 posY); void sub133E5(uint8 *impPtr, int posX, int posY, int maxX, int maxY, int argC); + void sub1512B(); + void sub221FA(uint8 *impArray, bool flag); + void sub15094(); + void sub150EE(); + void sub15018(); uint8 _videoMode; uint8 _bufferCharBM[128]; @@ -252,6 +261,9 @@ class EfhEngine : public Engine { int16 _oldMapPosX, _oldMapPosY; int16 _techDataId_MapPosX, _techDataId_MapPosY; uint16 _lastMainPlaceId; + + uint8 _word2C86E; + uint8 *_dword2C856; }; } // End of namespace Efh From 825d755a63df8436aea5bd16643d8a45449b6b81 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Wed, 17 Nov 2021 00:25:29 +0100 Subject: [PATCH 056/412] EFH: Fix issue in loadTechMapImp --- engines/efh/efh.cpp | 52 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 2849ff1c98ef..885afb253d11 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -292,8 +292,8 @@ void EfhEngine::loadTechMapImp(int16 fileId) { readFileToBuffer(fileName, _hiResImageBuf); uncompressBuffer(_hiResImageBuf, _map); - loadImageSetToTileBank(1, _mapBitmapRef[0]); - loadImageSetToTileBank(1, _mapBitmapRef[1]); + loadImageSetToTileBank(1, _mapBitmapRef[0] + 1); + loadImageSetToTileBank(2, _mapBitmapRef[1] + 1); initMapMonsters(); readImpFile(_techId, true); @@ -768,12 +768,11 @@ void EfhEngine::rImageFile(Common::String filename, uint8 *buffer, uint8 **subFi } void EfhEngine::displayFctFullScreen() { - // CHECKME: 200 is in the original but looks suspicious. + // CHECKME: 319 is in the original but looks suspicious. displayBitmapAtPos(0, 0, 319, 200); } void EfhEngine::displayBitmapAtPos(int16 minX, int16 minY, int16 maxX, int16 maxY) { - warning("STUB - displayBitmapAtPos"); _graphicsStruct->copy(_vgaGraphicsStruct2); _initRect = Common::Rect(minX, minY, maxX, maxY); displayBitmap(_vgaGraphicsStruct2, _vgaGraphicsStruct1, _initRect, minX, minY); @@ -784,7 +783,52 @@ void EfhEngine::displayBitmap(EfhGraphicsStruct *efh_graphics_struct, EfhGraphic } void EfhEngine::sub24D92(BufferBM *bufferBM, int16 posX, int16 posY) { + static uint16 byte2C80C[72] = { + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, + 0, 0, 0, 0, 0x3F, 1, 0xC7, 0 + }; + warning("STUB - sub24D92"); + +#if 0 + if (bufferBM == nullptr) + return; + + Common::Rect unkRect; + unkRect.left = posX - bufferBM->_startX; + unkRect.right = unkRect.left + bufferBM->_width - 1; + unkRect.top = posY - bufferBM->_startY; + unkRect.bottom = unkRect.top + bufferBM->_height - 1; + + Common::Rect destRect; + if (!computeLargeRect(_graphicsStruct->_area, &unkRect, &destRect)) + return; + + uint16 bufferFieldA = bufferBM->_fieldA; + int16 deltaMinY = (destRect.top - unkRect.top) * bufferFieldA; + int16 destWidth = destRect.width() + 1; + + int16 deltaMinX = -1; + int16 tmpVal = (destRect.left - unkRect.left) * 2; + + if (tmpVal < 0) + deltaMinX = 0; + + int16 deltaWidth = (unkRect.right - unkRect.left) * 2 - (destRect.right - unkRect.left) * 2 + tmpVal; + + uint8 *si = &bufferBM->_dataPtr[deltaMinY + tmpVal]; + uint8 ch = bufferBM->_paletteTransformation; + uint8 cl = 4; + uint16 var3A = byte2C80C[bufferBM->_fieldD << 3]; + //incomplete +#endif } void EfhEngine::sub133E5(uint8 *impPtr, int posX, int posY, int maxX, int maxY, int argC) { From 2ec0e43a2543637388318dc7e7a86930acc29725 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Thu, 18 Nov 2021 22:55:15 +0100 Subject: [PATCH 057/412] EFH: Implement loadMapMonsters, add encounter monster const array --- engines/efh/constants.cpp | 236 ++++++++++++++++++++++++++++++++++++++ engines/efh/constants.h | 44 +++++++ engines/efh/efh.cpp | 69 ++++++++++- engines/efh/efh.h | 17 +++ engines/efh/module.mk | 1 + 5 files changed, 365 insertions(+), 2 deletions(-) create mode 100644 engines/efh/constants.cpp create mode 100644 engines/efh/constants.h diff --git a/engines/efh/constants.cpp b/engines/efh/constants.cpp new file mode 100644 index 000000000000..79ed75e5d3e2 --- /dev/null +++ b/engines/efh/constants.cpp @@ -0,0 +1,236 @@ +/* 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "efh/constants.h" + +namespace Efh { + +const Encounter _encounters[] { + {"Indian", 0, 5, 50, {64, 64, 68, 70, 92}, 25, 2}, + {"Warrior", 0, 6, 85, {70, 64, 68, 70, 92}, 35, 2}, + {"Tracker", 0, 8, 115, {92, 64, 68, 70, 92}, 38, 2}, + {"Savage", 0, 15, 150, {92, 64, 68, 70, 92}, 50, 2}, + {"Chief", 0, 50, 200, {94, 64, 70, 92, 95}, 95, 2}, + {"Archer", 1, 5, 50, {70, 71, 64, 66, 69}, 35, 2}, + {"Bowman", 1, 10, 50, {70, 71, 64, 66, 69}, 50, 2}, + {"Ranger", 1, 20, 150, {70, 71, 64, 66, 69}, 45, 2}, + {"Censor", 2, 5, 35, {205, 64, 64, 64, 64}, 25, 2}, + {"Noisy Guy", 2, 7, 80, {205, 64, 64, 64, 64}, 27, 2}, + {"Cruiser", 2, 12, 55, {205, 210, 64, 64, 64}, 32, 2}, + {"Boomer", 2, 20, 110, {205, 210, 210, 64, 64}, 45, 2}, + {"Neanderthal", 3, 5, 65, {127, 127, 127, 127, 64}, 25, 2}, + {"Savage", 3, 7, 90, {127, 127, 127, 127, 64}, 35, 2}, + {"Roughian", 3, 15, 110, {127, 127, 127, 87, 64}, 37, 2}, + {"Troglodyte", 3, 20, 135, {127, 127, 127, 127, 64}, 45, 2}, + {"Scuba Guy", 4, 5, 50, {211, 64, 144, 165, 64}, 25, 2}, + {"Diver", 4, 12, 80, {211, 165, 144, 165, 64}, 28, 2}, + {"Surfer", 4, 10, 75, {212, 212, 144, 205, 64}, 30, 2}, + {"Warrior", 4, 15, 100, {66, 69, 68, 64, 66}, 35, 2}, + {"Maniac", 4, 20, 150, {214, 201, 205, 81, 90}, 38, 2}, + {"Loon", 4, 35, 250, {214, 201, 205, 81, 90}, 45, 2}, + {"Crypt Thing", 5, 15, 200, {215, 215, 215, 217, 217}, 35, 2}, + {"Crypt Corpse", 5, 20, 250, {215, 215, 215, 217, 217}, 40, 2}, + {"Zombie", 5, 25, 225, {215, 215, 215, 217, 217}, 45, 2}, + {"Dead Being", 5, 40, 350, {215, 215, 216, 217, 217}, 55, 2}, + {"Despair", 6, 10, 125, {127, 127, 128, 128, 129}, 25, 2}, + {"Apparition", 6, 15, 245, {127, 127, 128, 128, 129}, 29, 2}, + {"Burial Spirit", 6, 25, 300, {127, 128, 128, 129, 129}, 55, 2}, + {"Ghoul", 6, 32, 410, {127, 127, 128, 128, 129}, 70, 2}, + {"Skeleton", 6, 6, 75, {127, 127, 128, 128, 129}, 60, 2}, + {"Soul", 6, 40, 400, {127, 127, 128, 128, 129}, 62, 2}, + {"Projection", 6, 27, 350, {127, 127, 128, 128, 129}, 65, 2}, + {"Cowboy", 7, 5, 150, {90, 90, 90, 90, 91}, 25, 2}, + {"Sheriff", 7, 8, 250, {90, 90, 90, 91, 91}, 35, 2}, + {"Bad Bart", 7, 35, 500, {90, 90, 91, 91, 91}, 95, 2}, + {"Gun Slinger", 7, 20, 380, {90, 90, 91, 91, 91}, 55, 2}, + {"Fast Draw", 7, 17, 290, {90, 91, 91, 91, 91}, 45, 2}, + {"Quick Draw", 7, 30, 420, {90, 91, 92, 93, 92}, 65, 2}, + {"Dinosaur", 8, 35, 200, {128, 128, 128, 126, 126}, 25, 2}, + {"Biped", 8, 50, 225, {128, 128, 128, 126, 126}, 30, 2}, + {"Dino Beast", 8, 65, 250, {128, 128, 128, 126, 126}, 35, 2}, + {"Intellosaur", 8, 80, 380, {128, 128, 128, 126, 126}, 45, 2}, + {"Awful Animal", 8, 105, 495, {128, 128, 128, 126, 126}, 55, 2}, + {"Death Serpent", 9, 60, 450, {94, 97, 98, 99, 135}, 75, 2}, + {"Demon Snake", 9, 80, 580, {97, 98, 94, 99, 137}, 85, 2}, + {"Fire Lizard", 9, 100, 400, {135, 98, 99, 137, 136}, 95, 2}, + {"Winged Demon", 9, 110, 475, {97, 98, 138, 139, 140}, 100, 2}, + {"Duke of Hell", 10, 500, 2000, {137, 138, 139, 140, 135}, 100, 2}, + {"Beach Fiend", 10, 150, 580, {137, 138, 139, 136, 98}, 100, 2}, + {"Arch Devil", 10, 2000, 10000, {98, 97, 98, 140, 139}, 100, 2}, + {"Major Fiend", 10, 195, 666, {98, 99, 98, 99, 137}, 100, 2}, + {"Enforcer", 11, 20, 110, {127, 126, 76, 75, 145}, 25, 2}, + {"Grunt", 11, 30, 150, {163, 127, 161, 165, 152}, 35, 2}, + {"Behemoth", 11, 35, 175, {144, 148, 160, 161, 163}, 45, 2}, + {"Giant Demon", 11, 50, 245, {127, 107, 151, 155, 159}, 55, 2}, + {"Slaver", 11, 42, 225, {127, 124, 114, 115, 121}, 65, 2}, + {"Minor Demon", 12, 6, 100, {73, 73, 130, 130, 130}, 27, 2}, + {"Common Demon", 12, 9, 150, {73, 73, 130, 130, 130}, 30, 2}, + {"Small Demon", 12, 15, 175, {73, 73, 73, 73, 130}, 38, 2}, + {"Simple Demon", 12, 20, 200, {73, 73, 73, 130, 130}, 45, 2}, + {"Lesser Demon", 12, 12, 160, {73, 73, 73, 73, 73}, 32, 2}, + {"Warrior", 13, 7, 50, {65, 65, 66, 66, 64}, 30, 2}, + {"Gladiator", 13, 12, 95, {65, 65, 66, 66, 64}, 35, 2}, + {"Moutaineer", 13, 10, 80, {66, 66, 80, 72, 64}, 45, 2}, + {"Strong Guy", 13, 13, 98, {66, 66, 66, 66, 66}, 55, 2}, + {"Hell Private", 14, 10, 150, {66, 66, 66, 65, 65}, 35, 2}, + {"Hell Corporal", 14, 15, 150, {66, 66, 66, 65, 65}, 40, 2}, + {"Hell Sgt.", 14, 17, 150, {66, 66, 66, 65, 65}, 45, 2}, + {"Hell LT.", 14, 25, 245, {105, 66, 66, 65, 65}, 50, 2}, + {"Hell Guard", 14, 6, 100, {66, 66, 66, 65, 65}, 20, 2}, + {"Hell Soldier", 14, 35, 380, {106, 66, 66, 163, 65}, 65, 2}, + {"Demon Fighter", 14, 40, 400, {106, 105, 163, 65, 65}, 75, 2}, + {"Ice Beast", 15, 25, 650, {69, 69, 69, 68, 68}, 45, 2}, + {"Snow Fiend", 15, 30, 666, {132, 69, 69, 68, 68}, 55, 2}, + {"SalivaMonster", 15, 45, 750, {107, 110, 132, 157, 129}, 65, 2}, + {"Spit Grunt", 15, 40, 666, {107, 110, 132, 157, 129}, 75, 2}, + {"Cold Demon", 15, 42, 666, {107, 110, 68, 69, 69}, 85, 2}, + {"Insectoid", 16, 15, 400, {153, 152, 154, 161, 147}, 35, 2}, + {"Giant Insect", 16, 17, 400, {94, 96, 96, 202, 202}, 45, 2}, + {"Insect Guard", 16, 25, 400, {94, 96, 99, 202, 202}, 55, 2}, + {"Roaming Bug", 16, 35, 450, {94, 96, 99, 136, 134}, 45, 2}, + {"Blade Bug", 16, 45, 590, {135, 158, 156, 202, 202}, 45, 2}, + {"Logger", 17, 7, 125, {89, 78, 89, 89, 64}, 30, 2}, + {"Massacrer", 17, 10, 175, {89, 89, 89, 89, 64}, 35, 2}, + {"Murderer", 17, 12, 225, {89, 89, 89, 79, 64}, 38, 2}, + {"Crazy Guy", 17, 13, 235, {89, 87, 88, 89, 64}, 40, 2}, + {"Massive Dude", 17, 15, 250, {89, 89, 81, 89, 64}, 36, 2}, + {"Chainsaw Guy", 17, 11, 180, {89, 89, 88, 89, 64}, 45, 2}, + {"DevilDaughter", 18, 75, 850, {181, 182, 182, 181, 195}, 100, 2}, + {"Evil Woman", 18, 5, 85, {181, 182, 182, 181, 195}, 35, 2}, + {"Enchantress'", 18, 7, 150, {181, 182, 182, 181, 195}, 40, 2}, // The extra quote is in the original game + {"Temptress'", 18, 9, 200, {181, 182, 182, 181, 195}, 55, 2}, // The extra quote is in the original game + {"Lustivious'", 18, 100, 1750, {181, 182, 196, 197, 197}, 100, 1}, // The extra quote is in the original game + {"Major Demon", 19, 25, 666, {106, 105, 163, 65, 65}, 45, 2}, + {"Giant Demon", 19, 50, 865, {106, 105, 163, 65, 65}, 55, 2}, + {"Gnarly Demon", 19, 75, 999, {106, 105, 163, 65, 65}, 65, 2}, + {"Pit Fiend", 19, 40, 777, {114, 113, 163, 163, 163}, 95, 2}, + {"Hellish Fiend", 19, 80, 1500, {113, 114, 113, 163, 163}, 100, 2}, + {"Monk", 20, 6, 75, {0, 0, 0, 0, 0}, 0, 2}, + {"Unholy Monk", 20, 12, 100, {202, 197, 96, 108, 149}, 30, 2}, + {"Evil Monk", 20, 15, 150, {202, 197, 96, 153, 149}, 33, 2}, + {"Sacrificer", 20, 18, 185, {202, 197, 108, 108, 108}, 37, 2}, + {"Nasty Guy", 20, 25, 200, {202, 197, 96, 153, 149}, 45, 2}, + {"Mutant Demon", 21, 15, 100, {93, 91, 90, 94, 95}, 35, 2}, + {"Hell Captain", 21, 25, 275, {93, 91, 90, 94, 95}, 37, 2}, + {"Muscle Demon", 21, 32, 350, {93, 91, 90, 94, 95}, 40, 2}, + {"Blaster Demon", 21, 60, 690, {93, 91, 90, 94, 95}, 45, 2}, + {"Knight", 22, 15, 150, {133, 133, 150, 128, 128}, 35, 2}, + {"Evil Knight", 22, 25, 200, {133, 150, 116, 122, 128}, 40, 2}, + {"UnJust Knight", 22, 35, 375, {133, 150, 128, 122, 128}, 45, 2}, + {"Astray Knight", 22, 50, 450, {133, 150, 120, 121, 128}, 65, 2}, + {"Anit-Paladin", 22, 75, 750, {109, 115, 128, 128, 128}, 85, 2}, + {"Moaning", 23, 3, 3, {72, 78, 81, 83, 83}, 50, 2}, + {"Tormented", 23, 5, 5, {72, 78, 81, 83, 83}, 50, 2}, + {"Suffering", 23, 4, 4, {72, 78, 81, 83, 83}, 50, 2}, + {"Starving Guy", 23, 2, 2, {72, 78, 81, 83, 83}, 50, 2}, + {"Withered Soul", 23, 1, 1, {72, 78, 81, 83, 83}, 50, 2}, + {"Ogre", 24, 20, 275, {109, 106, 65, 163, 163}, 45, 2}, + {"ElectroKnight", 24, 25, 290, {109, 106, 65, 163, 163}, 55, 2}, + {"Energy Demon", 24, 30, 320, {109, 106, 65, 163, 163}, 55, 2}, + {"Power Devil", 24, 35, 350, {107, 109, 114, 207, 207}, 65, 2}, + {"Sorcerer", 24, 42, 400, {109, 106, 65, 163, 163}, 75, 2}, + {"Enchanter", 24, 35, 350, {109, 106, 65, 163, 163}, 85, 2}, + {"Canon Monk", 28, 35, 100, {0, 0, 0, 0, 0}, 0, 2}, + {"Canon Monk", 28, 35, 100, {0, 0, 0, 0, 0}, 0, 2}, + {"Canon Monk", 28, 35, 100, {0, 0, 0, 0, 0}, 0, 2}, + {"Canon Monk", 28, 35, 100, {0, 0, 0, 0, 0}, 0, 2}, + {"Canon Monk", 28, 35, 100, {0, 0, 0, 0, 0}, 0, 2}, + {"Screamer", 26, 5, 35, {152, 152, 146, 145, 64}, 30, 2}, + {"Moaner", 26, 7, 40, {152, 152, 146, 145, 64}, 35, 2}, + {"Screacher", 26, 12, 85, {152, 152, 146, 145, 64}, 40, 2}, + {"Singer", 26, 15, 100, {152, 152, 146, 145, 64}, 45, 2}, + {"Pilot", 27, 12, 150, {90, 90, 90, 92, 92}, 35, 2}, + {"Crashed Pilot", 27, 20, 200, {90, 90, 90, 92, 92}, 40, 2}, + {"WW I Pilot", 27, 25, 225, {90, 90, 90, 92, 92}, 45, 2}, + {"WW II Pilot", 27, 35, 280, {94, 134, 136, 136, 92}, 55, 2}, + {"Boney Soldier", 27, 45, 350, {90, 134, 136, 137, 138}, 65, 2}, + {"ModernSoldier", 27, 75, 845, {97, 97, 98, 99, 94}, 95, 2}, + {"Surpriser", 28, 10, 100, {100, 101, 102, 103, 104}, 35, 2}, + {"Shocker", 28, 15, 350, {100, 101, 102, 103, 104}, 45, 2}, + {"Blast Monk", 28, 20, 400, {100, 101, 102, 103, 104}, 55, 2}, + {"Canon Monk", 28, 28, 480, {100, 101, 102, 103, 104}, 65, 2}, + {"Killer", 28, 35, 550, {100, 101, 102, 103, 104}, 75, 2}, + {"Rubber Necker", 29, 45, 1000, {152, 153, 144, 111, 112}, 20, 2}, + {"Skull Thing", 29, 60, 1250, {113, 114, 115, 105, 112}, 30, 2}, + {"Laser Eye", 29, 80, 1750, {94, 134, 135, 90, 91}, 40, 2}, + {"Beamer", 29, 100, 2200, {94, 134, 135, 90, 91}, 50, 2}, + {"Hideous Beast", 29, 150, 3500, {94, 134, 135, 90, 91}, 60, 2}, + {"Samurai", 30, 10, 35, {67, 67, 67, 68, 68}, 30, 2}, + {"Ninja", 30, 15, 90, {67, 67, 67, 68, 68}, 32, 2}, + {"SegaSamurai", 30, 20, 150, {67, 67, 67, 68, 68}, 45, 2}, + {"NintendoNinja", 30, 35, 220, {67, 67, 67, 68, 68}, 45, 2}, + {"OrientalSlayr", 30, 45, 250, {67, 67, 67, 68, 68}, 55, 2}, + {"Soldier", 31, 10, 100, {100, 101, 102, 90, 92}, 30, 2}, + {"Fighter", 31, 15, 125, {100, 93, 94, 96, 104}, 35, 2}, + {"Grenader", 31, 20, 175, {100, 101, 102, 103, 104}, 45, 2}, + {"Gunner", 31, 25, 190, {137, 136, 135, 134, 94}, 50, 2}, + {"Scratche", 32, 6, 95, {0, 0, 0, 0, 0}, 0, 2}, + {"Claw", 32, 15, 150, {0, 0, 0, 0, 0}, 0, 2}, + {"Claw Demon", 32, 25, 264, {0, 0, 0, 0, 0}, 0, 2}, + {"Talon Demon", 32, 35, 300, {0, 0, 0, 0, 0}, 0, 2}, + {"Malicioun", 32, 50, 350, {0, 0, 0, 0, 0}, 0, 2}, + {"Imp", 33, 3, 100, {64, 64, 131, 131, 131}, 35, 2}, + {"Tiny Demon", 33, 6, 150, {64, 132, 131, 131, 131}, 40, 2}, + {"Short Devil", 33, 12, 255, {132, 132, 131, 131, 132}, 45, 2}, + {"Gremlin", 33, 25, 300, {64, 64, 131, 131, 131}, 50, 2}, + {"Thug", 34, 8, 175, {93, 93, 94, 92, 95}, 30, 2}, + {"Punk", 34, 15, 250, {93, 93, 94, 92, 95}, 35, 2}, + {"Killer", 34, 18, 275, {93, 93, 94, 92, 95}, 40, 2}, + {"Street Dude", 34, 25, 350, {93, 93, 94, 92, 95}, 45, 2}, + {"Slasher", 35, 5, 190, {131, 131, 131, 131, 131}, 30, 2}, + {"Blade Demon", 35, 15, 250, {132, 131, 131, 131, 131}, 35, 2}, + {"Cleaver Devil", 35, 30, 290, {132, 132, 131, 131, 131}, 45, 2}, + {"Stench Beast", 36, 6, 75, {0, 0, 0, 0, 0}, 0, 2}, + {"Breather", 36, 10, 150, {0, 0, 0, 0, 0}, 0, 2}, + {"Smelly Thing", 36, 15, 175, {0, 0, 0, 0, 0}, 0, 2}, + {"Ugly Devil", 36, 25, 225, {0, 0, 0, 0, 0}, 0, 2}, + {"Surf Nazi", 37, 5, 67, {64, 86, 218, 218, 219}, 30, 2}, + {"Beacher", 37, 8, 95, {64, 86, 218, 218, 219}, 35, 2}, + {"Scum", 37, 12, 125, {64, 86, 218, 218, 219}, 45, 2}, + {"Waste", 37, 18, 150, {64, 86, 218, 218, 219}, 55, 2}, + {"Duelist", 38, 6, 65, {65, 65, 65, 147, 66}, 40, 2}, + {"Sword Guy", 38, 10, 87, {65, 155, 65, 153, 66}, 50, 2}, + {"Muskateer", 38, 15, 97, {65, 65, 154, 66, 66}, 65, 2}, + {"Valkyrie", 39, 7, 37, {65, 65, 65, 66, 66}, 35, 2}, + {"WarriorMaiden", 39, 20, 137, {65, 65, 65, 66, 66}, 55, 2}, + {"Worm King", 40, 150, 4500, {202, 194, 195, 181, 181}, 100, 2}, + {"Worm Lord", 40, 100, 3300, {202, 194, 195, 181, 181}, 100, 2}, + {"Eye of Hell", 40, 60, 1200, {202, 194, 195, 181, 181}, 70, 2}, + {"Visionary", 40, 40, 800, {202, 194, 195, 181, 181}, 55, 2}, + {"Thing", 40, 25, 650, {202, 194, 195, 181, 181}, 45, 2}, + {"Zombie", 41, 10, 450, {97, 97, 98, 98, 127}, 35, 2}, + {"Police Dude", 41, 25, 350, {97, 161, 148, 98, 127}, 45, 2}, + {"Cop", 41, 15, 275, {97, 152, 98, 156, 127}, 30, 2}, + {"Dark Cop", 41, 20, 300, {97, 162, 98, 98, 127}, 35, 2}, + {"Bully Cop", 41, 25, 350, {97, 97, 98, 98, 127}, 45, 2}, + {"Drowning", 42, 10, 50, {0, 0, 0, 0, 0}, 0, 2}, + {"Watery Guy", 42, 35, 150, {0, 0, 0, 0, 0}, 0, 2}, + {"Evangelist", 43, 8, 50, {0, 0, 0, 0, 0}, 0, 2}, + {"Preacher", 43, 15, 150, {0, 0, 0, 0, 0}, 0, 2}, + {"Smooth Talker", 43, 20, 175, {0, 0, 0, 0, 0}, 0, 2}, + {"Hulk", 44, 20, 100, {220, 220, 220, 220, 202}, 32, 0}, + {"MIGHTY Guy", 44, 30, 200, {220, 220, 220, 220, 202}, 43, 2}, + {"Powerful Dude", 44, 45, 400, {220, 220, 220, 220, 202}, 55, 2}, + { "XXXXXXXXXXXXX", 0xFF, 0xFFFF, 0xFFFF, {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF}, 0, 0 } +}; + +} // End of namespace Efh diff --git a/engines/efh/constants.h b/engines/efh/constants.h new file mode 100644 index 000000000000..4a709f8004ef --- /dev/null +++ b/engines/efh/constants.h @@ -0,0 +1,44 @@ +/* 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef EFH_CONSTANTS_H +#define EFH_CONSTANTS_H + +#include "common/scummsys.h" + +namespace Efh { + +struct Encounter { + char _name[14]; + uint8 _animId; + uint16 _pictureRef; + uint16 _xpGiven; + uint16 _dropItemId[5]; + uint8 _dropOccurrencePct; + uint8 _nameArticle; +}; + +extern const Encounter _encounters[]; + +} // End of namespace Efh + +#endif // EFH_CONSTANTS_H diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 885afb253d11..9264dffbe8af 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -29,6 +29,8 @@ #include "graphics/cursorman.h" #include "efh/efh.h" +#include "efh/constants.h" + #include "engines/util.h" namespace Efh { @@ -291,6 +293,9 @@ void EfhEngine::loadTechMapImp(int16 fileId) { fileName = Common::String::format("map.%d", _techId); readFileToBuffer(fileName, _hiResImageBuf); uncompressBuffer(_hiResImageBuf, _map); + // This is not present in the original. + // The purpose is to properly load the mapMonster data in an array of struct in order to use it without being a pain afterwards + loadMapMonsters(); loadImageSetToTileBank(1, _mapBitmapRef[0] + 1); loadImageSetToTileBank(2, _mapBitmapRef[1] + 1); @@ -441,7 +446,24 @@ void EfhEngine::initEngine() { _mapBitmapRef = &_map[0]; _mapUnknownPtr = &_map[2]; - _mapMonstersPtr = &_map[902]; + + // Replaces _mapMonstersPtr which was equal to &_map[902]; + for (int i = 0; i < 64; ++i) { + _mapMonsters[i]._possessivePronounSHL6 = 0; + _mapMonsters[i]._field_1 = 0; + _mapMonsters[i]._guess_fullPlaceId = 0xFF; + _mapMonsters[i]._posX = 0; + _mapMonsters[i]._posY = 0; + _mapMonsters[i]._itemId_Weapon = 0; + _mapMonsters[i]._field_6 = 0; + _mapMonsters[i]._MonsterRef = 0; + _mapMonsters[i]._field_8 = 0; + _mapMonsters[i]._field_9 = 0; + _mapMonsters[i]._groupSize = 0; + for (int j = 0; j < 9; ++j) + _mapMonsters[i]._pictureRef[j] = 0; + } + _mapGameMapPtr = &_map[2758]; _vgaGraphicsStruct2->copy(_vgaGraphicsStruct1); @@ -697,7 +719,50 @@ void EfhEngine::initEngine() { } void EfhEngine::initMapMonsters() { - warning("STUB - initMapMonsters"); + for (uint8 monsterId = 0; monsterId < 64; ++monsterId) { + if (_mapMonsters[monsterId]._guess_fullPlaceId == 0xFF) + continue; + + for (uint8 counter = 0; counter < 9; ++counter) + _mapMonsters[monsterId]._pictureRef[counter] = 0; + + uint8 groupSize = _mapMonsters[monsterId]._groupSize; + if (groupSize == 0) + groupSize = _rnd->getRandomNumber(10); + + for (uint8 counter = 0; counter < groupSize; ++counter) { + uint rand100 = _rnd->getRandomNumber(99) + 1; + uint16 pictureRef = _encounters[_mapMonsters[monsterId]._MonsterRef]._pictureRef; + + if (rand100 <= 25) { + uint16 delta = _rnd->getRandomNumber((pictureRef / 2) - 1) + 1; + _mapMonsters[monsterId]._pictureRef[counter] = pictureRef - delta; + } else if (rand100 <= 75) { + _mapMonsters[monsterId]._pictureRef[counter] = pictureRef; + } else { + uint16 delta = _rnd->getRandomNumber((pictureRef / 2) - 1) + 1; + _mapMonsters[monsterId]._pictureRef[counter] = pictureRef + delta; + } + } + } +} + +void EfhEngine::loadMapMonsters() { + for (int i = 0; i < 64; ++i) { + _mapMonsters[i]._possessivePronounSHL6 = _mapMonstersPtr[29 * i]; + _mapMonsters[i]._field_1 = _mapMonstersPtr[29 * i + 1]; + _mapMonsters[i]._guess_fullPlaceId = _mapMonstersPtr[29 * i + 2]; + _mapMonsters[i]._posX = _mapMonstersPtr[29 * i + 3]; + _mapMonsters[i]._posY = _mapMonstersPtr[29 * i + 4]; + _mapMonsters[i]._itemId_Weapon = _mapMonstersPtr[29 * i + 5]; + _mapMonsters[i]._field_6 = _mapMonstersPtr[29 * i + 6]; + _mapMonsters[i]._MonsterRef = _mapMonstersPtr[29 * i + 7]; + _mapMonsters[i]._field_8 = _mapMonstersPtr[29 * i + 8]; + _mapMonsters[i]._field_9 = _mapMonstersPtr[29 * i + 9]; + _mapMonsters[i]._groupSize = _mapMonstersPtr[29 * i + 10]; + for (int j = 0; j < 9; ++j) + _mapMonsters[i]._pictureRef[j] = READ_LE_UINT16(&_mapMonstersPtr[29 * i + 11 + j * 2]); + } } void EfhEngine::saveAnimImageSetId() { diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 40c8a9873e1f..47dccd733c37 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -99,6 +99,21 @@ struct CharStatus { int16 _duration; }; +struct MapMonster { + uint8 _possessivePronounSHL6; + uint8 _field_1; + uint8 _guess_fullPlaceId; // unsigned? Magic values are 0xFF and 0xFE + uint8 _posX; + uint8 _posY; + uint8 _itemId_Weapon; + uint8 _field_6; + uint8 _MonsterRef; + uint8 _field_8; + uint8 _field_9; + uint8 _groupSize; + uint16 _pictureRef[9]; +}; + class EfhEngine : public Engine { public: EfhEngine(OSystem *syst, const EfhGameDescription *gd); @@ -160,6 +175,7 @@ class EfhEngine : public Engine { Common::KeyCode getLastCharAfterAnimCount(int16 delay); void initEngine(); void initMapMonsters(); + void loadMapMonsters(); void saveAnimImageSetId(); void displayLowStatusScreen(int i); void loadImageSet(int imageSetId, uint8 *buffer, uint8 **subFilesArray, char CGAVal, char EGAVal, uint8 *destBuffer, uint8 *transfBuffer); @@ -218,6 +234,7 @@ class EfhEngine : public Engine { uint8 *_mapBitmapRef; uint8 *_mapUnknownPtr; uint8 *_mapMonstersPtr; + MapMonster _mapMonsters[64]; uint8 *_mapGameMapPtr; uint8 _defaultBoxColor; diff --git a/engines/efh/module.mk b/engines/efh/module.mk index 6b8f7bdee6ca..cd1d0983a97d 100644 --- a/engines/efh/module.mk +++ b/engines/efh/module.mk @@ -1,6 +1,7 @@ MODULE := engines/efh MODULE_OBJS = \ + constants.o \ efh.o \ metaengine.o From 1a2914912c1930969a5eb8098a4f3b61ad1efb17 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Fri, 19 Nov 2021 07:48:44 +0100 Subject: [PATCH 058/412] EFH: Fix crash in previous commit, implement decryptImpFile() --- engines/efh/efh.cpp | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 9264dffbe8af..ea0ed3b8d60c 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -386,7 +386,39 @@ Common::KeyCode EfhEngine::playSong(uint8 *buffer) { } void EfhEngine::decryptImpFile(bool techMapFl) { - warning("STUB - decryptImpFile"); + uint16 counter = 0; + uint16 target; + uint8 *curPtr; + + if (!techMapFl) { + _imp2PtrArray[++counter] = curPtr = _imp2; + target = 431; + } else { + _imp2PtrArray[++counter] = curPtr = _imp1; + target = 99; + } + + do { + *curPtr = (*curPtr - 3) ^ 0xD7; + if (*curPtr == 0x40) { + curPtr += 3; + if (!techMapFl) + _imp2PtrArray[++counter] = curPtr; + else + _imp1PtrArray[++counter] = curPtr; + } else + ++curPtr; + } while (*curPtr != 0x60 && counter <= target); + + Common::DumpFile dump; + if (!techMapFl) { + dump.open("imp2_unc.dump"); + dump.write(_imp2, curPtr - _imp2); + } else { + dump.open("imp1_unc.dump"); + dump.write(_imp1, curPtr - _imp1); + } + dump.close(); } void EfhEngine::readImpFile(int16 id, bool techMapFl) { @@ -748,6 +780,8 @@ void EfhEngine::initMapMonsters() { } void EfhEngine::loadMapMonsters() { + _mapMonstersPtr = &_map[902]; + for (int i = 0; i < 64; ++i) { _mapMonsters[i]._possessivePronounSHL6 = _mapMonstersPtr[29 * i]; _mapMonsters[i]._field_1 = _mapMonstersPtr[29 * i + 1]; From db4dc8ab92d863ddbd4b63bcc266764d3d580f09 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Fri, 19 Nov 2021 07:55:54 +0100 Subject: [PATCH 059/412] EFH: Implement copyCurrentPlaceToBuffer --- engines/efh/efh.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index ea0ed3b8d60c..0368d937cbea 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -1138,7 +1138,10 @@ void EfhEngine::displayFullScreenColoredMenuBox(int color) { } void EfhEngine::copyCurrentPlaceToBuffer(int id) { - warning("STUB - copyCurrentPlaceToBuffer"); + uint8 *placesPtr = &_places[576 * id]; + + // Note that 576 = 24 * 24 + memcpy(_curPlace, placesPtr, 24 * 24); } void EfhEngine::sub10B77_unkDisplayFct1(uint8 *imagePtr, int16 posX, int16 posY, uint8 guess_paletteTransformation) { From e87ddaf1fd2719d3c29db0939d2c080313c057f0 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sat, 20 Nov 2021 02:33:20 +0100 Subject: [PATCH 060/412] EFH: Fix rImageFile, init palette, hack a display function --- engines/efh/efh.cpp | 46 ++++++++++++++++++++++++++++++++++++++++++++- engines/efh/efh.h | 4 ++-- 2 files changed, 47 insertions(+), 3 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 0368d937cbea..e6d3cda5ca12 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -185,6 +185,30 @@ Common::Platform EfhEngine::getPlatform() const { return _platform; } +void EfhEngine::initPalette() { + const uint8 pal[3 * 16] = { + 0, 0, 0, + 0, 0, 170, + 0, 170, 0, + 0, 170, 170, + 170, 0, 0, + 170, 0, 170, + 170, 85, 0, + 170, 170, 170, + 85, 85, 85, + 85, 85, 255, + 1, 1, 1, + 85, 255, 255, + 255, 85, 85, + 255, 85, 255, + 255, 255, 85, + 255, 255, 255 + }; + + _system->getPaletteManager()->setPalette(pal, 0, 16); + _system->updateScreen(); +} + Common::Error EfhEngine::run() { s_Engine = this; initialize(); @@ -192,6 +216,8 @@ Common::Error EfhEngine::run() { _mainSurface = new Graphics::Surface(); _mainSurface->create(320, 200, Graphics::PixelFormat::createFormatCLUT8()); + + initPalette(); /* // Setup mixer syncSoundSettings(); @@ -842,7 +868,7 @@ void EfhEngine::loadImageSet(int imageSetId, uint8 *buffer, uint8 **subFilesArra rImageFile(fileName, buffer, subFilesArray, CGAVal, EGAVal, destBuffer, transfBuffer); } -void EfhEngine::rImageFile(Common::String filename, uint8 *buffer, uint8 **subFilesArray, char CGAVal, char EGAVal, uint8 *packedBuffer, uint8 *targetBuffer) { +void EfhEngine::rImageFile(Common::String filename, uint8 *targetBuffer, uint8 **subFilesArray, char CGAVal, char EGAVal, uint8 *packedBuffer, uint8 *transformedBuf) { readFileToBuffer(filename, packedBuffer); uint32 size = uncompressBuffer(packedBuffer, targetBuffer); // TODO: Keep this dump for debug purposes only @@ -879,6 +905,8 @@ void EfhEngine::displayBitmapAtPos(int16 minX, int16 minY, int16 maxX, int16 max void EfhEngine::displayBitmap(EfhGraphicsStruct *efh_graphics_struct, EfhGraphicsStruct *efh_graphics_struct1, const Common::Rect &rect, int16 min_x, int16 min_y) { warning("STUB - displayBitmap"); + + } void EfhEngine::sub24D92(BufferBM *bufferBM, int16 posX, int16 posY) { @@ -928,6 +956,22 @@ void EfhEngine::sub24D92(BufferBM *bufferBM, int16 posX, int16 posY) { uint16 var3A = byte2C80C[bufferBM->_fieldD << 3]; //incomplete #endif + + + uint8 *destPtr = (uint8 *)_mainSurface->getBasePtr(posX, posY); + warning("%d %d - startX %d startY %d width %d height %d fieldA %d fieldD %d", posX, posY, bufferBM->_startX, bufferBM->_startY, bufferBM->_width, bufferBM->_height, bufferBM->_fieldA, bufferBM->_fieldD); + int counter = 0; + for (int j = 0; j < bufferBM->_height; ++j) { + for (int i = 0; i < bufferBM->_fieldA; ++i) { + destPtr[320 * j + 2 * i] = bufferBM->_dataPtr[counter] >> 4; + destPtr[320 * j + 2 * i + 1] = bufferBM->_dataPtr[counter] & 0xF; + ++counter; + } + } + + _system->copyRectToScreen((byte *)_mainSurface->getPixels(), 320, 0, 0, 320, 200); + _system->updateScreen(); + _system->delayMillis(200); } void EfhEngine::sub133E5(uint8 *impPtr, int posX, int posY, int maxX, int maxY, int argC) { diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 47dccd733c37..c84e07068bbb 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -142,7 +142,6 @@ class EfhEngine : public Engine { protected: Common::EventManager *_eventMan; int _lastTime; - // Engine APIs Common::Error run() override; void handleMenu(); @@ -153,6 +152,7 @@ class EfhEngine : public Engine { GameType _gameType; Common::Platform _platform; + void initPalette(); void initialize(); int32 readFileToBuffer(Common::String &filename, uint8 *destBuffer); void readAnimInfo(); @@ -179,7 +179,7 @@ class EfhEngine : public Engine { void saveAnimImageSetId(); void displayLowStatusScreen(int i); void loadImageSet(int imageSetId, uint8 *buffer, uint8 **subFilesArray, char CGAVal, char EGAVal, uint8 *destBuffer, uint8 *transfBuffer); - void rImageFile(Common::String filename, uint8 *buffer, uint8 **subFilesArray, char CGAVal, char EGAVal, uint8 *packedBuffer, uint8 *targetBuffer); + void rImageFile(Common::String filename, uint8 *targetBuffer, uint8 **subFilesArray, char CGAVal, char EGAVal, uint8 *packedBuffer, uint8 *transformedBuffer); void displayFctFullScreen(); void displayBitmapAtPos(int16 minX, int16 minY, int16 maxX, int16 maxY); void displayBitmap(EfhGraphicsStruct *efh_graphics_struct, EfhGraphicsStruct *efh_graphics_struct1, const Common::Rect &rect, int16 min_x, int16 min_y); From 24aca2246c5634efc140b2a894356b12e808146e Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sat, 20 Nov 2021 09:02:58 +0100 Subject: [PATCH 061/412] EFH: Move font data to constants --- engines/efh/constants.cpp | 108 ++++++++++++++++++++++++++++++++++++ engines/efh/constants.h | 6 ++ engines/efh/efh.cpp | 112 +------------------------------------- engines/efh/efh.h | 13 ++--- 4 files changed, 120 insertions(+), 119 deletions(-) diff --git a/engines/efh/constants.cpp b/engines/efh/constants.cpp index 79ed75e5d3e2..6ccc10c048b4 100644 --- a/engines/efh/constants.cpp +++ b/engines/efh/constants.cpp @@ -23,6 +23,114 @@ #include "efh/constants.h" namespace Efh { +const uint8 fontWidthArray[96] = { + 3, 2, 3, 5, 5, 5, 5, 2, 3, 3, 5, 5, 3, 3, 2, 7, 4, 3, 4, 4, 5, 4, 4, 4, 4, 4, 3, 4, 4, 5, 4, 5, 1, 4, 4, 4, + 4, 4, 4, 4, 4, 3, 4, 4, 4, 7, 5, 4, 4, 4, 4, 4, 5, 4, 5, 7, 5, 5, 5, 3, 7, 3, 5, 0, 2, 4, 4, 4, 4, 4, 4, 4, + 4, 1, 2, 4, 1, 7, 4, 4, 4, 4, 4, 4, 3, 4, 5, 7, 4, 4, 5, 3, 0, 3, 0, 0}; + +const uint8 fontExtraLinesArray[96] = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 3, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 0, 1, 0, 0}; + +const Font fontData[96] = { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x80, 0x00}, + {0xA0, 0xA0, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x50, 0xF8, 0x50, 0xF8, 0x50, 0x00, 0x00}, + {0x20, 0x78, 0xA0, 0x70, 0x28, 0xF0, 0x20, 0x00}, + {0xC8, 0xC8, 0x10, 0x20, 0x40, 0x98, 0x98, 0x00}, + {0x20, 0x50, 0x20, 0x40, 0xA8, 0x90, 0x68, 0x00}, + {0x40, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x40, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x40}, + {0x40, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x40}, + {0x00, 0xA8, 0x70, 0xF8, 0x70, 0xA8, 0x00, 0x00}, + {0x00, 0x20, 0x20, 0xF8, 0x20, 0x20, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x40}, + {0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00}, + {0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00}, + {0x60, 0x90, 0x90, 0x90, 0x90, 0x90, 0x60, 0x00}, + {0x40, 0xC0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00}, + {0x60, 0x90, 0x10, 0x20, 0x40, 0x80, 0xF0, 0x00}, + {0x60, 0x90, 0x10, 0x20, 0x10, 0x90, 0x60, 0x00}, + {0x10, 0x30, 0x50, 0x90, 0xF8, 0x10, 0x10, 0x00}, + {0xF0, 0x80, 0xE0, 0x10, 0x10, 0x90, 0x60, 0x00}, + {0x60, 0x90, 0x80, 0xE0, 0x90, 0x90, 0x60, 0x00}, + {0xF0, 0x10, 0x20, 0x20, 0x40, 0x40, 0x40, 0x00}, + {0x60, 0x90, 0x90, 0x60, 0x90, 0x90, 0x60, 0x00}, + {0x60, 0x90, 0x90, 0x70, 0x10, 0x90, 0x60, 0x00}, + {0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00}, + {0x00, 0x00, 0x20, 0x00, 0x00, 0x20, 0x40, 0x00}, + {0x10, 0x20, 0x40, 0x80, 0x40, 0x20, 0x10, 0x00}, + {0x00, 0x00, 0xF8, 0x00, 0x00, 0xF8, 0x00, 0x00}, + {0x80, 0x40, 0x20, 0x10, 0x20, 0x40, 0x80, 0x00}, + {0x70, 0x88, 0x08, 0x10, 0x20, 0x00, 0x20, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x60, 0x90, 0x90, 0xF0, 0x90, 0x90, 0x90, 0x00}, + {0xE0, 0x90, 0x90, 0xE0, 0x90, 0x90, 0xE0, 0x00}, + {0x60, 0x90, 0x80, 0x80, 0x80, 0x90, 0x60, 0x00}, + {0xE0, 0x90, 0x90, 0x90, 0x90, 0x90, 0xE0, 0x00}, + {0xF0, 0x80, 0x80, 0xE0, 0x80, 0x80, 0xF0, 0x00}, + {0xF0, 0x80, 0x80, 0xE0, 0x80, 0x80, 0x80, 0x00}, + {0x60, 0x90, 0x80, 0xB0, 0x90, 0x90, 0x70, 0x00}, + {0x90, 0x90, 0x90, 0xF0, 0x90, 0x90, 0x90, 0x00}, + {0xE0, 0x40, 0x40, 0x40, 0x40, 0x40, 0xE0, 0x00}, + {0x10, 0x10, 0x10, 0x10, 0x10, 0x90, 0x60, 0x00}, + {0x90, 0x90, 0x90, 0xE0, 0x90, 0x90, 0x90, 0x00}, + {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xF0, 0x00}, + {0x82, 0xC6, 0xAA, 0x92, 0x82, 0x82, 0x82, 0x00}, + {0x88, 0x88, 0xC8, 0xA8, 0x98, 0x88, 0x88, 0x00}, + {0x60, 0x90, 0x90, 0x90, 0x90, 0x90, 0x60, 0x00}, + {0xE0, 0x90, 0x90, 0xE0, 0x80, 0x80, 0x80, 0x00}, + {0x60, 0x90, 0x90, 0x90, 0x90, 0x90, 0x60, 0x10}, + {0xE0, 0x90, 0x90, 0xE0, 0x90, 0x90, 0x90, 0x00}, + {0x60, 0x90, 0x80, 0x60, 0x10, 0x90, 0x60, 0x00}, + {0xF8, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00}, + {0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x60, 0x00}, + {0x88, 0x88, 0x88, 0x50, 0x50, 0x20, 0x20, 0x00}, + {0x82, 0x82, 0x82, 0x92, 0xAA, 0xC6, 0x82, 0x00}, + {0x88, 0x88, 0x50, 0x20, 0x50, 0x88, 0x88, 0x00}, + {0x88, 0x88, 0x50, 0x20, 0x20, 0x20, 0x20, 0x00}, + {0xF8, 0x08, 0x10, 0x20, 0x40, 0x80, 0xF8, 0x00}, + {0xC0, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xC0}, + {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x00}, + {0x60, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x60}, + {0x20, 0x50, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x80, 0x80, 0x40, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x60, 0x10, 0x70, 0x90, 0x70, 0x00}, + {0x80, 0x80, 0xE0, 0x90, 0x90, 0x90, 0xE0, 0x00}, + {0x00, 0x00, 0x60, 0x90, 0x80, 0x90, 0x60, 0x00}, + {0x10, 0x10, 0x70, 0x90, 0x90, 0x90, 0x70, 0x00}, + {0x00, 0x00, 0x60, 0x90, 0xF0, 0x80, 0x60, 0x00}, + {0x30, 0x40, 0xE0, 0x40, 0x40, 0x40, 0x40, 0x00}, + {0x70, 0x90, 0x90, 0x90, 0x70, 0x10, 0xE0, 0x00}, + {0x80, 0x80, 0xE0, 0x90, 0x90, 0x90, 0x90, 0x00}, + {0x80, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00}, + {0x40, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x80}, + {0x80, 0x80, 0x90, 0x90, 0xE0, 0x90, 0x90, 0x00}, + {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00}, + {0x00, 0x00, 0xEC, 0x92, 0x92, 0x92, 0x92, 0x00}, + {0x00, 0x00, 0xE0, 0x90, 0x90, 0x90, 0x90, 0x00}, + {0x00, 0x00, 0x60, 0x90, 0x90, 0x90, 0x60, 0x00}, + {0x00, 0xE0, 0x90, 0x90, 0x90, 0xE0, 0x80, 0x80}, + {0x00, 0x70, 0x90, 0x90, 0x90, 0x70, 0x10, 0x10}, + {0x00, 0x00, 0xB0, 0xC0, 0x80, 0x80, 0x80, 0x00}, + {0x00, 0x00, 0x70, 0x80, 0x60, 0x10, 0xE0, 0x00}, + {0x40, 0x40, 0xE0, 0x40, 0x40, 0x40, 0x40, 0x00}, + {0x00, 0x00, 0x90, 0x90, 0x90, 0x90, 0x70, 0x00}, + {0x00, 0x00, 0x88, 0x50, 0x50, 0x20, 0x20, 0x00}, + {0x00, 0x00, 0x92, 0x92, 0x92, 0x92, 0x6E, 0x00}, + {0x00, 0x00, 0x90, 0x90, 0x60, 0x90, 0x90, 0x00}, + {0x00, 0x90, 0x90, 0x90, 0x90, 0x70, 0x10, 0xE0}, + {0x00, 0x00, 0xF8, 0x10, 0x20, 0x40, 0xF8, 0x00}, + {0x20, 0x40, 0x40, 0x80, 0x40, 0x40, 0x20, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x80, 0x40, 0x40, 0x20, 0x40, 0x40, 0x80, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} +}; const Encounter _encounters[] { {"Indian", 0, 5, 50, {64, 64, 68, 70, 92}, 25, 2}, diff --git a/engines/efh/constants.h b/engines/efh/constants.h index 4a709f8004ef..d64235fd93be 100644 --- a/engines/efh/constants.h +++ b/engines/efh/constants.h @@ -26,6 +26,9 @@ #include "common/scummsys.h" namespace Efh { +struct Font { + uint8 _lines[8]; +}; struct Encounter { char _name[14]; @@ -37,6 +40,9 @@ struct Encounter { uint8 _nameArticle; }; +extern const uint8 fontWidthArray[96]; +extern const uint8 fontExtraLinesArray[96]; +extern const Font fontData[96]; extern const Encounter _encounters[]; } // End of namespace Efh diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index e6d3cda5ca12..86436d494872 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -32,6 +32,7 @@ #include "efh/constants.h" #include "engines/util.h" +#include "graphics/palette.h" namespace Efh { @@ -532,117 +533,6 @@ void EfhEngine::initEngine() { _defaultBoxColor = 7; // Init Font - static uint8 fontWidthArray[96] = { - 3, 2, 3, 5, 5, 5, 5, 2, 3, 3, 5, 5, 3, 3, 2, 7, 4, 3, 4, 4, 5, 4, 4, 4, 4, 4, 3, 4, 4, 5, 4, 5, 1, 4, 4, 4, - 4, 4, 4, 4, 4, 3, 4, 4, 4, 7, 5, 4, 4, 4, 4, 4, 5, 4, 5, 7, 5, 5, 5, 3, 7, 3, 5, 0, 2, 4, 4, 4, 4, 4, 4, 4, - 4, 1, 2, 4, 1, 7, 4, 4, 4, 4, 4, 4, 3, 4, 5, 7, 4, 4, 5, 3, 0, 3, 0, 0 - }; - - static uint8 fontExtraLinesArray[96] = { - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 3, - 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 0, 1, 0, 0 - }; - - static Font fontData[96] = { - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x80, 0x00}, - {0xA0, 0xA0, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x50, 0xF8, 0x50, 0xF8, 0x50, 0x00, 0x00}, - {0x20, 0x78, 0xA0, 0x70, 0x28, 0xF0, 0x20, 0x00}, - {0xC8, 0xC8, 0x10, 0x20, 0x40, 0x98, 0x98, 0x00}, - {0x20, 0x50, 0x20, 0x40, 0xA8, 0x90, 0x68, 0x00}, - {0x40, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x40, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x40}, - {0x40, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x40}, - {0x00, 0xA8, 0x70, 0xF8, 0x70, 0xA8, 0x00, 0x00}, - {0x00, 0x20, 0x20, 0xF8, 0x20, 0x20, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x40}, - {0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00}, - {0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00}, - {0x60, 0x90, 0x90, 0x90, 0x90, 0x90, 0x60, 0x00}, - {0x40, 0xC0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00}, - {0x60, 0x90, 0x10, 0x20, 0x40, 0x80, 0xF0, 0x00}, - {0x60, 0x90, 0x10, 0x20, 0x10, 0x90, 0x60, 0x00}, - {0x10, 0x30, 0x50, 0x90, 0xF8, 0x10, 0x10, 0x00}, - {0xF0, 0x80, 0xE0, 0x10, 0x10, 0x90, 0x60, 0x00}, - {0x60, 0x90, 0x80, 0xE0, 0x90, 0x90, 0x60, 0x00}, - {0xF0, 0x10, 0x20, 0x20, 0x40, 0x40, 0x40, 0x00}, - {0x60, 0x90, 0x90, 0x60, 0x90, 0x90, 0x60, 0x00}, - {0x60, 0x90, 0x90, 0x70, 0x10, 0x90, 0x60, 0x00}, - {0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00}, - {0x00, 0x00, 0x20, 0x00, 0x00, 0x20, 0x40, 0x00}, - {0x10, 0x20, 0x40, 0x80, 0x40, 0x20, 0x10, 0x00}, - {0x00, 0x00, 0xF8, 0x00, 0x00, 0xF8, 0x00, 0x00}, - {0x80, 0x40, 0x20, 0x10, 0x20, 0x40, 0x80, 0x00}, - {0x70, 0x88, 0x08, 0x10, 0x20, 0x00, 0x20, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x60, 0x90, 0x90, 0xF0, 0x90, 0x90, 0x90, 0x00}, - {0xE0, 0x90, 0x90, 0xE0, 0x90, 0x90, 0xE0, 0x00}, - {0x60, 0x90, 0x80, 0x80, 0x80, 0x90, 0x60, 0x00}, - {0xE0, 0x90, 0x90, 0x90, 0x90, 0x90, 0xE0, 0x00}, - {0xF0, 0x80, 0x80, 0xE0, 0x80, 0x80, 0xF0, 0x00}, - {0xF0, 0x80, 0x80, 0xE0, 0x80, 0x80, 0x80, 0x00}, - {0x60, 0x90, 0x80, 0xB0, 0x90, 0x90, 0x70, 0x00}, - {0x90, 0x90, 0x90, 0xF0, 0x90, 0x90, 0x90, 0x00}, - {0xE0, 0x40, 0x40, 0x40, 0x40, 0x40, 0xE0, 0x00}, - {0x10, 0x10, 0x10, 0x10, 0x10, 0x90, 0x60, 0x00}, - {0x90, 0x90, 0x90, 0xE0, 0x90, 0x90, 0x90, 0x00}, - {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xF0, 0x00}, - {0x82, 0xC6, 0xAA, 0x92, 0x82, 0x82, 0x82, 0x00}, - {0x88, 0x88, 0xC8, 0xA8, 0x98, 0x88, 0x88, 0x00}, - {0x60, 0x90, 0x90, 0x90, 0x90, 0x90, 0x60, 0x00}, - {0xE0, 0x90, 0x90, 0xE0, 0x80, 0x80, 0x80, 0x00}, - {0x60, 0x90, 0x90, 0x90, 0x90, 0x90, 0x60, 0x10}, - {0xE0, 0x90, 0x90, 0xE0, 0x90, 0x90, 0x90, 0x00}, - {0x60, 0x90, 0x80, 0x60, 0x10, 0x90, 0x60, 0x00}, - {0xF8, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00}, - {0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x60, 0x00}, - {0x88, 0x88, 0x88, 0x50, 0x50, 0x20, 0x20, 0x00}, - {0x82, 0x82, 0x82, 0x92, 0xAA, 0xC6, 0x82, 0x00}, - {0x88, 0x88, 0x50, 0x20, 0x50, 0x88, 0x88, 0x00}, - {0x88, 0x88, 0x50, 0x20, 0x20, 0x20, 0x20, 0x00}, - {0xF8, 0x08, 0x10, 0x20, 0x40, 0x80, 0xF8, 0x00}, - {0xC0, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xC0}, - {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x00}, - {0x60, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x60}, - {0x20, 0x50, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x80, 0x80, 0x40, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x60, 0x10, 0x70, 0x90, 0x70, 0x00}, - {0x80, 0x80, 0xE0, 0x90, 0x90, 0x90, 0xE0, 0x00}, - {0x00, 0x00, 0x60, 0x90, 0x80, 0x90, 0x60, 0x00}, - {0x10, 0x10, 0x70, 0x90, 0x90, 0x90, 0x70, 0x00}, - {0x00, 0x00, 0x60, 0x90, 0xF0, 0x80, 0x60, 0x00}, - {0x30, 0x40, 0xE0, 0x40, 0x40, 0x40, 0x40, 0x00}, - {0x70, 0x90, 0x90, 0x90, 0x70, 0x10, 0xE0, 0x00}, - {0x80, 0x80, 0xE0, 0x90, 0x90, 0x90, 0x90, 0x00}, - {0x80, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00}, - {0x40, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x80}, - {0x80, 0x80, 0x90, 0x90, 0xE0, 0x90, 0x90, 0x00}, - {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00}, - {0x00, 0x00, 0xEC, 0x92, 0x92, 0x92, 0x92, 0x00}, - {0x00, 0x00, 0xE0, 0x90, 0x90, 0x90, 0x90, 0x00}, - {0x00, 0x00, 0x60, 0x90, 0x90, 0x90, 0x60, 0x00}, - {0x00, 0xE0, 0x90, 0x90, 0x90, 0xE0, 0x80, 0x80}, - {0x00, 0x70, 0x90, 0x90, 0x90, 0x70, 0x10, 0x10}, - {0x00, 0x00, 0xB0, 0xC0, 0x80, 0x80, 0x80, 0x00}, - {0x00, 0x00, 0x70, 0x80, 0x60, 0x10, 0xE0, 0x00}, - {0x40, 0x40, 0xE0, 0x40, 0x40, 0x40, 0x40, 0x00}, - {0x00, 0x00, 0x90, 0x90, 0x90, 0x90, 0x70, 0x00}, - {0x00, 0x00, 0x88, 0x50, 0x50, 0x20, 0x20, 0x00}, - {0x00, 0x00, 0x92, 0x92, 0x92, 0x92, 0x6E, 0x00}, - {0x00, 0x00, 0x90, 0x90, 0x60, 0x90, 0x90, 0x00}, - {0x00, 0x90, 0x90, 0x90, 0x90, 0x70, 0x10, 0xE0}, - {0x00, 0x00, 0xF8, 0x10, 0x20, 0x40, 0xF8, 0x00}, - {0x20, 0x40, 0x40, 0x80, 0x40, 0x40, 0x20, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x80, 0x40, 0x40, 0x20, 0x40, 0x40, 0x80, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} - }; - _fontDescr._widthArray = fontWidthArray; _fontDescr._extraLines = fontExtraLinesArray; _fontDescr._fontData = fontData; diff --git a/engines/efh/efh.h b/engines/efh/efh.h index c84e07068bbb..77f91d66dded 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -24,15 +24,16 @@ #define EFH_EFH_H #include "efh/detection.h" +#include "efh/constants.h" #include "common/file.h" #include "common/rect.h" #include "common/events.h" #include "engines/engine.h" -#include "graphics/palette.h" #include "graphics/surface.h" + namespace Common { class RandomSource; } @@ -70,14 +71,10 @@ class EfhGraphicsStruct { void copy(EfhGraphicsStruct *src); }; -struct Font { - uint8 _lines[8]; -}; - struct FontDescr { - uint8 *_widthArray; - uint8 *_extraLines; - Font *_fontData; + const uint8 *_widthArray; + const uint8 *_extraLines; + const Font *_fontData; uint8 _charHeight; uint8 _extraVerticalSpace; uint8 _extraHorizontalSpace; From 2ab89d40b4ad108d37fc6454f62262a387f2dea9 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sat, 20 Nov 2021 12:00:56 +0100 Subject: [PATCH 062/412] EFH: Renaming, remove unused parameters in a couple of functions --- engines/efh/constants.cpp | 10 ++++++---- engines/efh/constants.h | 8 ++++---- engines/efh/efh.cpp | 39 +++++++++++++++++---------------------- engines/efh/efh.h | 10 +++++----- 4 files changed, 32 insertions(+), 35 deletions(-) diff --git a/engines/efh/constants.cpp b/engines/efh/constants.cpp index 6ccc10c048b4..1e3bda56d24d 100644 --- a/engines/efh/constants.cpp +++ b/engines/efh/constants.cpp @@ -22,18 +22,20 @@ #include "efh/constants.h" +#include "engine.h" + namespace Efh { -const uint8 fontWidthArray[96] = { +const uint8 kFontWidthArray[96] = { 3, 2, 3, 5, 5, 5, 5, 2, 3, 3, 5, 5, 3, 3, 2, 7, 4, 3, 4, 4, 5, 4, 4, 4, 4, 4, 3, 4, 4, 5, 4, 5, 1, 4, 4, 4, 4, 4, 4, 4, 4, 3, 4, 4, 4, 7, 5, 4, 4, 4, 4, 4, 5, 4, 5, 7, 5, 5, 5, 3, 7, 3, 5, 0, 2, 4, 4, 4, 4, 4, 4, 4, 4, 1, 2, 4, 1, 7, 4, 4, 4, 4, 4, 4, 3, 4, 5, 7, 4, 4, 5, 3, 0, 3, 0, 0}; -const uint8 fontExtraLinesArray[96] = { +const uint8 kFontExtraLinesArray[96] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 0, 1, 0, 0}; -const Font fontData[96] = { +const Font kFontData[96] = { {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x80, 0x00}, {0xA0, 0xA0, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00}, @@ -132,7 +134,7 @@ const Font fontData[96] = { {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }; -const Encounter _encounters[] { +const Encounter kEncounters[] { {"Indian", 0, 5, 50, {64, 64, 68, 70, 92}, 25, 2}, {"Warrior", 0, 6, 85, {70, 64, 68, 70, 92}, 35, 2}, {"Tracker", 0, 8, 115, {92, 64, 68, 70, 92}, 38, 2}, diff --git a/engines/efh/constants.h b/engines/efh/constants.h index d64235fd93be..7b49ecdfdf04 100644 --- a/engines/efh/constants.h +++ b/engines/efh/constants.h @@ -40,10 +40,10 @@ struct Encounter { uint8 _nameArticle; }; -extern const uint8 fontWidthArray[96]; -extern const uint8 fontExtraLinesArray[96]; -extern const Font fontData[96]; -extern const Encounter _encounters[]; +extern const uint8 kFontWidthArray[96]; +extern const uint8 kFontExtraLinesArray[96]; +extern const Font kFontData[96]; +extern const Encounter kEncounters[]; } // End of namespace Efh diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 86436d494872..1bb54b1ad280 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -26,14 +26,11 @@ #include "common/config-manager.h" #include "common/events.h" #include "engines/util.h" -#include "graphics/cursorman.h" +#include "graphics/palette.h" #include "efh/efh.h" #include "efh/constants.h" -#include "engines/util.h" -#include "graphics/palette.h" - namespace Efh { EfhEngine *EfhEngine::s_Engine = nullptr; @@ -45,7 +42,7 @@ EfhGraphicsStruct::EfhGraphicsStruct() { _height = 0; _area = Common::Rect(0, 0, 0, 0); } -EfhGraphicsStruct::EfhGraphicsStruct(int16 *lineBuf, int16 x, int16 y, int16 width, int16 height) { +EfhGraphicsStruct::EfhGraphicsStruct(int8 **lineBuf, int16 x, int16 y, int16 width, int16 height) { _vgaLineBuffer = lineBuf; _shiftValue = 0; _width = width; @@ -284,7 +281,7 @@ void EfhEngine::loadNewPortrait() { findMapFile(_techId); _currentAnimImageSetId = 200 + _unkRelatedToAnimImageSetId; int imageSetId = _unkRelatedToAnimImageSetId + 13; - loadImageSet(imageSetId, _portraitBuf, _portraitSubFilesArray, 0, _paletteTransformationConstant, _hiResImageBuf, _loResImageBuf); + loadImageSet(imageSetId, _portraitBuf, _portraitSubFilesArray, _hiResImageBuf); } void EfhEngine::loadAnimImageSet() { @@ -298,7 +295,7 @@ void EfhEngine::loadAnimImageSet() { _currentAnimImageSetId = _animImageSetId; int16 animSetId = _animImageSetId + 17; - loadImageSet(animSetId, _portraitBuf, _portraitSubFilesArray, 0, _paletteTransformationConstant, _hiResImageBuf, _loResImageBuf); + loadImageSet(animSetId, _portraitBuf, _portraitSubFilesArray, _hiResImageBuf); } void EfhEngine::loadHistory() { @@ -533,9 +530,9 @@ void EfhEngine::initEngine() { _defaultBoxColor = 7; // Init Font - _fontDescr._widthArray = fontWidthArray; - _fontDescr._extraLines = fontExtraLinesArray; - _fontDescr._fontData = fontData; + _fontDescr._widthArray = kFontWidthArray; + _fontDescr._extraLines = kFontExtraLinesArray; + _fontDescr._fontData = kFontData; _fontDescr._charHeight = 8; _fontDescr._extraVerticalSpace = 3; _fontDescr._extraHorizontalSpace = 1; @@ -554,7 +551,7 @@ void EfhEngine::initEngine() { // } // Load Title Screen - loadImageSet(11, _circleImageBuf, _circleImageSubFileArray, 0, _paletteTransformationConstant, _hiResImageBuf, _loResImageBuf); + loadImageSet(11, _circleImageBuf, _circleImageSubFileArray, _hiResImageBuf); displayFctFullScreen(); sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 0, _paletteTransformationConstant); displayFctFullScreen(); @@ -584,7 +581,7 @@ void EfhEngine::initEngine() { loadNPCS(); // Load picture room with girlfriend - loadImageSet(62, _circleImageBuf, _circleImageSubFileArray, 0, _paletteTransformationConstant, _hiResImageBuf, _loResImageBuf); + loadImageSet(62, _circleImageBuf, _circleImageSubFileArray, _hiResImageBuf); fileName = "titlsong"; readFileToBuffer(fileName, _titleSong); setDefaultNoteDuration(); @@ -596,7 +593,7 @@ void EfhEngine::initEngine() { sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 0, _paletteTransformationConstant); // Load animations on previous picture with GF - loadImageSet(63, _circleImageBuf, _circleImageSubFileArray, 0, _paletteTransformationConstant, _hiResImageBuf, _loResImageBuf); + loadImageSet(63, _circleImageBuf, _circleImageSubFileArray, _hiResImageBuf); readImpFile(100, 0); lastInput = getLastCharAfterAnimCount(8); @@ -654,7 +651,7 @@ void EfhEngine::initEngine() { } } - loadImageSet(6, _circleImageBuf, _circleImageSubFileArray, 0, _paletteTransformationConstant, _hiResImageBuf, _loResImageBuf); + loadImageSet(6, _circleImageBuf, _circleImageSubFileArray, _hiResImageBuf); readImpFile(99, false); _word31E9E = 0xFFFF; restoreAnimImageSetId(); @@ -680,7 +677,7 @@ void EfhEngine::initMapMonsters() { for (uint8 counter = 0; counter < groupSize; ++counter) { uint rand100 = _rnd->getRandomNumber(99) + 1; - uint16 pictureRef = _encounters[_mapMonsters[monsterId]._MonsterRef]._pictureRef; + uint16 pictureRef = kEncounters[_mapMonsters[monsterId]._MonsterRef]._pictureRef; if (rand100 <= 25) { uint16 delta = _rnd->getRandomNumber((pictureRef / 2) - 1) + 1; @@ -753,12 +750,12 @@ void EfhEngine::displayLowStatusScreen(int i) { warning("STUB - displayLowStatusScreen"); } -void EfhEngine::loadImageSet(int imageSetId, uint8 *buffer, uint8 **subFilesArray, char CGAVal, char EGAVal, uint8 *destBuffer, uint8 *transfBuffer) { +void EfhEngine::loadImageSet(int imageSetId, uint8 *buffer, uint8 **subFilesArray, uint8 *destBuffer) { Common::String fileName = Common::String::format("imageset.%d", imageSetId); - rImageFile(fileName, buffer, subFilesArray, CGAVal, EGAVal, destBuffer, transfBuffer); + rImageFile(fileName, buffer, subFilesArray, destBuffer); } -void EfhEngine::rImageFile(Common::String filename, uint8 *targetBuffer, uint8 **subFilesArray, char CGAVal, char EGAVal, uint8 *packedBuffer, uint8 *transformedBuf) { +void EfhEngine::rImageFile(Common::String filename, uint8 *targetBuffer, uint8 **subFilesArray, uint8 *packedBuffer) { readFileToBuffer(filename, packedBuffer); uint32 size = uncompressBuffer(packedBuffer, targetBuffer); // TODO: Keep this dump for debug purposes only @@ -767,7 +764,7 @@ void EfhEngine::rImageFile(Common::String filename, uint8 *targetBuffer, uint8 * dump.write(targetBuffer, size); // End of dump - // TODO: Refactoring: once uncompressed, the container contains for each image its width, its height, and raw data (1 Bpp) + // TODO: Refactoring: once uncompressed, the container contains for each image its width, its height, and raw data (4 Bpp) // => Write a class to handle that more properly uint8 *ptr = targetBuffer; uint16 counter = 0; @@ -795,8 +792,6 @@ void EfhEngine::displayBitmapAtPos(int16 minX, int16 minY, int16 maxX, int16 max void EfhEngine::displayBitmap(EfhGraphicsStruct *efh_graphics_struct, EfhGraphicsStruct *efh_graphics_struct1, const Common::Rect &rect, int16 min_x, int16 min_y) { warning("STUB - displayBitmap"); - - } void EfhEngine::sub24D92(BufferBM *bufferBM, int16 posX, int16 posY) { @@ -922,7 +917,7 @@ void EfhEngine::loadImageSetToTileBank(int16 tileBankId, int16 imageSetId) { _mapBitmapRef[bankId] = setId; int16 ptrIndex = bankId * 72; - loadImageSet(setId, _tileBank[bankId], &_imageSetSubFilesArray[ptrIndex], 0, _paletteTransformationConstant, _hiResImageBuf, _loResImageBuf); + loadImageSet(setId, _tileBank[bankId], &_imageSetSubFilesArray[ptrIndex], _hiResImageBuf); } void EfhEngine::restoreAnimImageSetId() { diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 77f91d66dded..d6ffb8de2b9f 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -60,9 +60,9 @@ struct EfhGameDescription; class EfhGraphicsStruct { public: EfhGraphicsStruct(); - EfhGraphicsStruct(int16 *lineBuf, int16 x, int16 y, int16 width, int16 height); + EfhGraphicsStruct(int8 **lineBuf, int16 x, int16 y, int16 width, int16 height); - int16 *_vgaLineBuffer; + int8 **_vgaLineBuffer; uint16 _shiftValue; uint16 _width; uint16 _height; @@ -175,8 +175,8 @@ class EfhEngine : public Engine { void loadMapMonsters(); void saveAnimImageSetId(); void displayLowStatusScreen(int i); - void loadImageSet(int imageSetId, uint8 *buffer, uint8 **subFilesArray, char CGAVal, char EGAVal, uint8 *destBuffer, uint8 *transfBuffer); - void rImageFile(Common::String filename, uint8 *targetBuffer, uint8 **subFilesArray, char CGAVal, char EGAVal, uint8 *packedBuffer, uint8 *transformedBuffer); + void loadImageSet(int imageSetId, uint8 *buffer, uint8 **subFilesArray, uint8 *destBuffer); + void rImageFile(Common::String filename, uint8 *targetBuffer, uint8 **subFilesArray, uint8 *packedBuffer); void displayFctFullScreen(); void displayBitmapAtPos(int16 minX, int16 minY, int16 maxX, int16 maxY); void displayBitmap(EfhGraphicsStruct *efh_graphics_struct, EfhGraphicsStruct *efh_graphics_struct1, const Common::Rect &rect, int16 min_x, int16 min_y); @@ -204,7 +204,7 @@ class EfhEngine : public Engine { uint8 _videoMode; uint8 _bufferCharBM[128]; - int16 _vgaLineBuffer[200]; + int8 *_vgaLineBuffer[200]; EfhGraphicsStruct *_vgaGraphicsStruct1; EfhGraphicsStruct *_vgaGraphicsStruct2; EfhGraphicsStruct *_graphicsStruct; From 6ca672552a1187b5bf19eec1fc6b4181ac88868b Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sun, 21 Nov 2021 01:59:24 +0100 Subject: [PATCH 063/412] EFH: Implement drawBox --- engines/efh/efh.cpp | 38 +++++++++++++++++++++++++++++++++----- engines/efh/efh.h | 2 +- 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 1bb54b1ad280..14f14fba1b36 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -79,7 +79,7 @@ EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst) _vgaGraphicsStruct1 = new EfhGraphicsStruct(_vgaLineBuffer, 0, 0, 320, 200); _vgaGraphicsStruct2 = new EfhGraphicsStruct(); - + _videoMode = 0; _graphicsStruct = nullptr; _mapBitmapRef = nullptr; @@ -844,7 +844,7 @@ void EfhEngine::sub24D92(BufferBM *bufferBM, int16 posX, int16 posY) { uint8 *destPtr = (uint8 *)_mainSurface->getBasePtr(posX, posY); - warning("%d %d - startX %d startY %d width %d height %d fieldA %d fieldD %d", posX, posY, bufferBM->_startX, bufferBM->_startY, bufferBM->_width, bufferBM->_height, bufferBM->_fieldA, bufferBM->_fieldD); + // warning("%d %d - startX %d startY %d width %d height %d fieldA %d fieldD %d", posX, posY, bufferBM->_startX, bufferBM->_startY, bufferBM->_width, bufferBM->_height, bufferBM->_fieldA, bufferBM->_fieldD); int counter = 0; for (int j = 0; j < bufferBM->_height; ++j) { for (int i = 0; i < bufferBM->_fieldA; ++i) { @@ -1051,14 +1051,42 @@ uint8 EfhEngine::getMapTileInfo(int16 mapPosX, int16 mapPosY) { return _mapGameMapPtr[mapPosX * size + mapPosY]; } -void EfhEngine::drawBox(int minX, int minY, int maxX, int maxY) { - warning("STUB - drawBox"); +void EfhEngine::drawRect(int minX, int minY, int maxX, int maxY) { + if (minY > maxY) + SWAP(minY, maxY); + + if (minX > maxX) + SWAP(minX, maxX); + + // warning("drawRect - _graphicsStruct x %d -> %d, y %d -> %d", _graphicsStruct->_area.left, _graphicsStruct->_area.right, _graphicsStruct->_area.top, _graphicsStruct->_area.bottom); + + minX = CLIP(minX, 0, 319); + maxX = CLIP(maxX, 0, 319); + minY = CLIP(minY, 0, 199); + maxY = CLIP(maxY, 0, 199); + + int deltaY = 1 + maxY - minY; + int deltaX = 1 + maxX - minX; + + uint8 color = _defaultBoxColor & 0xF; + bool xorColor = (_defaultBoxColor & 0x40) != 0; + uint8 *destPtr = (uint8 *)_mainSurface->getBasePtr(minX, minY); + + for (int line = 0; line < deltaY; ++line) { + for (int col = 0; col < deltaX; ++col) { + if (xorColor) + destPtr[320 * line + col] ^= color; + else + destPtr[320 * line + col] = color; + } + } + } void EfhEngine::drawMenuBox(int minX, int minY, int maxX, int maxY, int color) { uint8 oldValue = _defaultBoxColor; _defaultBoxColor = color; - drawBox(minX, minY, maxX, maxY); + drawRect(minX, minY, maxX, maxY); _defaultBoxColor = oldValue; } diff --git a/engines/efh/efh.h b/engines/efh/efh.h index d6ffb8de2b9f..b22c589b7e80 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -187,7 +187,7 @@ class EfhEngine : public Engine { uint32 uncompressBuffer(uint8 *compressedBuf, uint8 *destBuf); void copyCurrentPlaceToBuffer(int id); uint8 getMapTileInfo(int16 mapPosX, int16 mapPosY); - void drawBox(int minX, int minY, int maxX, int maxY); + void drawRect(int minX, int minY, int maxX, int maxY); void drawMenuBox(int minX, int minY, int maxX, int maxY, int color); void displayFullScreenColoredMenuBox(int color); From 2d5377a276f041e8b2a4f4441e9cdedf7bcc34cd Mon Sep 17 00:00:00 2001 From: Strangerke Date: Mon, 22 Nov 2021 01:48:48 +0100 Subject: [PATCH 064/412] EFH: Refactor a bit the intro, implement getLastCharAfterAnimCount, remove more useless parameters from functions --- engines/efh/efh.cpp | 234 +++++++++++++++++++++++++++++--------------- engines/efh/efh.h | 8 +- 2 files changed, 162 insertions(+), 80 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 14f14fba1b36..06c9e4475b39 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -458,7 +458,101 @@ void EfhEngine::readImpFile(int16 id, bool techMapFl) { Common::KeyCode EfhEngine::getLastCharAfterAnimCount(int16 delay) { warning("STUB - getLastCharAfterAnimCount"); - return Common::KEYCODE_INVALID; + + if (delay == 0) + return Common::KEYCODE_INVALID; + + Common::Event event; + do { + _system->getEventManager()->pollEvent(event); + } while (event.kbd.keycode != Common::KEYCODE_INVALID); + + Common::KeyCode lastChar = Common::KEYCODE_INVALID; + + uint32 lastMs = _system->getMillis(); + while (delay > 0 && lastChar == Common::KEYCODE_INVALID) { + _system->delayMillis(20); + uint32 newMs = _system->getMillis(); + + if (newMs - lastMs >= 200) { + lastMs = newMs; + --delay; + unkFct_anim(); + } + + lastChar = handleAndMapInput(false); + } + + return lastChar; +} + +void EfhEngine::playIntro() { + sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 0); + displayFctFullScreen(); + sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 0); + + // Load animations on previous picture with GF + loadImageSet(63, _circleImageBuf, _circleImageSubFileArray, _hiResImageBuf); + readImpFile(100, 0); + Common::KeyCode lastInput = getLastCharAfterAnimCount(8); + if (lastInput == Common::KEYCODE_ESCAPE) + return; + + sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 144); + sub133E5(_imp2PtrArray[0], 6, 150, 268, 186, 0); + displayFctFullScreen(); + sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 144); + sub133E5(_imp2PtrArray[0], 6, 150, 268, 186, 0); + lastInput = getLastCharAfterAnimCount(80); + if (lastInput == Common::KEYCODE_ESCAPE) + return; + + sub10B77_unkDisplayFct1(_circleImageSubFileArray[1], 110, 16); + sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 144); + sub133E5(_imp2PtrArray[1], 6, 150, 268, 186, 0); + displayFctFullScreen(); + sub10B77_unkDisplayFct1(_circleImageSubFileArray[1], 110, 16); + sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 144); + sub133E5(_imp2PtrArray[1], 6, 150, 268, 186, 0); + lastInput = getLastCharAfterAnimCount(80); + if (lastInput == Common::KEYCODE_ESCAPE) + return; + + sub10B77_unkDisplayFct1(_circleImageSubFileArray[2], 110, 16); + sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 144); + sub133E5(_imp2PtrArray[2], 6, 150, 268, 186, 0); + displayFctFullScreen(); + sub10B77_unkDisplayFct1(_circleImageSubFileArray[2], 110, 16); + sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 144); + sub133E5(_imp2PtrArray[2], 6, 150, 268, 186, 0); + lastInput = getLastCharAfterAnimCount(80); + if (lastInput == Common::KEYCODE_ESCAPE) + return; + + sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 144); + sub133E5(_imp2PtrArray[3], 6, 150, 268, 186, 0); + displayFctFullScreen(); + sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 144); + sub133E5(_imp2PtrArray[3], 6, 150, 268, 186, 0); + lastInput = getLastCharAfterAnimCount(80); + if (lastInput == Common::KEYCODE_ESCAPE) + return; + + sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 144); + sub133E5(_imp2PtrArray[4], 6, 150, 268, 186, 0); + displayFctFullScreen(); + sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 144); + sub133E5(_imp2PtrArray[4], 6, 150, 268, 186, 0); + lastInput = getLastCharAfterAnimCount(80); + if (lastInput == Common::KEYCODE_ESCAPE) + return; + + sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 144); + sub133E5(_imp2PtrArray[5], 6, 150, 268, 186, 0); + displayFctFullScreen(); + sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 144); + sub133E5(_imp2PtrArray[5], 6, 150, 268, 186, 0); + getLastCharAfterAnimCount(80); } void EfhEngine::syncSoundSettings() { @@ -553,9 +647,9 @@ void EfhEngine::initEngine() { // Load Title Screen loadImageSet(11, _circleImageBuf, _circleImageSubFileArray, _hiResImageBuf); displayFctFullScreen(); - sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 0, _paletteTransformationConstant); + sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 0); displayFctFullScreen(); - sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 0, _paletteTransformationConstant); + sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 0); // Load map tiles bitmaps loadImageSetToTileBank(1, 1); @@ -588,67 +682,7 @@ void EfhEngine::initEngine() { Common::KeyCode lastInput = playSong(_titleSong); if (lastInput != Common::KEYCODE_ESCAPE) { - sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 0, _paletteTransformationConstant); - displayFctFullScreen(); - sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 0, _paletteTransformationConstant); - - // Load animations on previous picture with GF - loadImageSet(63, _circleImageBuf, _circleImageSubFileArray, _hiResImageBuf); - readImpFile(100, 0); - lastInput = getLastCharAfterAnimCount(8); - - if (lastInput != Common::KEYCODE_ESCAPE) { - sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 144, _paletteTransformationConstant); - sub133E5(_imp2PtrArray[0], 6, 150, 268, 186, 0); - displayFctFullScreen(); - sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 144, _paletteTransformationConstant); - sub133E5(_imp2PtrArray[0], 6, 150, 268, 186, 0); - lastInput = getLastCharAfterAnimCount(80); - if (lastInput != Common::KEYCODE_ESCAPE) { - sub10B77_unkDisplayFct1(_circleImageSubFileArray[1], 110, 16, _paletteTransformationConstant); - sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 144, _paletteTransformationConstant); - sub133E5(_imp2PtrArray[1], 6, 150, 268, 186, 0); - displayFctFullScreen(); - sub10B77_unkDisplayFct1(_circleImageSubFileArray[1], 110, 16, _paletteTransformationConstant); - sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 144, _paletteTransformationConstant); - sub133E5(_imp2PtrArray[1], 6, 150, 268, 186, 0); - lastInput = getLastCharAfterAnimCount(80); - if (lastInput != Common::KEYCODE_ESCAPE) { - sub10B77_unkDisplayFct1(_circleImageSubFileArray[2], 110, 16, _paletteTransformationConstant); - sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 144, _paletteTransformationConstant); - sub133E5(_imp2PtrArray[2], 6, 150, 268, 186, 0); - displayFctFullScreen(); - sub10B77_unkDisplayFct1(_circleImageSubFileArray[2], 110, 16, _paletteTransformationConstant); - sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 144, _paletteTransformationConstant); - sub133E5(_imp2PtrArray[2], 6, 150, 268, 186, 0); - lastInput = getLastCharAfterAnimCount(80); - if (lastInput != Common::KEYCODE_ESCAPE) { - sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 144, _paletteTransformationConstant); - sub133E5(_imp2PtrArray[3], 6, 150, 268, 186, 0); - displayFctFullScreen(); - sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 144, _paletteTransformationConstant); - sub133E5(_imp2PtrArray[3], 6, 150, 268, 186, 0); - lastInput = getLastCharAfterAnimCount(80); - if (lastInput != Common::KEYCODE_ESCAPE) { - sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 144, _paletteTransformationConstant); - sub133E5(_imp2PtrArray[4], 6, 150, 268, 186, 0); - displayFctFullScreen(); - sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 144, _paletteTransformationConstant); - sub133E5(_imp2PtrArray[4], 6, 150, 268, 186, 0); - lastInput = getLastCharAfterAnimCount(80); - if (lastInput != Common::KEYCODE_ESCAPE) { - sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 144, _paletteTransformationConstant); - sub133E5(_imp2PtrArray[5], 6, 150, 268, 186, 0); - displayFctFullScreen(); - sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 144, _paletteTransformationConstant); - sub133E5(_imp2PtrArray[5], 6, 150, 268, 186, 0); - lastInput = getLastCharAfterAnimCount(80); - } - } - } - } - } - } + playIntro(); } loadImageSet(6, _circleImageBuf, _circleImageSubFileArray, _hiResImageBuf); @@ -795,6 +829,7 @@ void EfhEngine::displayBitmap(EfhGraphicsStruct *efh_graphics_struct, EfhGraphic } void EfhEngine::sub24D92(BufferBM *bufferBM, int16 posX, int16 posY) { +#if 0 static uint16 byte2C80C[72] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, @@ -807,9 +842,6 @@ void EfhEngine::sub24D92(BufferBM *bufferBM, int16 posX, int16 posY) { 0, 0, 0, 0, 0x3F, 1, 0xC7, 0 }; - warning("STUB - sub24D92"); - -#if 0 if (bufferBM == nullptr) return; @@ -842,7 +874,7 @@ void EfhEngine::sub24D92(BufferBM *bufferBM, int16 posX, int16 posY) { //incomplete #endif - + // TODO: Quick code to display stuff, may require to really reverse the actual function uint8 *destPtr = (uint8 *)_mainSurface->getBasePtr(posX, posY); // warning("%d %d - startX %d startY %d width %d height %d fieldA %d fieldD %d", posX, posY, bufferBM->_startX, bufferBM->_startY, bufferBM->_width, bufferBM->_height, bufferBM->_fieldA, bufferBM->_fieldD); int counter = 0; @@ -856,7 +888,6 @@ void EfhEngine::sub24D92(BufferBM *bufferBM, int16 posX, int16 posY) { _system->copyRectToScreen((byte *)_mainSurface->getPixels(), 320, 0, 0, 320, 200); _system->updateScreen(); - _system->delayMillis(200); } void EfhEngine::sub133E5(uint8 *impPtr, int posX, int posY, int maxX, int maxY, int argC) { @@ -886,21 +917,44 @@ void EfhEngine::sub221FA(uint8 *impArray, bool flag) { } void EfhEngine::sub15094() { - sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 0, _paletteTransformationConstant); - sub10B77_unkDisplayFct1(_circleImageSubFileArray[1], 112, 0, _paletteTransformationConstant); - sub10B77_unkDisplayFct1(_circleImageSubFileArray[3], 16, 0, _paletteTransformationConstant); + sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 0); + sub10B77_unkDisplayFct1(_circleImageSubFileArray[1], 112, 0); + sub10B77_unkDisplayFct1(_circleImageSubFileArray[3], 16, 0); } void EfhEngine::sub150EE() { - sub10B77_unkDisplayFct1(_circleImageSubFileArray[2], 304, 0, _paletteTransformationConstant); - sub10B77_unkDisplayFct1(_circleImageSubFileArray[4], 128, 0, _paletteTransformationConstant); + sub10B77_unkDisplayFct1(_circleImageSubFileArray[2], 304, 0); + sub10B77_unkDisplayFct1(_circleImageSubFileArray[4], 128, 0); } void EfhEngine::sub15018() { - sub10B77_unkDisplayFct1(_circleImageSubFileArray[7], 16, 136, _paletteTransformationConstant); - sub10B77_unkDisplayFct1(_circleImageSubFileArray[8], 16, 192, _paletteTransformationConstant); - sub10B77_unkDisplayFct1(_circleImageSubFileArray[5], 0, 136, _paletteTransformationConstant); - sub10B77_unkDisplayFct1(_circleImageSubFileArray[6], 304, 136, _paletteTransformationConstant); + sub10B77_unkDisplayFct1(_circleImageSubFileArray[7], 16, 136); + sub10B77_unkDisplayFct1(_circleImageSubFileArray[8], 16, 192); + sub10B77_unkDisplayFct1(_circleImageSubFileArray[5], 0, 136); + sub10B77_unkDisplayFct1(_circleImageSubFileArray[6], 304, 136); +} + +void EfhEngine::setNumLock() { + // No implementation in ScummVM +} + +void EfhEngine::unkfct_mapFunction() { + warning("STUB - unkfct_mapFunction"); +} + +void EfhEngine::unkFct_anim() { + setNumLock(); + + if (_engineInitPending) + return; + + if (_animImageSetId != 0xFF) { + displayNextAnimFrame(); + displayFctFullScreen(); + displayAnimFrame(); + } + + unkfct_mapFunction(); } void EfhEngine::loadImageSetToTileBank(int16 tileBankId, int16 imageSetId) { @@ -1094,6 +1148,28 @@ void EfhEngine::displayFullScreenColoredMenuBox(int color) { drawMenuBox(0, 0, 320, 200, color); } +Common::KeyCode EfhEngine::handleAndMapInput(bool animFl) { + // The original checks for the joystick input + Common::Event event; + _system->getEventManager()->pollEvent(event); + Common::KeyCode retVal = Common::KEYCODE_INVALID; + if (event.type == Common::EVENT_KEYUP) { + retVal = event.kbd.keycode; + } + + if (animFl) { + warning("STUB - handleAndMapInput - animFl"); + } + return retVal; +} + +void EfhEngine::displayNextAnimFrame() { + if (++_unkAnimRelatedIndex >= 15) + _unkAnimRelatedIndex = 0; + + displayAnimFrame(); +} + void EfhEngine::copyCurrentPlaceToBuffer(int id) { uint8 *placesPtr = &_places[576 * id]; @@ -1101,7 +1177,7 @@ void EfhEngine::copyCurrentPlaceToBuffer(int id) { memcpy(_curPlace, placesPtr, 24 * 24); } -void EfhEngine::sub10B77_unkDisplayFct1(uint8 *imagePtr, int16 posX, int16 posY, uint8 guess_paletteTransformation) { +void EfhEngine::sub10B77_unkDisplayFct1(uint8 *imagePtr, int16 posX, int16 posY) { uint16 height = READ_LE_INT16(imagePtr); uint16 width = READ_LE_INT16(imagePtr + 2); uint8 *imageData = imagePtr + 4; diff --git a/engines/efh/efh.h b/engines/efh/efh.h index b22c589b7e80..28e8a8d05c07 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -170,6 +170,7 @@ class EfhEngine : public Engine { void decryptImpFile(bool techMapFl); void readImpFile(int16 id, bool techMapFl); Common::KeyCode getLastCharAfterAnimCount(int16 delay); + void playIntro(); void initEngine(); void initMapMonsters(); void loadMapMonsters(); @@ -190,10 +191,12 @@ class EfhEngine : public Engine { void drawRect(int minX, int minY, int maxX, int maxY); void drawMenuBox(int minX, int minY, int maxX, int maxY, int color); void displayFullScreenColoredMenuBox(int color); + Common::KeyCode handleAndMapInput(bool animFl); + void displayNextAnimFrame(); void sub15150(bool flag); void sub12A7F(); - void sub10B77_unkDisplayFct1(uint8 *imagePtr, int16 posX, int16 posY, uint8 guess_paletteTransformation); + void sub10B77_unkDisplayFct1(uint8 *imagePtr, int16 posX, int16 posY); void sub24D92(BufferBM *bufferBM, int16 posX, int16 posY); void sub133E5(uint8 *impPtr, int posX, int posY, int maxX, int maxY, int argC); void sub1512B(); @@ -201,6 +204,9 @@ class EfhEngine : public Engine { void sub15094(); void sub150EE(); void sub15018(); + void setNumLock(); + void unkfct_mapFunction(); + void unkFct_anim(); uint8 _videoMode; uint8 _bufferCharBM[128]; From 159ba2b577ab807701054827f86931e6eb519be3 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sun, 28 Nov 2021 22:49:57 +0100 Subject: [PATCH 065/412] EFH: Implement script_parse() and several underlying functions, some refactoring around Items and NPCS --- engines/efh/efh.cpp | 937 ++++++++++++++++++++++++++++++++++++++++---- engines/efh/efh.h | 125 +++++- 2 files changed, 968 insertions(+), 94 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 06c9e4475b39..32922d67433c 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -59,6 +59,87 @@ void EfhGraphicsStruct::copy(EfhGraphicsStruct *src) { _area = src->_area; } +void InvObject::init() { + _ref = 0; + _stat1 = 0; + _stat2 = 0; +} + +void ItemStruct::init() { + for (int16 idx = 0; idx < 15; ++idx) + _name[idx] = 0; + + _damage = 0; + _defense = 0; + _attacks = 0; + _uses = 0; + field_13 = 0; + _range = 0; + _attackType = 0; + field_16 = 0; + field17_attackTypeDefense = 0; + field_18 = 0; + field_19 = 0; + field_1A = 0; +} + +void NPCStruct::init() { + for (int i = 0; i < 9; ++i) + _name[i] = 0; + field_9 = 0; + field_A = 0; + field_B = 0; + field_C = 0; + field_D = 0; + field_E = 0; + field_F = 0; + field_10 = 0; + field_11 = 0; + field_12 = 0; + field_14 = 0; + _xp = 0; + + for (int i = 0; i < 15; ++i) + _activeScore[i] = 0; + + for (int i = 0; i < 11; ++i) { + _passiveScore[i] = 0; + _infoScore[i] = 0; + } + + field_3F = 0; + field_40 = 0; + + for (int i = 0; i < 10; ++i) + _inventory[i].init(); + + _possessivePronounSHL6 = 0; + _speed = 0; + field_6B = 0; + field_6C = 0; + field_6D = 0; + _unkItemId = 0; + field_6F = 0; + field_70 = 0; + field_71 = 0; + field_72 = 0; + field_73 = 0; + _hitPoints = 0; + _maxHP = 0; + field_78 = 0; + field_79 = 0; + field_7B = 0; + field_7D = 0; + field_7E = 0; + field_7F = 0; + field_80 = 0; + field_81 = 0; + field_82 = 0; + field_83 = 0; + field_84 = 0; + field_85 = 0; +} + EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst), _gameDescription(gd) { const Common::FSNode gameDataDir(ConfMan.get("path")); @@ -107,7 +188,7 @@ EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst) _imageDataPtr._width = 0; _imageDataPtr._startX = _imageDataPtr._startY = 0; _imageDataPtr._height = 0; - _imageDataPtr._fieldA = 0; + _imageDataPtr._lineDataSize = 0; _imageDataPtr._paletteTransformation = 0; _imageDataPtr._fieldD = 0; @@ -118,8 +199,10 @@ EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst) _techId = 0; _currentAnimImageSetId = 0xFF; - for (int i = 0; i < 20; ++i) + for (int i = 0; i < 20; ++i) { _portraitSubFilesArray[i] = nullptr; + _ennemyNamePt2[i] = 0; + } for (int i = 0; i < 100; ++i) _imp1PtrArray[i] = nullptr; @@ -136,9 +219,8 @@ EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst) _fullPlaceId = 0xFF; _guessAnimationAmount = 9; _largeMapFlag = 0xFFFF; - _teamCharIdArray = 0; - _charId = -1; - _word2C8B8 = -1; + _teamCharId[0] = 0; + _teamCharId[1] = _teamCharId[2] = -1; for (int i = 0; i < 3; ++i) { _teamCharStatus[i]._status = 0; @@ -155,9 +237,16 @@ EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst) _oldMapPosX = _oldMapPosY = 31; _techDataId_MapPosX = _techDataId_MapPosY = 31; + _textPosX = 0; + _textPosY = 0; + _lastMainPlaceId = 0; _word2C86E = 0; _dword2C856 = nullptr; + _word2C880 = 0; + _word2C894 = 0; + _word2C8D7 = -1; + _word2C87A = false; } EfhEngine::~EfhEngine() { @@ -220,9 +309,6 @@ Common::Error EfhEngine::run() { // Setup mixer syncSoundSettings(); _soundHandler->init(); - - CursorMan.replaceCursor(_normalCursor, 16, 16, 0, 0, 0); - CursorMan.showMouse(true); */ initEngine(); sub15150(true); @@ -330,7 +416,7 @@ void EfhEngine::loadTechMapImp(int16 fileId) { } -void EfhEngine::loadPlacesFile(uint16 fullPlaceId, int16 unused, bool forceReloadFl) { +void EfhEngine::loadPlacesFile(uint16 fullPlaceId, bool forceReloadFl) { //TODO : Remove unused parameter when all the calls are implemented if (fullPlaceId == 0xFF) return; @@ -387,12 +473,98 @@ void EfhEngine::readTileFact() { void EfhEngine::readItems() { Common::String fileName = "items"; - readFileToBuffer(fileName, _items); + uint8 itemBuff[8100]; + readFileToBuffer(fileName, itemBuff); + uint8 *curPtr = itemBuff; + + for (int i = 0; i < 300; ++i) { + for (int16 idx = 0; idx < 15; ++idx) + _items[i]._name[idx] = *curPtr++; + + + _items[i]._damage = *curPtr++; + _items[i]._defense = *curPtr++; + _items[i]._attacks = *curPtr++; + _items[i]._uses = *curPtr++; + _items[i].field_13 = *curPtr++; + _items[i]._range = *curPtr++; + _items[i]._attackType = *curPtr++; + _items[i].field_16 = *curPtr++; + _items[i].field17_attackTypeDefense = *curPtr++; + _items[i].field_18 = *curPtr++; + _items[i].field_19 = *curPtr++; + _items[i].field_1A = *curPtr++; + } } void EfhEngine::loadNPCS() { Common::String fileName = "npcs"; - readFileToBuffer(fileName, _npcBuf); + uint8 npcLoading[13400]; + readFileToBuffer(fileName, npcLoading); + uint8 *curPtr = npcLoading; + + for (int i = 0; i < 99; ++i) { + for (int idx = 0; idx < 9; ++idx) + _npcBuf[i]._name[idx] = *curPtr++; + _npcBuf[i].field_9 = *curPtr++; + _npcBuf[i].field_A = *curPtr++; + _npcBuf[i].field_B = *curPtr++; + _npcBuf[i].field_C = *curPtr++; + _npcBuf[i].field_D = *curPtr++; + _npcBuf[i].field_E = *curPtr++; + _npcBuf[i].field_F = *curPtr++; + _npcBuf[i].field_10 = *curPtr++; + _npcBuf[i].field_11 = *curPtr++; + _npcBuf[i].field_12 = READ_LE_INT16(curPtr); + _npcBuf[i].field_14 = READ_LE_INT16(curPtr + 2); + curPtr += 4; + _npcBuf[i]._xp = READ_LE_INT32(curPtr); + curPtr += 4; + for (int idx = 0; idx < 15; ++idx) { + _npcBuf[i]._activeScore[idx] = *curPtr++; + } + for (int idx = 0; idx < 11; ++idx) { + _npcBuf[i]._passiveScore[idx] = *curPtr++; + } + for (int idx = 0; idx < 11; ++idx) { + _npcBuf[i]._infoScore[idx] = *curPtr++; + } + _npcBuf[i].field_3F = *curPtr++; + _npcBuf[i].field_40 = *curPtr++; + for (int idx = 0; idx < 10; ++idx) { + _npcBuf[i]._inventory[idx]._ref = READ_LE_INT16(curPtr); + curPtr += 2; + _npcBuf[i]._inventory[idx]._stat1 = *curPtr++; + _npcBuf[i]._inventory[idx]._stat2 = *curPtr++; + } + _npcBuf[i]._possessivePronounSHL6 = *curPtr++; + _npcBuf[i]._speed = *curPtr++; + _npcBuf[i].field_6B = *curPtr++; + _npcBuf[i].field_6C = *curPtr++; + _npcBuf[i].field_6D = *curPtr++; + _npcBuf[i]._unkItemId = *curPtr++; + _npcBuf[i].field_6F = *curPtr++; + _npcBuf[i].field_70 = *curPtr++; + _npcBuf[i].field_71 = *curPtr++; + _npcBuf[i].field_72 = *curPtr++; + _npcBuf[i].field_73 = *curPtr++; + _npcBuf[i]._hitPoints = READ_LE_INT16(curPtr); + _npcBuf[i]._maxHP = READ_LE_INT16(curPtr + 2); + curPtr += 4; + _npcBuf[i].field_78 = *curPtr++; + _npcBuf[i].field_79 = READ_LE_INT16(curPtr); + _npcBuf[i].field_7B = READ_LE_INT16(curPtr + 2); + curPtr += 4; + _npcBuf[i].field_7D = *curPtr++; + _npcBuf[i].field_7E = *curPtr++; + _npcBuf[i].field_7F = *curPtr++; + _npcBuf[i].field_80 = *curPtr++; + _npcBuf[i].field_81 = *curPtr++; + _npcBuf[i].field_82 = *curPtr++; + _npcBuf[i].field_83 = *curPtr++; + _npcBuf[i].field_84 = *curPtr++; + _npcBuf[i].field_85 = *curPtr++; + } } void EfhEngine::setDefaultNoteDuration() { @@ -415,10 +587,10 @@ void EfhEngine::decryptImpFile(bool techMapFl) { uint8 *curPtr; if (!techMapFl) { - _imp2PtrArray[++counter] = curPtr = _imp2; + _imp2PtrArray[counter++] = curPtr = _imp2; target = 431; } else { - _imp2PtrArray[++counter] = curPtr = _imp1; + _imp2PtrArray[counter++] = curPtr = _imp1; target = 99; } @@ -427,9 +599,9 @@ void EfhEngine::decryptImpFile(bool techMapFl) { if (*curPtr == 0x40) { curPtr += 3; if (!techMapFl) - _imp2PtrArray[++counter] = curPtr; + _imp2PtrArray[counter++] = curPtr; else - _imp1PtrArray[++counter] = curPtr; + _imp1PtrArray[counter++] = curPtr; } else ++curPtr; } while (*curPtr != 0x60 && counter <= target); @@ -498,6 +670,7 @@ void EfhEngine::playIntro() { if (lastInput == Common::KEYCODE_ESCAPE) return; + // With GF on the bed sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 144); sub133E5(_imp2PtrArray[0], 6, 150, 268, 186, 0); displayFctFullScreen(); @@ -507,6 +680,7 @@ void EfhEngine::playIntro() { if (lastInput == Common::KEYCODE_ESCAPE) return; + // Poof sub10B77_unkDisplayFct1(_circleImageSubFileArray[1], 110, 16); sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 144); sub133E5(_imp2PtrArray[1], 6, 150, 268, 186, 0); @@ -518,6 +692,7 @@ void EfhEngine::playIntro() { if (lastInput == Common::KEYCODE_ESCAPE) return; + // On the phone sub10B77_unkDisplayFct1(_circleImageSubFileArray[2], 110, 16); sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 144); sub133E5(_imp2PtrArray[2], 6, 150, 268, 186, 0); @@ -588,7 +763,8 @@ void EfhEngine::initEngine() { memset(_imp1, 0, sizeof(_imp1)); memset(_imp2, 0, sizeof(_imp2)); memset(_titleSong, 0, sizeof(_titleSong)); - memset(_items, 0, sizeof(_items)); + for (int i = 0; i < 300; ++i) + _items[i].init(); memset(_tileFact, 0, sizeof(_tileFact)); memset(_animInfo, 0, sizeof(_animInfo)); memset(_history, 0, sizeof(_history)); @@ -707,19 +883,19 @@ void EfhEngine::initMapMonsters() { uint8 groupSize = _mapMonsters[monsterId]._groupSize; if (groupSize == 0) - groupSize = _rnd->getRandomNumber(10); + groupSize = getRandom(10); for (uint8 counter = 0; counter < groupSize; ++counter) { - uint rand100 = _rnd->getRandomNumber(99) + 1; + uint rand100 = getRandom(100); uint16 pictureRef = kEncounters[_mapMonsters[monsterId]._MonsterRef]._pictureRef; if (rand100 <= 25) { - uint16 delta = _rnd->getRandomNumber((pictureRef / 2) - 1) + 1; + uint16 delta = getRandom(pictureRef / 2); _mapMonsters[monsterId]._pictureRef[counter] = pictureRef - delta; } else if (rand100 <= 75) { _mapMonsters[monsterId]._pictureRef[counter] = pictureRef; } else { - uint16 delta = _rnd->getRandomNumber((pictureRef / 2) - 1) + 1; + uint16 delta = getRandom(pictureRef / 2); _mapMonsters[monsterId]._pictureRef[counter] = pictureRef + delta; } } @@ -815,83 +991,629 @@ void EfhEngine::rImageFile(Common::String filename, uint8 *targetBuffer, uint8 * void EfhEngine::displayFctFullScreen() { // CHECKME: 319 is in the original but looks suspicious. - displayBitmapAtPos(0, 0, 319, 200); + copyDirtyRect(0, 0, 319, 200); } -void EfhEngine::displayBitmapAtPos(int16 minX, int16 minY, int16 maxX, int16 maxY) { +void EfhEngine::copyDirtyRect(int16 minX, int16 minY, int16 maxX, int16 maxY) { _graphicsStruct->copy(_vgaGraphicsStruct2); _initRect = Common::Rect(minX, minY, maxX, maxY); - displayBitmap(_vgaGraphicsStruct2, _vgaGraphicsStruct1, _initRect, minX, minY); + copyGraphicBufferFromTo(_vgaGraphicsStruct2, _vgaGraphicsStruct1, _initRect, minX, minY); } -void EfhEngine::displayBitmap(EfhGraphicsStruct *efh_graphics_struct, EfhGraphicsStruct *efh_graphics_struct1, const Common::Rect &rect, int16 min_x, int16 min_y) { - warning("STUB - displayBitmap"); +void EfhEngine::copyGraphicBufferFromTo(EfhGraphicsStruct *efh_graphics_struct, EfhGraphicsStruct *efh_graphics_struct1, const Common::Rect &rect, int16 min_x, int16 min_y) { + warning("STUB - copyGraphicBufferFromTo"); } void EfhEngine::sub24D92(BufferBM *bufferBM, int16 posX, int16 posY) { -#if 0 - static uint16 byte2C80C[72] = { - 0, 1, 2, 3, 4, 5, 6, 7, - 8, 9, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, - 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, - 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, - 0, 0, 0, 0, 0x3F, 1, 0xC7, 0 - }; + // TODO: Quick code to display stuff, may require to really reverse the actual function + uint8 *destPtr = (uint8 *)_mainSurface->getBasePtr(posX, posY); + // warning("%d %d - startX %d startY %d width %d height %d lineDataSize %d fieldD %d", posX, posY, bufferBM->_startX, bufferBM->_startY, bufferBM->_width, bufferBM->_height, bufferBM->_lineDataSize, bufferBM->_fieldD); + int counter = 0; + for (int line = 0; line < bufferBM->_height; ++line) { + for (int col = 0; col < bufferBM->_lineDataSize; ++col) { // _lineDataSize = _width / 2 + destPtr[320 * line + 2 * col] = bufferBM->_dataPtr[counter] >> 4; + destPtr[320 * line + 2 * col + 1] = bufferBM->_dataPtr[counter] & 0xF; + ++counter; + } + } - if (bufferBM == nullptr) - return; + _system->copyRectToScreen((uint8 *)_mainSurface->getPixels(), 320, 0, 0, 320, 200); + _system->updateScreen(); +} - Common::Rect unkRect; - unkRect.left = posX - bufferBM->_startX; - unkRect.right = unkRect.left + bufferBM->_width - 1; - unkRect.top = posY - bufferBM->_startY; - unkRect.bottom = unkRect.top + bufferBM->_height - 1; +uint8 *EfhEngine::script_readNumberArray(uint8 *srcBuffer, int16 destArraySize, int16 *destArray) { + uint8 *buffer = srcBuffer; - Common::Rect destRect; - if (!computeLargeRect(_graphicsStruct->_area, &unkRect, &destRect)) - return; - - uint16 bufferFieldA = bufferBM->_fieldA; - int16 deltaMinY = (destRect.top - unkRect.top) * bufferFieldA; - int16 destWidth = destRect.width() + 1; + for (int16 i = 0; i < destArraySize; ++i) { + buffer = script_getNumber(buffer, &destArray[i]); + } - int16 deltaMinX = -1; - int16 tmpVal = (destRect.left - unkRect.left) * 2; + return buffer; +} - if (tmpVal < 0) - deltaMinX = 0; +uint8 *EfhEngine::script_getNumber(uint8 *srcBuffer, int16 *retval) { + uint8 *buffer = srcBuffer; + int16 var2 = 0; + for (;;) { + uint8 curChar = *buffer; + if (curChar < 0x30 || curChar > 0x39) { + *retval = var2; + return buffer; + } + var2 = var2 * 10 + curChar - 0x30; + } +} - int16 deltaWidth = (unkRect.right - unkRect.left) * 2 - (destRect.right - unkRect.left) * 2 + tmpVal; +void EfhEngine::removeObject(int16 charId, int16 objectId) { + _npcBuf[charId]._inventory[objectId]._ref = 0x7FFF; + _npcBuf[charId]._inventory[objectId]._stat1 = 0; + _npcBuf[charId]._inventory[objectId]._stat2 = 0; +} - uint8 *si = &bufferBM->_dataPtr[deltaMinY + tmpVal]; - uint8 ch = bufferBM->_paletteTransformation; - uint8 cl = 4; - uint16 var3A = byte2C80C[bufferBM->_fieldD << 3]; - //incomplete -#endif +void EfhEngine::totalPartyKill() { + for (int16 counter = 0; counter < 3; ++counter) { + if (_teamCharId[counter] != -1) + _npcBuf[counter]._hitPoints = 0; + } +} - // TODO: Quick code to display stuff, may require to really reverse the actual function - uint8 *destPtr = (uint8 *)_mainSurface->getBasePtr(posX, posY); - // warning("%d %d - startX %d startY %d width %d height %d fieldA %d fieldD %d", posX, posY, bufferBM->_startX, bufferBM->_startY, bufferBM->_width, bufferBM->_height, bufferBM->_fieldA, bufferBM->_fieldD); - int counter = 0; - for (int j = 0; j < bufferBM->_height; ++j) { - for (int i = 0; i < bufferBM->_fieldA; ++i) { - destPtr[320 * j + 2 * i] = bufferBM->_dataPtr[counter] >> 4; - destPtr[320 * j + 2 * i + 1] = bufferBM->_dataPtr[counter] & 0xF; - ++counter; +int16 EfhEngine::getRandom(int16 maxVal) { + if (maxVal == 0) + return 0; + + return 1 + _rnd->getRandomNumber(maxVal - 1); +} + +void EfhEngine::removeCharacterFromTeam(int16 teamMemberId) { + warning("STUB - removeCharacterFromTeam"); +} + +void EfhEngine::emptyFunction(int i) { + // TODO: Eventually remove this useless function +} + +void EfhEngine::refreshTeamSize() { + _teamSize = 0; + for (int16 counter = 0; counter < 3; ++counter) { + if (_teamCharId[counter] != -1) + ++_teamSize; + } +} + +bool EfhEngine::isCharacterATeamMember(int16 id) { + for (int16 counter = 0; counter < _teamSize; ++counter) { + if (_teamCharId[counter] == id) + return true; + } + + return false; +} + +void EfhEngine::handleWinSequence() { + warning("STUB - handleWinSequence"); +} + +bool EfhEngine::giveItemTo(int16 charId, int16 objectId, int altCharId) { + warning("STUB - giveItemTo"); + + return false; +} + +void EfhEngine::sub26437(char *str, int16 startX, int16 startY, uint16 unkFl) { + warning("STUB - sub26437"); +} + +void EfhEngine::displayCenteredString(char *str, int16 minX, int16 maxX, int16 posY) { + uint16 length = getStringWidth(str); + int16 startCenteredDisplayX = minX + (maxX - minX - length) / 2; + sub26437(str, startCenteredDisplayX, posY, _unkVideoRelatedWord1); +} + +int16 EfhEngine::chooseCharacterToReplace() { + warning("STUB - chooseCharacterToReplace"); + return 0x1B; +} + +int16 EfhEngine::handleCharacterJoining() { + static char strReplaceWho[13] = "Replace Who?"; + for (int16 counter = 0; counter < 3; ++counter) { + if (_teamCharId[counter] == -1) { + return counter; } } - _system->copyRectToScreen((byte *)_mainSurface->getPixels(), 320, 0, 0, 320, 200); - _system->updateScreen(); + for (int16 counter = 0; counter < 2; ++counter) { + drawMenuBox(200, 112, 278, 132, 0); + displayCenteredString(strReplaceWho, 200, 278, 117); + if (counter == 0) + displayFctFullScreen(); + } + + int16 charId = chooseCharacterToReplace(); + for (int16 counter = 0; counter < 2; ++counter) { + drawMenuBox(200, 112, 278, 132, 0); + if (counter == 0) + displayFctFullScreen(); + } + + if (charId == 0x1B) // Escape Keycode + return -1; + + removeCharacterFromTeam(charId); +} + +void EfhEngine::drawMapWindow() { + drawMenuBox(128, 8, 303, 135, 0); +} + +void EfhEngine::copyString(uint8 *srcStr, uint8 *destStr) { + uint8 lastChar = 1; + int16 idx = 0; + + while (lastChar != 0) { + lastChar = destStr[idx] = srcStr[idx]; + } +} + +int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, int maxY, int argC) { + bool doneFlag = false; + int16 var_F2 = 0xFFFF; + int16 var_F0 = 0xFF; + int16 var_EE = 0xFF; + const char *stringToDisplay = " "; + uint16 curLine = 0; + int16 numbLines = (1 + maxY - posY) / 9; + int16 width = maxX - posX; + int16 var_114 = getStringWidth((char *)stringToDisplay); + uint8 *buffer = stringBuffer; + char var_EC[80]; + char dest[150]; + memset(var_EC, 0, sizeof(var_EC)); + memset(dest, 0, sizeof(dest)); + int16 var_116 = 0; + setTextPos(posX, curLine * 9 + posY); + + while (!doneFlag) { + uint8 curChar = *buffer; + if (curChar != 0x5E && curChar != 0x20 && curChar != 0 && curChar != 0x7C) { + var_F2 = 0; + var_EC[++var_116] = curChar; + ++buffer; + continue; + } + + if (curChar != 0x5E) { + if (curChar == 0) + doneFlag = true; + else if (curChar == 0x7C) + var_F2 = 0; + + var_EC[var_116] = 0; + int16 var_11A = getStringWidth(var_EC); + int16 var_118 = var_114 + getStringWidth(dest); + + if (var_118 + var_11A > width || curChar == 0x7C) { + if (curLine >= numbLines) { + doneFlag = true; + } else { + if (var_F2 == 0) + unkFct_displayString_2(dest); + + *dest = 0; + strcpy(dest, var_EC); + strcat(dest, " "); + ++curLine; + setTextPos(posX, posY + curLine * 9); + var_116 = 0; + } + } else { + strcat(dest, var_EC); + strcat(dest, " "); + var_116 = 0; + } + ++buffer; + continue; + } + + // At this point, curChar == 0x5E + ++buffer; + int16 var_108 = 0; + buffer = script_getNumber(buffer, &var_108); + int16 scriptNumberArray[10]; + memset(scriptNumberArray, 0, ARRAYSIZE(scriptNumberArray)); + + switch (var_108) { + case 0x00: + buffer = script_readNumberArray(buffer, 3, scriptNumberArray); + if (argC != 0) { + if (_largeMapFlag) { + _largeMapFlag = false; + _techDataId_MapPosX = _mapPosX; + _techDataId_MapPosY = _mapPosY; + } + _oldMapPosX = _mapPosX = scriptNumberArray[1]; + _oldMapPosY = _mapPosY = scriptNumberArray[2]; + loadPlacesFile(scriptNumberArray[0], false); + _word2C880 = -1; + _word2C894 = -1; + } + break; + case 0x01: + if (argC != 0) { + _largeMapFlag = true; + _oldMapPosX = _mapPosX = _techDataId_MapPosX; + _oldMapPosY = _mapPosY = _techDataId_MapPosY; + _word2C880 = -1; + _word2C894 = -1; + } + break; + case 0x02: + buffer = script_readNumberArray(buffer, 3, scriptNumberArray); + if (argC != 0) { + if (_word2C8D7) + writeTechAndMapFiles(); + _oldMapPosX = _mapPosX = scriptNumberArray[1]; + _oldMapPosY = _mapPosY = scriptNumberArray[2]; + loadTechMapImp(scriptNumberArray[0]); + _largeMapFlag = true; + _word2C880 = -1; + _word2C894 = -1; + doneFlag = true; + } + break; + case 0x03: + buffer = script_readNumberArray(buffer, 4, scriptNumberArray); + if (argC != 0) { + int16 var110 = scriptNumberArray[2] - scriptNumberArray[0]; + int16 var10E = scriptNumberArray[3] - scriptNumberArray[1]; + + _mapPosX = getRandom(var110) + scriptNumberArray[0] - 1; + _mapPosY = getRandom(var10E) + scriptNumberArray[1] - 1; + _word2C880 = -1; + _word2C894 = -1; + } + break; + case 0x04: + buffer = script_readNumberArray(buffer, 2, scriptNumberArray); + if (argC != 0) { + _mapPosX = scriptNumberArray[0]; + _mapPosY = scriptNumberArray[1]; + _word2C880 = -1; + _word2C894 = -1; + } + break; + case 0x05: + buffer = script_readNumberArray(buffer, 4, scriptNumberArray); + if (argC != 0) { + int16 var110 = _teamCharId[scriptNumberArray[0]]; + if (var110 != -1) { + int16 var10E = scriptNumberArray[1]; + _npcBuf[var110]._activeScore[var10E] += scriptNumberArray[2] & 0xFF; + _npcBuf[var110]._activeScore[var10E] -= scriptNumberArray[3] & 0xFF; + } + } + break; + case 0x06: + buffer = script_readNumberArray(buffer, 2, scriptNumberArray); + if (argC != 0) { + int16 var110 = _teamCharId[scriptNumberArray[0]]; + if (var110 != -1) { + int16 var10E = scriptNumberArray[1]; + _npcBuf[var110]._activeScore[var10E] = scriptNumberArray[1]; + } + } + break; + case 0x07: + if (argC != 0) { + totalPartyKill(); + emptyFunction(2); + } + break; + case 0x08: + buffer = script_readNumberArray(buffer, 1, scriptNumberArray); + if (argC != 0 && scriptNumberArray[0] != -1) { + _npcBuf[_teamCharId[scriptNumberArray[0]]]._hitPoints = 0; + } + break; + case 0x09: + buffer = script_readNumberArray(buffer, 2, scriptNumberArray); + if (argC != 0) { + int16 var110 = _teamCharId[scriptNumberArray[0]]; + if (var110 != -1) { + int16 var10E = getRandom(scriptNumberArray[1]); + _npcBuf[var110]._hitPoints += var10E; + if (_npcBuf[var110]._hitPoints > _npcBuf[var110]._maxHP) + _npcBuf[var110]._hitPoints = _npcBuf[var110]._maxHP; + } + } + break; + case 0x0A: + buffer = script_readNumberArray(buffer, 1, scriptNumberArray); + if (argC != 0) { + int16 var110 = _teamCharId[scriptNumberArray[0]]; + if (var110 != -1) { + _npcBuf[var110]._hitPoints = _npcBuf[var110]._maxHP; + } + } + break; + case 0x0B: + buffer = script_readNumberArray(buffer, 2, scriptNumberArray); + if (argC != 0) { + int16 var110 = _teamCharId[scriptNumberArray[0]]; + if (var110 != -1) { + int16 var10E = getRandom(scriptNumberArray[1]); + _npcBuf[var110]._hitPoints -= var10E; + if (_npcBuf[var110]._hitPoints < 0) + _npcBuf[var110]._hitPoints = 0; + } + } + break; + case 0x0C: + buffer = script_readNumberArray(buffer, 2, scriptNumberArray); + if (argC != 0) { + int16 var110 = _teamCharId[scriptNumberArray[0]]; + bool found = false; + for (int16 counter = 0; counter < _teamSize && !found; ++counter) { + for (int16 objectId = 0; objectId < 10; ++objectId) { + if (_npcBuf[_teamCharId[counter]]._inventory[objectId]._ref == var110) { + removeObject(_teamCharId[counter], objectId); + found = true; + break; + } + } + } + } + break; + case 0x0D: + buffer = script_readNumberArray(buffer, 1, scriptNumberArray); + if (argC != 0) { + int16 var110 = _teamCharId[scriptNumberArray[0]]; + for (int16 counter = 0; counter < _teamSize; ++counter) { + if (giveItemTo(_teamCharId[counter], var110, 0xFF)) + break; + } + } + break; + case 0x0E: + buffer = script_readNumberArray(buffer, 3, scriptNumberArray); + if (argC != 0) { + int16 var110 = scriptNumberArray[0]; + bool found = false; + for (int16 counter = 0; counter < _teamSize && !found; ++counter) { + for (int16 objectId = 0; objectId < 10; ++objectId) { + if (_npcBuf[_teamCharId[counter]]._inventory[objectId]._ref == var110) { + found = true; + break; + } + } + } + + if (found) + var_F0 = scriptNumberArray[1]; + else + var_F0 = scriptNumberArray[2]; + } + break; + case 0x0F: + buffer = script_readNumberArray(buffer, 3, scriptNumberArray); + if (argC != 0) { + int16 var110 = scriptNumberArray[0]; + if (isCharacterATeamMember(var110)) + var_F0 = scriptNumberArray[1]; + else + var_F0 = scriptNumberArray[2]; + } + break; + case 0x10: + buffer = script_readNumberArray(buffer, 1, scriptNumberArray); + if (argC != 0) + var_F0 = scriptNumberArray[0]; + + break; + case 0x11: + if (argC != 0) + _unkArray2C8AA[0] = 0; + break; + case 0x12: + if (argC != 0) { + int16 var110 = sub151FD(_mapPosX, _mapPosY); + if (var110 != -1) + _mapUnknownPtr[9 * var110 + 1] = 0xFF; + } + break; + case 0x13: + buffer = script_readNumberArray(buffer, 3, scriptNumberArray); + if (argC != 0 && _largeMapFlag) { + _word2C87A = true; + loadPlacesFile(scriptNumberArray[0], false); + sub15A28(scriptNumberArray[1], scriptNumberArray[2]); + sub2455E(scriptNumberArray[0], scriptNumberArray[1], scriptNumberArray[2]); + var_F0 = -1; + } + break; + case 0x14: + buffer = script_readNumberArray(buffer, 1, scriptNumberArray); + if (argC != 0) { + int16 var110 = scriptNumberArray[0]; + if (!isCharacterATeamMember(var110)) + var_EE = var110; + var_F0 = -1; + } + break; + case 0x15: + buffer = script_readNumberArray(buffer, 2, scriptNumberArray); + if (argC != 0) { + _oldMapPosX = _mapPosX = scriptNumberArray[0]; + _oldMapPosY = _mapPosY = scriptNumberArray[1]; + _largeMapFlag = true; + _word2C894 = 0xFFFF; + } + break; + case 0x16: + buffer = script_readNumberArray(buffer, 1, scriptNumberArray); + if (argC != 0) { + int16 var110 = scriptNumberArray[0]; + // TODO: This "if" is useless, it's doing just the same loop and if statement. Consider removing it. + if (isCharacterATeamMember(var110)) { + for (int16 counter = 0; counter < 3; ++counter) { + if (_teamCharId[counter] == var110) { + removeCharacterFromTeam(counter); + break; + } + } + } + } + break; + case 0x17: + buffer = script_readNumberArray(buffer, 1, scriptNumberArray); + if (argC != 0) { + int16 var110 = scriptNumberArray[0]; + displayAnimFrames(var110, true); + } + break; + case 0x18: + buffer = script_readNumberArray(buffer, 2, scriptNumberArray); + if (argC != 0) { + int16 var110 = scriptNumberArray[1] - scriptNumberArray[0] + 1; + bool found = false; + var110 = getRandom(var110) + scriptNumberArray[0] - 1; + int16 counter; + for (counter = 0; counter < _teamSize; ++counter) { + if (giveItemTo(_teamCharId[counter], var110, 0xFF)) { + found = true; + break; + } + } + + if (!found) { + drawMapWindow(); + displayFctFullScreen(); + drawMapWindow(); + var110 = sub1C219("Nothing...", 1, 2, 0xFFFF); + displayFctFullScreen(); + } else { + warning("STUB case 0x18"); + copyString((uint8 *)_npcBuf[_teamCharId[counter]]._name, (uint8 *)_ennemyNamePt2); + copyString((uint8 *)_items[var110]._name, buffer); + sprintf(dest, "%s finds a %s!", _ennemyNamePt2, (char *)buffer); + drawMapWindow(); + displayFctFullScreen(); + drawMapWindow(); + var110 = sub1C219(dest, 1, 2, 0xFFFF); + displayFctFullScreen(); + } + + var110 = sub151FD(_mapPosX, _mapPosY); + if (var110 != -1) { + _mapUnknownPtr[var110 * 9 + 1] = 0xFF; + } + _word2C894 = 0xFFFF; + } + break; + case 0x19: + buffer = script_readNumberArray(buffer, 3, scriptNumberArray); + if (argC != 0) { + if (_largeMapFlag) { + _mapGameMapPtr[scriptNumberArray[0] * 6 + scriptNumberArray[1]] = scriptNumberArray[2] & 0xFF; + } else { + _curPlace[scriptNumberArray[0] * 24 + scriptNumberArray[1]] = scriptNumberArray[2] & 0xFF; + } + } + break; + case 0x1A: + buffer = script_readNumberArray(buffer, 2, scriptNumberArray); + if (argC != 0) { + int16 var110 = sub151FD(scriptNumberArray[0], scriptNumberArray[1]); + if (var110 != -1) { + _mapUnknownPtr[9 * var110 + 1] = 0xFF; + } + } + break; + case 0x1B: + buffer = script_readNumberArray(buffer, 3, scriptNumberArray); + if (argC != 0) { + int16 var110 = sub151FD(scriptNumberArray[0], scriptNumberArray[1]); + if (var110 != -1) { + _mapUnknownPtr[9 * var110 + 1] = 0xFF; + } + _mapUnknownPtr[9 * scriptNumberArray[2] + 1] = scriptNumberArray[0]; + _mapUnknownPtr[9 * scriptNumberArray[2] + 2] = scriptNumberArray[1]; + } + break; + case 0x1C: + buffer = script_readNumberArray(buffer, 1, scriptNumberArray); + if (argC != 0) { + _history[scriptNumberArray[0]] = 0xFF; + } + break; + case 0x1D: + buffer = script_readNumberArray(buffer, 1, scriptNumberArray); + if (argC != 0) { + _history[scriptNumberArray[0]] = 0; + } + break; + case 0x1E: + buffer = script_readNumberArray(buffer, 3, scriptNumberArray); + if (argC != 0) { + if (_history[scriptNumberArray[0]] == 0) + var_F0 = scriptNumberArray[2]; + else + var_F0 = scriptNumberArray[1]; + } + break; + case 0x1F: + buffer = script_readNumberArray(buffer, 1, scriptNumberArray); + if (argC != 0) + _unkArray2C8AA[0] = scriptNumberArray[0]; + + break; + case 0x20: + if (argC != 0) { + handleWinSequence(); + _system->quit(); + } + default: + break; + } + } + + if (*dest != 0 && curLine < numbLines && var_F2 == 0) + unkFct_displayString_2(dest); + + if (var_EE != 0xFF) { + displayLowStatusScreen(-1); + int16 teamSlot = handleCharacterJoining(); + if (teamSlot > -1) { + _teamCharId[teamSlot] = var_EE; + } + refreshTeamSize(); + } + + return var_F0; } void EfhEngine::sub133E5(uint8 *impPtr, int posX, int posY, int maxX, int maxY, int argC) { - warning("STUB - sub133E5"); + uint16 stringIdx = 0; + uint8 message[200]; + memset(message, 0, sizeof(message)); + + for (;;) { + uint8 curChar = *impPtr; + if (curChar == 0 || curChar == 0x40 || curChar == 0x60) + break; + + if (curChar == 0x0D) { + message[stringIdx++] = ' '; + ++impPtr; + } else if (curChar == 0x0A) { + ++impPtr; + } else { + message[stringIdx++] = curChar; + ++impPtr; + } + } + + script_parse(message, posX, posY, maxX, maxY, argC); } void EfhEngine::sub1512B() { @@ -934,6 +1656,24 @@ void EfhEngine::sub15018() { sub10B77_unkDisplayFct1(_circleImageSubFileArray[6], 304, 136); } +void EfhEngine::sub15A28(int16 arg0, int16 arg2) { + warning("STUB: sub15A28"); +} + +void EfhEngine::sub2455E(int16 arg0, int16 arg1, int16 arg2) { + warning("STUB: sub2455E"); +} + +int16 EfhEngine::sub1C219(const char *str, int menuType, int arg4, int displayTeamWindowFl) { + warning("STUB: sub1C219"); + return -1; +} + +int16 EfhEngine::sub151FD(int16 posX, int16 posY) { + warning("STUB: sub151FD"); + return -1; +} + void EfhEngine::setNumLock() { // No implementation in ScummVM } @@ -957,6 +1697,10 @@ void EfhEngine::unkFct_anim() { unkfct_mapFunction(); } +void EfhEngine::unkFct_displayString_2(char *message) { + warning("STUB - unkFct_displayString_2 %s", message); +} + void EfhEngine::loadImageSetToTileBank(int16 tileBankId, int16 imageSetId) { // TODO: all the values of titleBankId and imageSetId are hardcoded. When all the calls are implemented, fix the values to avoid to have to decrease them int16 bankId = tileBankId - 1; @@ -979,9 +1723,6 @@ void EfhEngine::restoreAnimImageSetId() { } void EfhEngine::checkProtection() { - // bool successfulCheck = false; - // uint8 protectionItemId = _rnd->getRandomNumber(5); - // uint8 ProtectionArrayId = _rnd->getRandomNumber(14); _unkVideoRelatedWord1 = 0xE; //CHECKME : Well, yeah, some code may be missing there. Who knows. @@ -997,8 +1738,6 @@ void EfhEngine::loadGame() { // // The savegame is used to initialize the engine, so this part is reimplemented. // The check for existence is replaced by an error. - // - // Fun fact : it was therefore expected to overwrite the original savegame on the floppy each time you saved. What could possibly go wrong? Common::String fileName = "savegame"; Common::File f; @@ -1010,9 +1749,9 @@ void EfhEngine::loadGame() { _fullPlaceId = f.readUint16LE(); _guessAnimationAmount = f.readSint16LE(); _largeMapFlag = f.readUint16LE(); - _teamCharIdArray = f.readSint16LE(); - _charId = f.readSint16LE(); - _word2C8B8 = f.readSint16LE(); + _teamCharId[0] = f.readSint16LE(); + _teamCharId[1] = f.readSint16LE(); + _teamCharId[2] = f.readSint16LE(); for (int i = 0; i < 3; ++i) { _teamCharStatus[i]._status = f.readSint16LE(); @@ -1044,7 +1783,7 @@ void EfhEngine::loadGame() { loadTechMapImp(_techId); _lastMainPlaceId = 0xFFFF; - loadPlacesFile(_fullPlaceId, 0, true); + loadPlacesFile(_fullPlaceId, true); } uint32 EfhEngine::uncompressBuffer(uint8 *compressedBuf, uint8 *destBuf) { @@ -1170,6 +1909,34 @@ void EfhEngine::displayNextAnimFrame() { displayAnimFrame(); } +void EfhEngine::writeTechAndMapFiles() { + warning("STUB - writeTechAndMapFiles"); +} + +uint16 EfhEngine::getStringWidth(char *buffer) { + uint16 retVal = 0; + + for (;;) { + uint8 curChar = (uint8) *buffer++; + if (curChar == 0) { + --buffer; + break; + } + + if (curChar < 0x20) + continue; + + retVal += _fontDescr._widthArray[curChar - 0x20] + 1; + } + + return retVal; +} + +void EfhEngine::setTextPos(int16 textPosX, int16 textPosY) { + _textPosX = textPosX; + _textPosY = textPosY; +} + void EfhEngine::copyCurrentPlaceToBuffer(int id) { uint8 *placesPtr = &_places[576 * id]; @@ -1182,10 +1949,10 @@ void EfhEngine::sub10B77_unkDisplayFct1(uint8 *imagePtr, int16 posX, int16 posY) uint16 width = READ_LE_INT16(imagePtr + 2); uint8 *imageData = imagePtr + 4; - _imageDataPtr._fieldA = width; + _imageDataPtr._lineDataSize = width; _imageDataPtr._dataPtr = imageData; _imageDataPtr._height = height; - _imageDataPtr._width = width * 2; + _imageDataPtr._width = width * 2; // 2 pixels per byte _imageDataPtr._startX = _imageDataPtr._startY = 0; sub24D92(&_imageDataPtr, posX, posY); diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 28e8a8d05c07..b05429f43a5f 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -71,6 +71,81 @@ class EfhGraphicsStruct { void copy(EfhGraphicsStruct *src); }; +struct InvObject { + int16 _ref; + uint8 _stat1; + uint8 _stat2; + + void init(); +}; + +struct ItemStruct { + char _name[15]; + uint8 _damage; + uint8 _defense; + uint8 _attacks; + uint8 _uses; + uint8 field_13; + uint8 _range; + uint8 _attackType; + uint8 field_16; + uint8 field17_attackTypeDefense; + uint8 field_18; + uint8 field_19; + uint8 field_1A; + + void init(); +}; + +struct NPCStruct { + char _name[9]; + uint8 field_9; + uint8 field_A; + uint8 field_B; + uint8 field_C; + uint8 field_D; + uint8 field_E; + uint8 field_F; + uint8 field_10; + uint8 field_11; + uint16 field_12; + uint16 field_14; + uint32 _xp; + uint8 _activeScore[15]; + uint8 _passiveScore[11]; + uint8 _infoScore[11]; + uint8 field_3F; + uint8 field_40; + InvObject _inventory[10]; + uint8 _possessivePronounSHL6; + uint8 _speed; + uint8 field_6B; + uint8 field_6C; + uint8 field_6D; + uint8 _unkItemId; + uint8 field_6F; + uint8 field_70; + uint8 field_71; + uint8 field_72; + uint8 field_73; + int16 _hitPoints; + int16 _maxHP; + uint8 field_78; + uint16 field_79; + uint16 field_7B; + uint8 field_7D; + uint8 field_7E; + uint8 field_7F; + uint8 field_80; + uint8 field_81; + uint8 field_82; + uint8 field_83; + uint8 field_84; + uint8 field_85; + + void init(); +}; + struct FontDescr { const uint8 *_widthArray; const uint8 *_extraLines; @@ -86,7 +161,7 @@ struct BufferBM { uint16 _startX; uint16 _startY; uint16 _height; - uint16 _fieldA; + uint16 _lineDataSize; uint8 _paletteTransformation; uint16 _fieldD; }; @@ -158,7 +233,7 @@ class EfhEngine : public Engine { void loadAnimImageSet(); void loadHistory(); void loadTechMapImp(int16 fileId); - void loadPlacesFile(uint16 fullPlaceId, int16 unused, bool forceReloadFl); + void loadPlacesFile(uint16 fullPlaceId, bool forceReloadFl); void drawUnknownMenuBox(); void displayAnimFrame(); void displayAnimFrames(int16 animId, bool displayMenuBoxFl); @@ -179,8 +254,8 @@ class EfhEngine : public Engine { void loadImageSet(int imageSetId, uint8 *buffer, uint8 **subFilesArray, uint8 *destBuffer); void rImageFile(Common::String filename, uint8 *targetBuffer, uint8 **subFilesArray, uint8 *packedBuffer); void displayFctFullScreen(); - void displayBitmapAtPos(int16 minX, int16 minY, int16 maxX, int16 maxY); - void displayBitmap(EfhGraphicsStruct *efh_graphics_struct, EfhGraphicsStruct *efh_graphics_struct1, const Common::Rect &rect, int16 min_x, int16 min_y); + void copyDirtyRect(int16 minX, int16 minY, int16 maxX, int16 maxY); + void copyGraphicBufferFromTo(EfhGraphicsStruct *efh_graphics_struct, EfhGraphicsStruct *efh_graphics_struct1, const Common::Rect &rect, int16 min_x, int16 min_y); void loadImageSetToTileBank(int16 tileBankId, int16 imageSetId); void restoreAnimImageSetId(); void checkProtection(); @@ -193,20 +268,46 @@ class EfhEngine : public Engine { void displayFullScreenColoredMenuBox(int color); Common::KeyCode handleAndMapInput(bool animFl); void displayNextAnimFrame(); + void writeTechAndMapFiles(); + uint16 getStringWidth(char *buffer); + void setTextPos(int16 textPosX, int16 textPosY); void sub15150(bool flag); void sub12A7F(); void sub10B77_unkDisplayFct1(uint8 *imagePtr, int16 posX, int16 posY); void sub24D92(BufferBM *bufferBM, int16 posX, int16 posY); + uint8 *script_readNumberArray(uint8 *buffer, int16 destArraySize, int16 *destArray); + uint8 *script_getNumber(uint8 *srcBuffer, int16 *retval); + void removeObject(int16 charId, int16 objectId); + void totalPartyKill(); + int16 getRandom(int16 maxVal); + void removeCharacterFromTeam(int16 teamMemberId); + void emptyFunction(int i); + void refreshTeamSize(); + bool isCharacterATeamMember(int16 id); + void handleWinSequence(); + bool giveItemTo(int16 charId, int16 objectId, int altCharId); + void sub26437(char * str, int16 startX, int16 startY, uint16 unkFl); + void displayCenteredString(char * str, int16 minX, int16 maxX, int16 posY); + int16 chooseCharacterToReplace(); + int16 handleCharacterJoining(); + void drawMapWindow(); + void copyString(uint8 *srcStr, uint8 *destStr); + int16 script_parse(uint8 *str, int posX, int posY, int maxX, int maxY, int argC); void sub133E5(uint8 *impPtr, int posX, int posY, int maxX, int maxY, int argC); void sub1512B(); void sub221FA(uint8 *impArray, bool flag); void sub15094(); void sub150EE(); void sub15018(); + void sub15A28(int16 arg0, int16 arg2); + void sub2455E(int16 arg0, int16 arg1, int16 arg2); + int16 sub1C219(const char *str, int menuType, int arg4, int displayTeamWindowFl); + int16 sub151FD(int16 posX, int16 posY); void setNumLock(); void unkfct_mapFunction(); void unkFct_anim(); + void unkFct_displayString_2(char *message); uint8 _videoMode; uint8 _bufferCharBM[128]; @@ -224,15 +325,16 @@ class EfhEngine : public Engine { uint8 _map[7000]; uint8 _places[12000]; uint8 _curPlace[600]; - uint8 _npcBuf[13400]; + NPCStruct _npcBuf[100]; uint8 _imp1[13000]; uint8 _imp2[10000]; uint8 _titleSong[1024]; - uint8 _items[8100]; + ItemStruct _items[300]; uint8 _tileFact[864]; uint8 _animInfo[9000]; uint8 _history[256]; uint8 _techData[4096]; + char _ennemyNamePt2[20]; uint8 *_mapBitmapRef; uint8 *_mapUnknownPtr; @@ -263,9 +365,9 @@ class EfhEngine : public Engine { uint16 _fullPlaceId; int16 _guessAnimationAmount; uint16 _largeMapFlag; // CHECKME: bool? - int16 _teamCharIdArray; - int16 _charId; - int16 _word2C8B8; + int16 _teamCharId[3]; + int16 _textPosX; + int16 _textPosY; Common::Rect _initRect; bool _engineInitPending; @@ -275,6 +377,11 @@ class EfhEngine : public Engine { int16 _unkArray2C8AA[3]; int16 _teamSize; int16 _word2C872; + int16 _word2C880; + int16 _word2C894; + int16 _word2C8D7; + bool _word2C87A; + int16 _imageSetSubFilesIdx; int16 _mapPosX, _mapPosY; From f7c609ebdb7ad65337a5d646d92ac97379269112 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Mon, 29 Nov 2021 00:50:11 +0100 Subject: [PATCH 066/412] EFH: Fix a couple of crashes --- engines/efh/efh.cpp | 27 ++++++++++++++++----------- engines/efh/efh.h | 4 +++- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 32922d67433c..877e3e45d7bc 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -202,6 +202,7 @@ EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst) for (int i = 0; i < 20; ++i) { _portraitSubFilesArray[i] = nullptr; _ennemyNamePt2[i] = 0; + _nameBuffer[i] = 0; } for (int i = 0; i < 100; ++i) @@ -247,6 +248,8 @@ EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst) _word2C894 = 0; _word2C8D7 = -1; _word2C87A = false; + + memset(_messageToBePrinted, 0, 400); } EfhEngine::~EfhEngine() { @@ -1140,6 +1143,7 @@ int16 EfhEngine::handleCharacterJoining() { return -1; removeCharacterFromTeam(charId); + return 2; } void EfhEngine::drawMapWindow() { @@ -1157,7 +1161,7 @@ void EfhEngine::copyString(uint8 *srcStr, uint8 *destStr) { int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, int maxY, int argC) { bool doneFlag = false; - int16 var_F2 = 0xFFFF; + int16 var_F2 = -1; int16 var_F0 = 0xFF; int16 var_EE = 0xFF; const char *stringToDisplay = " "; @@ -1446,7 +1450,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, _oldMapPosX = _mapPosX = scriptNumberArray[0]; _oldMapPosY = _mapPosY = scriptNumberArray[1]; _largeMapFlag = true; - _word2C894 = 0xFFFF; + _word2C894 = -1; } break; case 0x16: @@ -1494,8 +1498,8 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, } else { warning("STUB case 0x18"); copyString((uint8 *)_npcBuf[_teamCharId[counter]]._name, (uint8 *)_ennemyNamePt2); - copyString((uint8 *)_items[var110]._name, buffer); - sprintf(dest, "%s finds a %s!", _ennemyNamePt2, (char *)buffer); + copyString((uint8 *)_items[var110]._name, (uint8 *)_nameBuffer); + sprintf(dest, "%s finds a %s!", _ennemyNamePt2, _nameBuffer); drawMapWindow(); displayFctFullScreen(); drawMapWindow(); @@ -1507,7 +1511,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, if (var110 != -1) { _mapUnknownPtr[var110 * 9 + 1] = 0xFF; } - _word2C894 = 0xFFFF; + _word2C894 = -1; } break; case 0x19: @@ -1592,28 +1596,29 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, return var_F0; } -void EfhEngine::sub133E5(uint8 *impPtr, int posX, int posY, int maxX, int maxY, int argC) { +void EfhEngine::sub133E5(uint8 *srcPtr, int posX, int posY, int maxX, int maxY, int argC) { uint16 stringIdx = 0; - uint8 message[200]; - memset(message, 0, sizeof(message)); + uint8 *impPtr = srcPtr; + memset(_messageToBePrinted, 0, 200); for (;;) { uint8 curChar = *impPtr; + if (curChar == 0 || curChar == 0x40 || curChar == 0x60) break; if (curChar == 0x0D) { - message[stringIdx++] = ' '; + _messageToBePrinted[stringIdx++] = ' '; ++impPtr; } else if (curChar == 0x0A) { ++impPtr; } else { - message[stringIdx++] = curChar; + _messageToBePrinted[stringIdx++] = curChar; ++impPtr; } } - script_parse(message, posX, posY, maxX, maxY, argC); + script_parse(_messageToBePrinted, posX, posY, maxX, maxY, argC); } void EfhEngine::sub1512B() { diff --git a/engines/efh/efh.h b/engines/efh/efh.h index b05429f43a5f..dbcc49bd30af 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -335,7 +335,9 @@ class EfhEngine : public Engine { uint8 _history[256]; uint8 _techData[4096]; char _ennemyNamePt2[20]; - + char _nameBuffer[20]; + uint8 _messageToBePrinted[400]; + uint8 *_mapBitmapRef; uint8 *_mapUnknownPtr; uint8 *_mapMonstersPtr; From 99f3f1e727a0a74c0ece9ea0a9b94016e45a43b7 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Tue, 30 Nov 2021 00:04:17 +0100 Subject: [PATCH 067/412] EFH: Implement string display --- engines/efh/efh.cpp | 85 ++++++++++++++++++++++++++++++++++++++++----- engines/efh/efh.h | 4 +++ 2 files changed, 80 insertions(+), 9 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 877e3e45d7bc..c79573c94e6b 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -248,6 +248,7 @@ EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst) _word2C894 = 0; _word2C8D7 = -1; _word2C87A = false; + _unk_sub26437_flag = 0; memset(_messageToBePrinted, 0, 400); } @@ -581,6 +582,8 @@ void EfhEngine::setDefaultNoteDuration() { Common::KeyCode EfhEngine::playSong(uint8 *buffer) { warning("STUB: playSong"); + _system->delayMillis(1000); + return Common::KEYCODE_INVALID; } @@ -632,8 +635,6 @@ void EfhEngine::readImpFile(int16 id, bool techMapFl) { } Common::KeyCode EfhEngine::getLastCharAfterAnimCount(int16 delay) { - warning("STUB - getLastCharAfterAnimCount"); - if (delay == 0) return Common::KEYCODE_INVALID; @@ -668,7 +669,7 @@ void EfhEngine::playIntro() { // Load animations on previous picture with GF loadImageSet(63, _circleImageBuf, _circleImageSubFileArray, _hiResImageBuf); - readImpFile(100, 0); + readImpFile(100, false); Common::KeyCode lastInput = getLastCharAfterAnimCount(8); if (lastInput == Common::KEYCODE_ESCAPE) return; @@ -995,6 +996,10 @@ void EfhEngine::rImageFile(Common::String filename, uint8 *targetBuffer, uint8 * void EfhEngine::displayFctFullScreen() { // CHECKME: 319 is in the original but looks suspicious. copyDirtyRect(0, 0, 319, 200); + + + _system->copyRectToScreen((uint8 *)_mainSurface->getPixels(), 320, 0, 0, 320, 200); + _system->updateScreen(); } void EfhEngine::copyDirtyRect(int16 minX, int16 minY, int16 maxX, int16 maxY) { @@ -1020,8 +1025,8 @@ void EfhEngine::sub24D92(BufferBM *bufferBM, int16 posX, int16 posY) { } } - _system->copyRectToScreen((uint8 *)_mainSurface->getPixels(), 320, 0, 0, 320, 200); - _system->updateScreen(); +// _system->copyRectToScreen((uint8 *)_mainSurface->getPixels(), 320, 0, 0, 320, 200); +// _system->updateScreen(); } uint8 *EfhEngine::script_readNumberArray(uint8 *srcBuffer, int16 destArraySize, int16 *destArray) { @@ -1103,7 +1108,40 @@ bool EfhEngine::giveItemTo(int16 charId, int16 objectId, int altCharId) { } void EfhEngine::sub26437(char *str, int16 startX, int16 startY, uint16 unkFl) { - warning("STUB - sub26437"); + uint8 *curPtr = (uint8 *)str; + uint16 lineHeight = _fontDescr._charHeight + _fontDescr._extraVerticalSpace; + _unk_sub26437_flag = unkFl & 0x3FFF; + int16 minX = startX; + int16 minY = startY; // Used in case 0x8000 + int16 var6 = _fontDescr._extraLines[0] + startY - 1; // Used in case 0x8000 + + if (unkFl & 0x8000) { + warning("STUB - sub26437 - 0x8000"); + } + + for (uint8 curChar = *curPtr++; curChar != 0; curChar = *curPtr++) { + if (curChar == 0x0A) { + startX = minX; + startY += lineHeight; + continue; + } + + if (curChar < 0x20) + continue; + + uint16 characterId = (curChar + 0xE0) & 0xFF; + uint8 charWidth = _fontDescr._widthArray[characterId]; + + if (startX + charWidth >= 319) { + startX = minX; + startY += lineHeight; + } + + uint8 varC = _fontDescr._extraLines[characterId]; + sub252CE(curChar, startX, startY + varC); + startX += charWidth + _fontDescr._extraHorizontalSpace; + } + } void EfhEngine::displayCenteredString(char *str, int16 minX, int16 maxX, int16 posY) { @@ -1181,7 +1219,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, uint8 curChar = *buffer; if (curChar != 0x5E && curChar != 0x20 && curChar != 0 && curChar != 0x7C) { var_F2 = 0; - var_EC[++var_116] = curChar; + var_EC[var_116++] = curChar; ++buffer; continue; } @@ -1496,7 +1534,6 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, var110 = sub1C219("Nothing...", 1, 2, 0xFFFF); displayFctFullScreen(); } else { - warning("STUB case 0x18"); copyString((uint8 *)_npcBuf[_teamCharId[counter]]._name, (uint8 *)_ennemyNamePt2); copyString((uint8 *)_items[var110]._name, (uint8 *)_nameBuffer); sprintf(dest, "%s finds a %s!", _ennemyNamePt2, _nameBuffer); @@ -1679,6 +1716,23 @@ int16 EfhEngine::sub151FD(int16 posX, int16 posY) { return -1; } +void EfhEngine::sub252CE(uint8 curChar, int16 posX, int posY) { + // Quick hacked display, may require rework + uint8 *destPtr = (uint8 *)_mainSurface->getBasePtr(posX, posY); + + int16 charId = curChar - 0x20; + uint8 width = _fontDescr._widthArray[charId]; + + for (int16 line = 0; line < 8; ++line) { + int16 x = 0; + for (int i = 7; i >= 7 - width; --i) { + if (_fontDescr._fontData[charId]._lines[line] & (1 << i)) + destPtr[320 * line + x] = 14; + ++x; + } + } +} + void EfhEngine::setNumLock() { // No implementation in ScummVM } @@ -1702,8 +1756,21 @@ void EfhEngine::unkFct_anim() { unkfct_mapFunction(); } +void EfhEngine::setNextCharacterPos() { + if (_textPosX <= 311) + return; + + _textPosX = 0; + _textPosY += 8; + + if (_textPosY > 191) + _textPosY = 0; +} + void EfhEngine::unkFct_displayString_2(char *message) { - warning("STUB - unkFct_displayString_2 %s", message); + sub26437(message, _textPosX, _textPosY, _unkVideoRelatedWord1); + _textPosX += getStringWidth(message) + 1; + setNextCharacterPos(); } void EfhEngine::loadImageSetToTileBank(int16 tileBankId, int16 imageSetId) { diff --git a/engines/efh/efh.h b/engines/efh/efh.h index dbcc49bd30af..28e17f2dc55d 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -304,9 +304,12 @@ class EfhEngine : public Engine { void sub2455E(int16 arg0, int16 arg1, int16 arg2); int16 sub1C219(const char *str, int menuType, int arg4, int displayTeamWindowFl); int16 sub151FD(int16 posX, int16 posY); + void sub252CE(uint8 curChar, int16 posX, int posY); + void setNumLock(); void unkfct_mapFunction(); void unkFct_anim(); + void setNextCharacterPos(); void unkFct_displayString_2(char *message); uint8 _videoMode; @@ -383,6 +386,7 @@ class EfhEngine : public Engine { int16 _word2C894; int16 _word2C8D7; bool _word2C87A; + int16 _unk_sub26437_flag; int16 _imageSetSubFilesIdx; From 2bbd63c0bca80f5be87b6018001e0bb4b284c6da Mon Sep 17 00:00:00 2001 From: Strangerke Date: Wed, 1 Dec 2021 00:17:26 +0100 Subject: [PATCH 068/412] EFH: Implement displayLowStatusScreen and some other functions, refactor AnimInfo --- engines/efh/efh.cpp | 224 +++++++++++++++++++++++++++++++++++++++++--- engines/efh/efh.h | 35 ++++++- 2 files changed, 241 insertions(+), 18 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index c79573c94e6b..bb9809cce605 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -65,6 +65,20 @@ void InvObject::init() { _stat2 = 0; } +void UnkAnimStruct::init() { + field0 = field1 = field2 = field3 = 0; +} + +void AnimInfo::init() { + for (int i = 0; i < 15; ++i) + _unkAnimArray[i].init(); + + for (int i = 0; i < 10; ++i) { + _field3C_startY[i] = 0; + _field46_startX[i] = 0; + } +} + void ItemStruct::init() { for (int16 idx = 0; idx < 15; ++idx) _name[idx] = 0; @@ -247,8 +261,11 @@ EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst) _word2C880 = 0; _word2C894 = 0; _word2C8D7 = -1; + _word2C876 = true; + _word2C878 = true; _word2C87A = false; _unk_sub26437_flag = 0; + _word2C8D9 = 0; memset(_messageToBePrinted, 0, 400); } @@ -317,13 +334,15 @@ Common::Error EfhEngine::run() { initEngine(); sub15150(true); sub12A7F(); - displayLowStatusScreen(-1); + displayLowStatusScreen(true); if (!_protectionPassed) return Common::kNoError; warning("STUB - Main loop"); - + for (;;) { + displayFctFullScreen(); + } return Common::kNoError; } @@ -345,7 +364,27 @@ int32 EfhEngine::readFileToBuffer(Common::String &filename, uint8 *destBuffer) { void EfhEngine::readAnimInfo() { Common::String fileName = "animinfo"; - readFileToBuffer(fileName, _animInfo); + uint8 animInfoBuf[9000]; + memset(animInfoBuf, 0, 9000); + uint8 *curPtr = animInfoBuf; + + readFileToBuffer(fileName, animInfoBuf); + for (int i = 0; i < 100; ++i) { + for (int id = 0; id < 15; ++id) { + _animInfo[i]._unkAnimArray[id].field0 = *curPtr++; + _animInfo[i]._unkAnimArray[id].field1 = *curPtr++; + _animInfo[i]._unkAnimArray[id].field2 = *curPtr++; + _animInfo[i]._unkAnimArray[id].field3 = *curPtr++; + } + + for (int id = 0; id < 10; ++id) + _animInfo[i]._field3C_startY[id] = *curPtr++; + + for (int id = 0; id < 10; ++id) { + _animInfo[i]._field46_startX[id] = READ_LE_INT16(curPtr); + curPtr += 2; + } + } } void EfhEngine::findMapFile(int16 mapId) { @@ -445,7 +484,22 @@ void EfhEngine::drawUnknownMenuBox() { void EfhEngine::displayAnimFrame() { // The original had a parameter. As it was always equal to zero, it was removed in ScummVM - warning("STUB - displayAnimFrame"); + + if (_animImageSetId == 0xFF) + return; + + if (_animImageSetId == 0xFE) { + sub10B77_unkDisplayFct1(_portraitSubFilesArray[0], 16, 8); + return; + } + + sub10B77_unkDisplayFct1(_portraitSubFilesArray[0], 16, 8); + for (int i = 0; i < 4; ++i) { + int16 var2 = _animInfo[_animImageSetId]._unkAnimArray[_unkAnimRelatedIndex].field0; + if (var2 == 0xFF) + continue; + sub10B77_unkDisplayFct1(_portraitSubFilesArray[var2 + 1], _animInfo[_animImageSetId]._field46_startX[var2] + 16, _animInfo[_animImageSetId]._field3C_startY[var2] + 8); + } } void EfhEngine::displayAnimFrames(int16 animId, bool displayMenuBoxFl) { @@ -770,7 +824,10 @@ void EfhEngine::initEngine() { for (int i = 0; i < 300; ++i) _items[i].init(); memset(_tileFact, 0, sizeof(_tileFact)); - memset(_animInfo, 0, sizeof(_animInfo)); + + for (int i = 0; i < 100; ++i) + _animInfo[i].init(); + memset(_history, 0, sizeof(_history)); memset(_techData, 0, sizeof(_techData)); @@ -931,6 +988,30 @@ void EfhEngine::saveAnimImageSetId() { _animImageSetId = 255; } +int16 EfhEngine::getEquipmentDefense(int16 charId, bool flag) { + warning("STUB: getEquipmentDefense"); + return 0; +} + +uint16 EfhEngine::sub1C80A(int16 charId, int field18, bool flag) { + for (int i = 0; i < 10; ++i) { + if ((_npcBuf[charId]._inventory[i]._stat1 & 0x80) == 0) + continue; + + int16 itemId = _npcBuf[charId]._inventory[i]._ref; + + if (_items[itemId].field_18 != field18) + continue; + + if (!flag) + return i; + + return itemId; + } + + return 0x7FFF; +} + void EfhEngine::sub15150(bool flag) { uint8 mapTileInfo = getMapTileInfo(_mapPosX, _mapPosY); int16 imageSetId = _currentTileBankImageSetId[mapTileInfo / 72]; @@ -956,12 +1037,108 @@ void EfhEngine::sub15150(bool flag) { } } +void EfhEngine::sub1258F(bool largeMapFl, int16 posX, int16 posY, int imapSize, bool unkFl1, bool unkFl2) { + warning("STUB : sub1258F"); +} + +void EfhEngine::sub1256E(int16 posX, int16 posY) { + sub1258F(false, posX, posY, 23, _word2C876, _word2C878); +} + +void EfhEngine::sub1254C(int16 posX, int16 posY) { + sub1258F(true, posX, posY, 63, _word2C876, _word2C878); +} + void EfhEngine::sub12A7F() { - warning("STUB - sub12A7F"); + for (int16 counter = 0; counter < 2; ++counter) { + _word2C894 = 0; + if (!_largeMapFlag) { + if (_fullPlaceId != 0xFF) + sub1256E(_mapPosX, _mapPosY); + + if (_word2C8D9 != 0) + sub150EE(); + } else { + if (_techId != 0xFF) + sub1254C(_mapPosX, _mapPosY); + + if (_word2C8D9 != 0) + sub150EE(); + } + if (counter == 0) + displayFctFullScreen(); + } } -void EfhEngine::displayLowStatusScreen(int i) { - warning("STUB - displayLowStatusScreen"); +void EfhEngine::displayLowStatusScreen(bool flag) { + static char strName[5] = "Name"; + static char strDef[4] = "DEF"; + static char strHp[3] = "HP"; + static char strMaxHp[7] = "Max HP"; + static char strWeapon[7] = "Weapon"; + static char strDead[9] = "* DEAD *"; + + char buffer[80]; + memset(buffer, 0, 80); + + for (int counter = 0; counter < 2; ++counter) { + if (counter == 0 || flag) { + unkFct_displayMenuBox_2(0); + set_unkVideoRelatedWord1_to_0Fh(); + displayCenteredString(strName, 16, 88, 152); + displayCenteredString(strDef, 104, 128, 152); + displayCenteredString(strHp, 144, 176, 152); + displayCenteredString(strMaxHp, 192, 224, 152); + displayCenteredString(strWeapon, 225, 302, 152); + set_unkVideoRelatedWord1_to_0Ch(); + + for (int i = 0; i < 3; ++i) { + if (_teamCharId[i] == -1) + continue; + int16 charId = _teamCharId[i]; + int16 textPosY = 161 + 9 * i; + copyString(_npcBuf[charId]._name, buffer); + setTextPos(16, textPosY); + unkFct_displayString_2(buffer); + sprintf(buffer, "%d", getEquipmentDefense(charId, false)); + displayCenteredString(buffer, 104, 128, textPosY); + sprintf(buffer, "%d", _npcBuf[charId]._hitPoints); + displayCenteredString(buffer, 144, 176, textPosY); + sprintf(buffer, "%d", _npcBuf[charId]._maxHP); + displayCenteredString(buffer, 192, 224, textPosY); + + if (_npcBuf[charId]._hitPoints <= 0) { + displayCenteredString(strDead, 225, 302, textPosY); + continue; + } + + switch (_teamCharStatus[i]._status) { + case 0: { + uint16 var4 = sub1C80A(charId, 9, true); + if (var4 == 0x7FFF) + strcpy(_nameBuffer, "(NONE)"); + else + copyString(_items[var4]._name, _nameBuffer); + } + break; + case 1: + strcpy(_nameBuffer, "* ASLEEP *"); + break; + case 2: + strcpy(_nameBuffer, "* FROZEN *"); + break; + default: + strcpy(_nameBuffer, "* DISABLED *"); + break; + } + + displayCenteredString(_nameBuffer, 225, 302, textPosY); + } + } + + if (counter == 0 && flag) + displayFctFullScreen(); + } } void EfhEngine::loadImageSet(int imageSetId, uint8 *buffer, uint8 **subFilesArray, uint8 *destBuffer) { @@ -1188,12 +1365,13 @@ void EfhEngine::drawMapWindow() { drawMenuBox(128, 8, 303, 135, 0); } -void EfhEngine::copyString(uint8 *srcStr, uint8 *destStr) { - uint8 lastChar = 1; +void EfhEngine::copyString(char *srcStr, char *destStr) { + char lastChar = 1; int16 idx = 0; while (lastChar != 0) { lastChar = destStr[idx] = srcStr[idx]; + ++idx; } } @@ -1534,8 +1712,8 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, var110 = sub1C219("Nothing...", 1, 2, 0xFFFF); displayFctFullScreen(); } else { - copyString((uint8 *)_npcBuf[_teamCharId[counter]]._name, (uint8 *)_ennemyNamePt2); - copyString((uint8 *)_items[var110]._name, (uint8 *)_nameBuffer); + copyString(_npcBuf[_teamCharId[counter]]._name, _ennemyNamePt2); + copyString(_items[var110]._name, _nameBuffer); sprintf(dest, "%s finds a %s!", _ennemyNamePt2, _nameBuffer); drawMapWindow(); displayFctFullScreen(); @@ -1622,7 +1800,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, unkFct_displayString_2(dest); if (var_EE != 0xFF) { - displayLowStatusScreen(-1); + displayLowStatusScreen(true); int16 teamSlot = handleCharacterJoining(); if (teamSlot > -1) { _teamCharId[teamSlot] = var_EE; @@ -1664,7 +1842,7 @@ void EfhEngine::sub1512B() { sub150EE(); sub15018(); displayAnimFrame(); - displayLowStatusScreen(0); + displayLowStatusScreen(false); } void EfhEngine::sub221FA(uint8 *impArray, bool flag) { @@ -1733,6 +1911,20 @@ void EfhEngine::sub252CE(uint8 curChar, int16 posX, int posY) { } } +void EfhEngine::set_unkVideoRelatedWord1_to_0Fh() { + if (_videoMode == 8) // CGA + _unkVideoRelatedWord1 = 0x3; + else + _unkVideoRelatedWord1 = 0xF; +} + +void EfhEngine::set_unkVideoRelatedWord1_to_0Ch() { + if (_videoMode == 8) // CGA + _unkVideoRelatedWord1 = 0x2; + else + _unkVideoRelatedWord1 = 0xC; +} + void EfhEngine::setNumLock() { // No implementation in ScummVM } @@ -1773,6 +1965,10 @@ void EfhEngine::unkFct_displayString_2(char *message) { setNextCharacterPos(); } +void EfhEngine::unkFct_displayMenuBox_2(int16 color) { + drawMenuBox(16, 152, 302, 189, color); +} + void EfhEngine::loadImageSetToTileBank(int16 tileBankId, int16 imageSetId) { // TODO: all the values of titleBankId and imageSetId are hardcoded. When all the calls are implemented, fix the values to avoid to have to decrease them int16 bankId = tileBankId - 1; diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 28e17f2dc55d..a666ae12fb1e 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -79,6 +79,22 @@ struct InvObject { void init(); }; +struct UnkAnimStruct { + uint8 field0; + uint8 field1; + uint8 field2; + uint8 field3; + + void init(); +}; +struct AnimInfo { + UnkAnimStruct _unkAnimArray[15]; + uint8 _field3C_startY[10]; + uint16 _field46_startX[10]; + + void init(); +}; + struct ItemStruct { char _name[15]; uint8 _damage; @@ -250,7 +266,9 @@ class EfhEngine : public Engine { void initMapMonsters(); void loadMapMonsters(); void saveAnimImageSetId(); - void displayLowStatusScreen(int i); + int16 getEquipmentDefense(int16 charId, bool flag); + uint16 sub1C80A(int16 charId, int field18, bool flag); + void displayLowStatusScreen(bool flag); void loadImageSet(int imageSetId, uint8 *buffer, uint8 **subFilesArray, uint8 *destBuffer); void rImageFile(Common::String filename, uint8 *targetBuffer, uint8 **subFilesArray, uint8 *packedBuffer); void displayFctFullScreen(); @@ -273,6 +291,9 @@ class EfhEngine : public Engine { void setTextPos(int16 textPosX, int16 textPosY); void sub15150(bool flag); + void sub1258F(bool cond, int16 pos_x, int16 pos_y, int i, bool c876, bool c878); + void sub1256E(int16 posX, int16 posY); + void sub1254C(int16 posX, int16 posY); void sub12A7F(); void sub10B77_unkDisplayFct1(uint8 *imagePtr, int16 posX, int16 posY); void sub24D92(BufferBM *bufferBM, int16 posX, int16 posY); @@ -292,7 +313,7 @@ class EfhEngine : public Engine { int16 chooseCharacterToReplace(); int16 handleCharacterJoining(); void drawMapWindow(); - void copyString(uint8 *srcStr, uint8 *destStr); + void copyString(char *srcStr, char *destStr); int16 script_parse(uint8 *str, int posX, int posY, int maxX, int maxY, int argC); void sub133E5(uint8 *impPtr, int posX, int posY, int maxX, int maxY, int argC); void sub1512B(); @@ -305,12 +326,15 @@ class EfhEngine : public Engine { int16 sub1C219(const char *str, int menuType, int arg4, int displayTeamWindowFl); int16 sub151FD(int16 posX, int16 posY); void sub252CE(uint8 curChar, int16 posX, int posY); + void set_unkVideoRelatedWord1_to_0Fh(); + void set_unkVideoRelatedWord1_to_0Ch(); void setNumLock(); void unkfct_mapFunction(); void unkFct_anim(); void setNextCharacterPos(); void unkFct_displayString_2(char *message); + void unkFct_displayMenuBox_2(int16 color); uint8 _videoMode; uint8 _bufferCharBM[128]; @@ -334,7 +358,7 @@ class EfhEngine : public Engine { uint8 _titleSong[1024]; ItemStruct _items[300]; uint8 _tileFact[864]; - uint8 _animInfo[9000]; + AnimInfo _animInfo[100]; uint8 _history[256]; uint8 _techData[4096]; char _ennemyNamePt2[20]; @@ -385,6 +409,8 @@ class EfhEngine : public Engine { int16 _word2C880; int16 _word2C894; int16 _word2C8D7; + bool _word2C876; + bool _word2C878; bool _word2C87A; int16 _unk_sub26437_flag; @@ -395,8 +421,9 @@ class EfhEngine : public Engine { int16 _techDataId_MapPosX, _techDataId_MapPosY; uint16 _lastMainPlaceId; - uint8 _word2C86E; + uint16 _word2C86E; uint8 *_dword2C856; + int16 _word2C8D9; }; } // End of namespace Efh From 9f3174bd5e66fa10b2ac388939ff9879a2ca499c Mon Sep 17 00:00:00 2001 From: Strangerke Date: Wed, 1 Dec 2021 01:04:56 +0100 Subject: [PATCH 069/412] EFH: Implement getEquipmentDefense --- engines/efh/efh.cpp | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index bb9809cce605..6fb43ba9d499 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -989,8 +989,30 @@ void EfhEngine::saveAnimImageSetId() { } int16 EfhEngine::getEquipmentDefense(int16 charId, bool flag) { - warning("STUB: getEquipmentDefense"); - return 0; + int16 altDef = 0; + int16 totalDef = 0; + for (int i = 0; i < 10; ++i) { + if (_npcBuf[charId]._inventory[i]._ref == 0x7FFF) + continue; + + if ((_npcBuf[charId]._inventory[i]._stat1 & 0x80) == 0) + continue; + + int16 curDef = _npcBuf[charId]._inventory[i]._stat2; + if (curDef == 0xFF) + curDef = _items[_npcBuf[charId]._inventory[i]._ref]._defense; + + if (curDef <= 0) + continue; + + totalDef += curDef; + altDef += (curDef / 8) + 1; + } + + if (flag) + return totalDef; + + return altDef; } uint16 EfhEngine::sub1C80A(int16 charId, int field18, bool flag) { From 05ba2b7d598f849f70b605584b98d6b2495afe1a Mon Sep 17 00:00:00 2001 From: Strangerke Date: Thu, 2 Dec 2021 00:21:47 +0100 Subject: [PATCH 070/412] EFH: Implement drawMap, some renaming --- engines/efh/efh.cpp | 246 ++++++++++++++++++++++++++++++-------------- engines/efh/efh.h | 29 +++--- 2 files changed, 186 insertions(+), 89 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 6fb43ba9d499..4d5cbc436156 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -229,7 +229,7 @@ EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst) _initRect = Common::Rect(0, 0, 0, 0); _engineInitPending = true; - _unkVideoRelatedWord1 = 0x0E; + _textColor = 0x0E; // Yellow _protectionPassed = false; _fullPlaceId = 0xFF; _guessAnimationAmount = 9; @@ -489,16 +489,16 @@ void EfhEngine::displayAnimFrame() { return; if (_animImageSetId == 0xFE) { - sub10B77_unkDisplayFct1(_portraitSubFilesArray[0], 16, 8); + displayRawDataAtPos(_portraitSubFilesArray[0], 16, 8); return; } - sub10B77_unkDisplayFct1(_portraitSubFilesArray[0], 16, 8); + displayRawDataAtPos(_portraitSubFilesArray[0], 16, 8); for (int i = 0; i < 4; ++i) { int16 var2 = _animInfo[_animImageSetId]._unkAnimArray[_unkAnimRelatedIndex].field0; if (var2 == 0xFF) continue; - sub10B77_unkDisplayFct1(_portraitSubFilesArray[var2 + 1], _animInfo[_animImageSetId]._field46_startX[var2] + 16, _animInfo[_animImageSetId]._field3C_startY[var2] + 8); + displayRawDataAtPos(_portraitSubFilesArray[var2 + 1], _animInfo[_animImageSetId]._field46_startX[var2] + 16, _animInfo[_animImageSetId]._field3C_startY[var2] + 8); } } @@ -717,9 +717,9 @@ Common::KeyCode EfhEngine::getLastCharAfterAnimCount(int16 delay) { } void EfhEngine::playIntro() { - sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 0); + displayRawDataAtPos(_circleImageSubFileArray[0], 0, 0); displayFctFullScreen(); - sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 0); + displayRawDataAtPos(_circleImageSubFileArray[0], 0, 0); // Load animations on previous picture with GF loadImageSet(63, _circleImageBuf, _circleImageSubFileArray, _hiResImageBuf); @@ -729,61 +729,61 @@ void EfhEngine::playIntro() { return; // With GF on the bed - sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 144); + displayRawDataAtPos(_circleImageSubFileArray[0], 0, 144); sub133E5(_imp2PtrArray[0], 6, 150, 268, 186, 0); displayFctFullScreen(); - sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 144); + displayRawDataAtPos(_circleImageSubFileArray[0], 0, 144); sub133E5(_imp2PtrArray[0], 6, 150, 268, 186, 0); lastInput = getLastCharAfterAnimCount(80); if (lastInput == Common::KEYCODE_ESCAPE) return; // Poof - sub10B77_unkDisplayFct1(_circleImageSubFileArray[1], 110, 16); - sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 144); + displayRawDataAtPos(_circleImageSubFileArray[1], 110, 16); + displayRawDataAtPos(_circleImageSubFileArray[0], 0, 144); sub133E5(_imp2PtrArray[1], 6, 150, 268, 186, 0); displayFctFullScreen(); - sub10B77_unkDisplayFct1(_circleImageSubFileArray[1], 110, 16); - sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 144); + displayRawDataAtPos(_circleImageSubFileArray[1], 110, 16); + displayRawDataAtPos(_circleImageSubFileArray[0], 0, 144); sub133E5(_imp2PtrArray[1], 6, 150, 268, 186, 0); lastInput = getLastCharAfterAnimCount(80); if (lastInput == Common::KEYCODE_ESCAPE) return; // On the phone - sub10B77_unkDisplayFct1(_circleImageSubFileArray[2], 110, 16); - sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 144); + displayRawDataAtPos(_circleImageSubFileArray[2], 110, 16); + displayRawDataAtPos(_circleImageSubFileArray[0], 0, 144); sub133E5(_imp2PtrArray[2], 6, 150, 268, 186, 0); displayFctFullScreen(); - sub10B77_unkDisplayFct1(_circleImageSubFileArray[2], 110, 16); - sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 144); + displayRawDataAtPos(_circleImageSubFileArray[2], 110, 16); + displayRawDataAtPos(_circleImageSubFileArray[0], 0, 144); sub133E5(_imp2PtrArray[2], 6, 150, 268, 186, 0); lastInput = getLastCharAfterAnimCount(80); if (lastInput == Common::KEYCODE_ESCAPE) return; - sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 144); + displayRawDataAtPos(_circleImageSubFileArray[0], 0, 144); sub133E5(_imp2PtrArray[3], 6, 150, 268, 186, 0); displayFctFullScreen(); - sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 144); + displayRawDataAtPos(_circleImageSubFileArray[0], 0, 144); sub133E5(_imp2PtrArray[3], 6, 150, 268, 186, 0); lastInput = getLastCharAfterAnimCount(80); if (lastInput == Common::KEYCODE_ESCAPE) return; - sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 144); + displayRawDataAtPos(_circleImageSubFileArray[0], 0, 144); sub133E5(_imp2PtrArray[4], 6, 150, 268, 186, 0); displayFctFullScreen(); - sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 144); + displayRawDataAtPos(_circleImageSubFileArray[0], 0, 144); sub133E5(_imp2PtrArray[4], 6, 150, 268, 186, 0); lastInput = getLastCharAfterAnimCount(80); if (lastInput == Common::KEYCODE_ESCAPE) return; - sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 144); + displayRawDataAtPos(_circleImageSubFileArray[0], 0, 144); sub133E5(_imp2PtrArray[5], 6, 150, 268, 186, 0); displayFctFullScreen(); - sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 144); + displayRawDataAtPos(_circleImageSubFileArray[0], 0, 144); sub133E5(_imp2PtrArray[5], 6, 150, 268, 186, 0); getLastCharAfterAnimCount(80); } @@ -884,9 +884,9 @@ void EfhEngine::initEngine() { // Load Title Screen loadImageSet(11, _circleImageBuf, _circleImageSubFileArray, _hiResImageBuf); displayFctFullScreen(); - sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 0); + displayRawDataAtPos(_circleImageSubFileArray[0], 0, 0); displayFctFullScreen(); - sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 0); + displayRawDataAtPos(_circleImageSubFileArray[0], 0, 0); // Load map tiles bitmaps loadImageSetToTileBank(1, 1); @@ -1043,7 +1043,7 @@ void EfhEngine::sub15150(bool flag) { for (int counter = 0; counter < 2; ++counter) { if (counter == 0 || flag) { - sub1512B(); + displayGameScreen(); // TODO: _word2C86E is some kind of counter if (_word2C86E != 0) { // TODO: _dword2C856 is most likely an "Imp" Array @@ -1059,16 +1059,105 @@ void EfhEngine::sub15150(bool flag) { } } -void EfhEngine::sub1258F(bool largeMapFl, int16 posX, int16 posY, int imapSize, bool unkFl1, bool unkFl2) { - warning("STUB : sub1258F"); +void EfhEngine::drawMap(bool largeMapFl, int16 mapPosX, int16 mapPosY, int mapSize, bool unkFl1, bool unkFl2) { + int16 unkPosX = 5; + int16 unkPosY = 4; + int16 posX = 0; + int16 posY = 0; + int16 var6 = 0; + int16 minX = mapPosX - 5; + int16 minY = mapPosY - 4; + + if (minX < 0) { + unkPosX -= minX; + minX = 0; + } + + if (minY < 0) { + unkPosY -= minY; + minY = 0; + } + + int16 maxX = minX + 10; + int16 maxY = minY + 7; + + if (maxX > mapSize) { + unkPosX += (maxX - mapSize); + maxX = mapSize; + minX = mapSize - 10; + } + + if (maxY > mapSize) { + unkPosY += (maxY - mapSize); + maxY = mapSize; + minY = mapSize - 7; + } + + int16 var10 = 8; + for (int16 counterY = minY; counterY <= maxY; ++counterY) { + int16 var12 = 128; + for (int16 var16 = minX; var16 <= maxX; ++var16) { + if (largeMapFl) { + int16 idx = _mapGameMapPtr[(var16 * 64) + counterY]; // 64 = large map size (square) + displayRawDataAtPos(_imageSetSubFilesArray[idx], var12, var10); + } else { + int16 idx = _curPlace[(var16 * 24) + counterY]; // 24 = small map size (square) + displayRawDataAtPos(_imageSetSubFilesArray[idx], var12, var10); + } + var12 += 16; + } + var10 += 16; + } + + if (unkFl1) { + int16 var12 = 128 + unkPosX * 16; + int16 var10 = 8 + unkPosY * 16; + displayRawDataAtPos(_imageSetSubFilesArray[_imageSetSubFilesIdx], var12, var10); + } + + if (unkFl2) { + for (int16 var16 = 0; var16 < 64; ++var16) { + if ((_largeMapFlag && _mapMonsters[var16]._guess_fullPlaceId == 0xFE) || (!_largeMapFlag && _mapMonsters[var16]._guess_fullPlaceId == _fullPlaceId)){ + bool var4 = false; + posX = _mapMonsters[var16]._posX; + posY = _mapMonsters[var16]._posY; + + if (posX < minX || posX > maxX || posY < minY || posY > maxY) + continue; + + for (int16 counterY = 0; counterY < 9 && !var4; ++counterY) { + if (_mapMonsters[var16]._pictureRef[counterY] > 0) + var4 = true; + } + + if (!var4) + continue; + + var6 = 148 + kEncounters[_mapMonsters[var16]._MonsterRef]._animId; + int16 var1 = _mapMonsters[var16]._possessivePronounSHL6 & 0x3F; + + if (var1 == 0x3F && isCharacterATeamMember(_mapMonsters[var16]._field_1)) + continue; + + int16 var12 = 128 + (posX - minX) * 16; + var10 = 8 + (posY - minY) * 16; + displayRawDataAtPos(_imageSetSubFilesArray[var6], var12, var10); + } + } + } + + if (_word2C8D7 != 0) + return; + + warning("drawMap() - unexpected code reached, not implemented"); } -void EfhEngine::sub1256E(int16 posX, int16 posY) { - sub1258F(false, posX, posY, 23, _word2C876, _word2C878); +void EfhEngine::displaySmallMap(int16 posX, int16 posY) { + drawMap(false, posX, posY, 23, _word2C876, _word2C878); } -void EfhEngine::sub1254C(int16 posX, int16 posY) { - sub1258F(true, posX, posY, 63, _word2C876, _word2C878); +void EfhEngine::displayLargeMap(int16 posX, int16 posY) { + drawMap(true, posX, posY, 63, _word2C876, _word2C878); } void EfhEngine::sub12A7F() { @@ -1076,16 +1165,16 @@ void EfhEngine::sub12A7F() { _word2C894 = 0; if (!_largeMapFlag) { if (_fullPlaceId != 0xFF) - sub1256E(_mapPosX, _mapPosY); + displaySmallMap(_mapPosX, _mapPosY); if (_word2C8D9 != 0) - sub150EE(); + drawUpperRightBorders(); } else { if (_techId != 0xFF) - sub1254C(_mapPosX, _mapPosY); + displayLargeMap(_mapPosX, _mapPosY); if (_word2C8D9 != 0) - sub150EE(); + drawUpperRightBorders(); } if (counter == 0) displayFctFullScreen(); @@ -1106,13 +1195,13 @@ void EfhEngine::displayLowStatusScreen(bool flag) { for (int counter = 0; counter < 2; ++counter) { if (counter == 0 || flag) { unkFct_displayMenuBox_2(0); - set_unkVideoRelatedWord1_to_0Fh(); + setTextColorWhite(); displayCenteredString(strName, 16, 88, 152); displayCenteredString(strDef, 104, 128, 152); displayCenteredString(strHp, 144, 176, 152); displayCenteredString(strMaxHp, 192, 224, 152); displayCenteredString(strWeapon, 225, 302, 152); - set_unkVideoRelatedWord1_to_0Ch(); + setTextColorRed(); for (int i = 0; i < 3; ++i) { if (_teamCharId[i] == -1) @@ -1211,7 +1300,7 @@ void EfhEngine::copyGraphicBufferFromTo(EfhGraphicsStruct *efh_graphics_struct, warning("STUB - copyGraphicBufferFromTo"); } -void EfhEngine::sub24D92(BufferBM *bufferBM, int16 posX, int16 posY) { +void EfhEngine::displayBufferBmAtPos(BufferBM *bufferBM, int16 posX, int16 posY) { // TODO: Quick code to display stuff, may require to really reverse the actual function uint8 *destPtr = (uint8 *)_mainSurface->getBasePtr(posX, posY); // warning("%d %d - startX %d startY %d width %d height %d lineDataSize %d fieldD %d", posX, posY, bufferBM->_startX, bufferBM->_startY, bufferBM->_width, bufferBM->_height, bufferBM->_lineDataSize, bufferBM->_fieldD); @@ -1346,7 +1435,7 @@ void EfhEngine::sub26437(char *str, int16 startX, int16 startY, uint16 unkFl) { void EfhEngine::displayCenteredString(char *str, int16 minX, int16 maxX, int16 posY) { uint16 length = getStringWidth(str); int16 startCenteredDisplayX = minX + (maxX - minX - length) / 2; - sub26437(str, startCenteredDisplayX, posY, _unkVideoRelatedWord1); + sub26437(str, startCenteredDisplayX, posY, _textColor); } int16 EfhEngine::chooseCharacterToReplace() { @@ -1363,7 +1452,7 @@ int16 EfhEngine::handleCharacterJoining() { } for (int16 counter = 0; counter < 2; ++counter) { - drawMenuBox(200, 112, 278, 132, 0); + drawColoredRect(200, 112, 278, 132, 0); displayCenteredString(strReplaceWho, 200, 278, 117); if (counter == 0) displayFctFullScreen(); @@ -1371,7 +1460,7 @@ int16 EfhEngine::handleCharacterJoining() { int16 charId = chooseCharacterToReplace(); for (int16 counter = 0; counter < 2; ++counter) { - drawMenuBox(200, 112, 278, 132, 0); + drawColoredRect(200, 112, 278, 132, 0); if (counter == 0) displayFctFullScreen(); } @@ -1384,7 +1473,7 @@ int16 EfhEngine::handleCharacterJoining() { } void EfhEngine::drawMapWindow() { - drawMenuBox(128, 8, 303, 135, 0); + drawColoredRect(128, 8, 303, 135, 0); } void EfhEngine::copyString(char *srcStr, char *destStr) { @@ -1858,11 +1947,11 @@ void EfhEngine::sub133E5(uint8 *srcPtr, int posX, int posY, int maxX, int maxY, script_parse(_messageToBePrinted, posX, posY, maxX, maxY, argC); } -void EfhEngine::sub1512B() { - displayFullScreenColoredMenuBox(0); - sub15094(); - sub150EE(); - sub15018(); +void EfhEngine::displayGameScreen() { + clearScreen(0); + drawUpperLeftBorders(); + drawUpperRightBorders(); + drawBottomBorders(); displayAnimFrame(); displayLowStatusScreen(false); } @@ -1870,7 +1959,7 @@ void EfhEngine::sub1512B() { void EfhEngine::sub221FA(uint8 *impArray, bool flag) { for (uint8 counter = 0; counter < 2; ++counter) { if (counter == 0 || flag) { - drawMenuBox(16, 115, 111, 133, 0); + drawColoredRect(16, 115, 111, 133, 0); if (impArray != nullptr) { _word2C86E = 4; _dword2C856 = impArray; @@ -1880,22 +1969,22 @@ void EfhEngine::sub221FA(uint8 *impArray, bool flag) { } } -void EfhEngine::sub15094() { - sub10B77_unkDisplayFct1(_circleImageSubFileArray[0], 0, 0); - sub10B77_unkDisplayFct1(_circleImageSubFileArray[1], 112, 0); - sub10B77_unkDisplayFct1(_circleImageSubFileArray[3], 16, 0); +void EfhEngine::drawUpperLeftBorders() { + displayRawDataAtPos(_circleImageSubFileArray[0], 0, 0); + displayRawDataAtPos(_circleImageSubFileArray[1], 112, 0); + displayRawDataAtPos(_circleImageSubFileArray[3], 16, 0); } -void EfhEngine::sub150EE() { - sub10B77_unkDisplayFct1(_circleImageSubFileArray[2], 304, 0); - sub10B77_unkDisplayFct1(_circleImageSubFileArray[4], 128, 0); +void EfhEngine::drawUpperRightBorders() { + displayRawDataAtPos(_circleImageSubFileArray[2], 304, 0); + displayRawDataAtPos(_circleImageSubFileArray[4], 128, 0); } -void EfhEngine::sub15018() { - sub10B77_unkDisplayFct1(_circleImageSubFileArray[7], 16, 136); - sub10B77_unkDisplayFct1(_circleImageSubFileArray[8], 16, 192); - sub10B77_unkDisplayFct1(_circleImageSubFileArray[5], 0, 136); - sub10B77_unkDisplayFct1(_circleImageSubFileArray[6], 304, 136); +void EfhEngine::drawBottomBorders() { + displayRawDataAtPos(_circleImageSubFileArray[7], 16, 136); + displayRawDataAtPos(_circleImageSubFileArray[8], 16, 192); + displayRawDataAtPos(_circleImageSubFileArray[5], 0, 136); + displayRawDataAtPos(_circleImageSubFileArray[6], 304, 136); } void EfhEngine::sub15A28(int16 arg0, int16 arg2) { @@ -1927,24 +2016,31 @@ void EfhEngine::sub252CE(uint8 curChar, int16 posX, int posY) { int16 x = 0; for (int i = 7; i >= 7 - width; --i) { if (_fontDescr._fontData[charId]._lines[line] & (1 << i)) - destPtr[320 * line + x] = 14; + destPtr[320 * line + x] = _textColor; ++x; } } } -void EfhEngine::set_unkVideoRelatedWord1_to_0Fh() { +void EfhEngine::setTextColorWhite() { + if (_videoMode == 8) // CGA + _textColor = 0x3; + else + _textColor = 0xF; +} + +void EfhEngine::setTextColorRed() { if (_videoMode == 8) // CGA - _unkVideoRelatedWord1 = 0x3; + _textColor = 0x2; else - _unkVideoRelatedWord1 = 0xF; + _textColor = 0xC; } -void EfhEngine::set_unkVideoRelatedWord1_to_0Ch() { +void EfhEngine::setTextColor_08h() { if (_videoMode == 8) // CGA - _unkVideoRelatedWord1 = 0x2; + _textColor = 0x1; else - _unkVideoRelatedWord1 = 0xC; + _textColor = 0x8; } void EfhEngine::setNumLock() { @@ -1982,13 +2078,13 @@ void EfhEngine::setNextCharacterPos() { } void EfhEngine::unkFct_displayString_2(char *message) { - sub26437(message, _textPosX, _textPosY, _unkVideoRelatedWord1); + sub26437(message, _textPosX, _textPosY, _textColor); _textPosX += getStringWidth(message) + 1; setNextCharacterPos(); } void EfhEngine::unkFct_displayMenuBox_2(int16 color) { - drawMenuBox(16, 152, 302, 189, color); + drawColoredRect(16, 152, 302, 189, color); } void EfhEngine::loadImageSetToTileBank(int16 tileBankId, int16 imageSetId) { @@ -2013,7 +2109,7 @@ void EfhEngine::restoreAnimImageSetId() { } void EfhEngine::checkProtection() { - _unkVideoRelatedWord1 = 0xE; + _textColor = 0xE; //CHECKME : Well, yeah, some code may be missing there. Who knows. @@ -2166,15 +2262,15 @@ void EfhEngine::drawRect(int minX, int minY, int maxX, int maxY) { } -void EfhEngine::drawMenuBox(int minX, int minY, int maxX, int maxY, int color) { +void EfhEngine::drawColoredRect(int minX, int minY, int maxX, int maxY, int color) { uint8 oldValue = _defaultBoxColor; _defaultBoxColor = color; drawRect(minX, minY, maxX, maxY); _defaultBoxColor = oldValue; } -void EfhEngine::displayFullScreenColoredMenuBox(int color) { - drawMenuBox(0, 0, 320, 200, color); +void EfhEngine::clearScreen(int color) { + drawColoredRect(0, 0, 320, 200, color); } Common::KeyCode EfhEngine::handleAndMapInput(bool animFl) { @@ -2234,7 +2330,7 @@ void EfhEngine::copyCurrentPlaceToBuffer(int id) { memcpy(_curPlace, placesPtr, 24 * 24); } -void EfhEngine::sub10B77_unkDisplayFct1(uint8 *imagePtr, int16 posX, int16 posY) { +void EfhEngine::displayRawDataAtPos(uint8 *imagePtr, int16 posX, int16 posY) { uint16 height = READ_LE_INT16(imagePtr); uint16 width = READ_LE_INT16(imagePtr + 2); uint8 *imageData = imagePtr + 4; @@ -2245,6 +2341,6 @@ void EfhEngine::sub10B77_unkDisplayFct1(uint8 *imagePtr, int16 posX, int16 posY) _imageDataPtr._width = width * 2; // 2 pixels per byte _imageDataPtr._startX = _imageDataPtr._startY = 0; - sub24D92(&_imageDataPtr, posX, posY); + displayBufferBmAtPos(&_imageDataPtr, posX, posY); } } // End of namespace Efh diff --git a/engines/efh/efh.h b/engines/efh/efh.h index a666ae12fb1e..bea50bb78e33 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -282,8 +282,8 @@ class EfhEngine : public Engine { void copyCurrentPlaceToBuffer(int id); uint8 getMapTileInfo(int16 mapPosX, int16 mapPosY); void drawRect(int minX, int minY, int maxX, int maxY); - void drawMenuBox(int minX, int minY, int maxX, int maxY, int color); - void displayFullScreenColoredMenuBox(int color); + void drawColoredRect(int minX, int minY, int maxX, int maxY, int color); + void clearScreen(int color); Common::KeyCode handleAndMapInput(bool animFl); void displayNextAnimFrame(); void writeTechAndMapFiles(); @@ -291,12 +291,12 @@ class EfhEngine : public Engine { void setTextPos(int16 textPosX, int16 textPosY); void sub15150(bool flag); - void sub1258F(bool cond, int16 pos_x, int16 pos_y, int i, bool c876, bool c878); - void sub1256E(int16 posX, int16 posY); - void sub1254C(int16 posX, int16 posY); + void drawMap(bool largeMapFl, int16 mapPosX, int16 mapPosY, int mapSize, bool unkFl1, bool unkFl2); + void displaySmallMap(int16 posX, int16 posY); + void displayLargeMap(int16 posX, int16 posY); void sub12A7F(); - void sub10B77_unkDisplayFct1(uint8 *imagePtr, int16 posX, int16 posY); - void sub24D92(BufferBM *bufferBM, int16 posX, int16 posY); + void displayRawDataAtPos(uint8 *imagePtr, int16 posX, int16 posY); + void displayBufferBmAtPos(BufferBM *bufferBM, int16 posX, int16 posY); uint8 *script_readNumberArray(uint8 *buffer, int16 destArraySize, int16 *destArray); uint8 *script_getNumber(uint8 *srcBuffer, int16 *retval); void removeObject(int16 charId, int16 objectId); @@ -316,18 +316,19 @@ class EfhEngine : public Engine { void copyString(char *srcStr, char *destStr); int16 script_parse(uint8 *str, int posX, int posY, int maxX, int maxY, int argC); void sub133E5(uint8 *impPtr, int posX, int posY, int maxX, int maxY, int argC); - void sub1512B(); + void displayGameScreen(); void sub221FA(uint8 *impArray, bool flag); - void sub15094(); - void sub150EE(); - void sub15018(); + void drawUpperLeftBorders(); + void drawUpperRightBorders(); + void drawBottomBorders(); void sub15A28(int16 arg0, int16 arg2); void sub2455E(int16 arg0, int16 arg1, int16 arg2); int16 sub1C219(const char *str, int menuType, int arg4, int displayTeamWindowFl); int16 sub151FD(int16 posX, int16 posY); void sub252CE(uint8 curChar, int16 posX, int posY); - void set_unkVideoRelatedWord1_to_0Fh(); - void set_unkVideoRelatedWord1_to_0Ch(); + void setTextColorWhite(); + void setTextColorRed(); + void setTextColor_08h(); void setNumLock(); void unkfct_mapFunction(); @@ -375,7 +376,7 @@ class EfhEngine : public Engine { FontDescr _fontDescr; uint16 _word31E9E; - uint16 _unkVideoRelatedWord1; + uint16 _textColor; int16 _oldAnimImageSetId; int16 _animImageSetId; From e48753cf6dff5e336c6f8ee0c12c8d6aba0aeae3 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Thu, 2 Dec 2021 00:32:41 +0100 Subject: [PATCH 071/412] EFH: Disable noisy useless code --- engines/efh/efh.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 4d5cbc436156..403681f507b5 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -1283,8 +1283,7 @@ void EfhEngine::rImageFile(Common::String filename, uint8 *targetBuffer, uint8 * void EfhEngine::displayFctFullScreen() { // CHECKME: 319 is in the original but looks suspicious. - copyDirtyRect(0, 0, 319, 200); - + // copyDirtyRect(0, 0, 319, 200); _system->copyRectToScreen((uint8 *)_mainSurface->getPixels(), 320, 0, 0, 320, 200); _system->updateScreen(); From 63534f8a346f75bd11fa7b1d3cff4e825129d106 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Fri, 3 Dec 2021 07:50:02 +0100 Subject: [PATCH 072/412] EFH: Start implementing main loop --- engines/efh/efh.cpp | 371 +++++++++++++++++++++++++++++++++++++++++--- engines/efh/efh.h | 26 +++- 2 files changed, 368 insertions(+), 29 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 403681f507b5..8041fa5a4253 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -247,6 +247,7 @@ EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst) _teamSize = 1; _word2C872 = 0; _imageSetSubFilesIdx = 144; + _oldImageSetSubFilesIdx = 144; _mapPosX = _mapPosY = 31; _oldMapPosX = _oldMapPosY = 31; @@ -258,14 +259,15 @@ EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst) _lastMainPlaceId = 0; _word2C86E = 0; _dword2C856 = nullptr; - _word2C880 = 0; - _word2C894 = 0; - _word2C8D7 = -1; + _word2C880 = false; + _word2C894 = false; + _word2C8D7 = true; _word2C876 = true; _word2C878 = true; _word2C87A = false; _unk_sub26437_flag = 0; - _word2C8D9 = 0; + _word2C8D9 = false; + _word2C8D5 = false; memset(_messageToBePrinted, 0, 400); } @@ -339,8 +341,123 @@ Common::Error EfhEngine::run() { if (!_protectionPassed) return Common::kNoError; + uint32 lastMs = _system->getMillis(); warning("STUB - Main loop"); for (;;) { + _system->delayMillis(20); + uint32 newMs = _system->getMillis(); + + if (newMs - lastMs >= 200) { + lastMs = newMs; + unkFct_anim(); + } + + Common::Event event; + _system->getEventManager()->pollEvent(event); + Common::KeyCode retVal = Common::KEYCODE_INVALID; + Common::KeyCode lastInput = getLastCharAfterAnimCount(4); + if (event.type == Common::EVENT_KEYUP) { + retVal = lastInput; + } + + switch (retVal) { + case Common::KEYCODE_DOWN: + case Common::KEYCODE_KP2: + goSouth(); + _imageSetSubFilesIdx = 144; + break; + case Common::KEYCODE_UP: + case Common::KEYCODE_KP8: + goNorth(); + _imageSetSubFilesIdx = 145; + break; + case Common::KEYCODE_RIGHT: + case Common::KEYCODE_KP6: + goEast(); + _imageSetSubFilesIdx = 146; + break; + case Common::KEYCODE_LEFT: + case Common::KEYCODE_KP4: + goWest(); + _imageSetSubFilesIdx = 147; + break; + case Common::KEYCODE_PAGEUP: + case Common::KEYCODE_KP9: + goNorthEast(); + _imageSetSubFilesIdx = 146; + break; + case Common::KEYCODE_PAGEDOWN: + case Common::KEYCODE_KP3: + goSouthEast(); + _imageSetSubFilesIdx = 146; + break; + case Common::KEYCODE_END: + case Common::KEYCODE_KP1: + goSouthWest(); + _imageSetSubFilesIdx = 147; + break; + case Common::KEYCODE_HOME: + case Common::KEYCODE_KP7: + goNorthWest(); + _imageSetSubFilesIdx = 147; + break; + + default: + if (retVal != Common::KEYCODE_INVALID) + warning("Main Loop: Unhandled input %d", retVal); + break; + } + + if ((_mapPosX != _oldMapPosX || _mapPosY != _oldMapPosY) && !_shouldQuit) { + int16 var4 = sub16E14(); + if (!_word2C8D5 || var4 != 0) { + _oldMapPosX = _mapPosX; + _oldMapPosY = _mapPosY; + _oldImageSetSubFilesIdx = _imageSetSubFilesIdx; + _word2C894 = true; + } else { + _mapPosX = _oldMapPosX; + _mapPosY = _oldMapPosY; + if (_oldImageSetSubFilesIdx != _imageSetSubFilesIdx) { + _word2C894 = true; + _oldImageSetSubFilesIdx = _imageSetSubFilesIdx; + } + } + if (_largeMapFlag) { + _techDataId_MapPosX = _mapPosX; + _techDataId_MapPosY = _mapPosY; + } + } + + if (!_shouldQuit) { + sub174A0(); + } + + if (_word2C894 && !_shouldQuit) { + sub12A7F(); + displayLowStatusScreen(true); + } + + if (!_shouldQuit) { + handleNewRoundEffects(); + + if (_word2C86E > 0) { + if (--_word2C86E == 0) { + sub221FA(nullptr, true); + } + } + } + + if (--_unkArray2C8AA[0] < 0 && !_shouldQuit) + _unkArray2C8AA[0] = 0; + + if (isTPK()) { + if (handleDeathMenu()) + _shouldQuit = true; + } + + warning("Main loop - missing implementation"); + displayFctFullScreen(); } return Common::kNoError; @@ -1111,7 +1228,7 @@ void EfhEngine::drawMap(bool largeMapFl, int16 mapPosX, int16 mapPosY, int mapSi if (unkFl1) { int16 var12 = 128 + unkPosX * 16; - int16 var10 = 8 + unkPosY * 16; + var10 = 8 + unkPosY * 16; displayRawDataAtPos(_imageSetSubFilesArray[_imageSetSubFilesIdx], var12, var10); } @@ -1146,7 +1263,7 @@ void EfhEngine::drawMap(bool largeMapFl, int16 mapPosX, int16 mapPosY, int mapSi } } - if (_word2C8D7 != 0) + if (_word2C8D7) return; warning("drawMap() - unexpected code reached, not implemented"); @@ -1162,18 +1279,18 @@ void EfhEngine::displayLargeMap(int16 posX, int16 posY) { void EfhEngine::sub12A7F() { for (int16 counter = 0; counter < 2; ++counter) { - _word2C894 = 0; + _word2C894 = false; if (!_largeMapFlag) { if (_fullPlaceId != 0xFF) displaySmallMap(_mapPosX, _mapPosY); - if (_word2C8D9 != 0) + if (_word2C8D9) drawUpperRightBorders(); } else { if (_techId != 0xFF) displayLargeMap(_mapPosX, _mapPosY); - if (_word2C8D9 != 0) + if (_word2C8D9) drawUpperRightBorders(); } if (counter == 0) @@ -1384,6 +1501,16 @@ bool EfhEngine::isCharacterATeamMember(int16 id) { return false; } +bool EfhEngine::isTPK() { + int16 zeroedChar = 0; + for (int16 counter = 0; counter < _teamSize; ++counter) { + if (_npcBuf[_teamCharId[counter]]._hitPoints <= 0) + ++zeroedChar; + } + + return zeroedChar == _teamSize; +} + void EfhEngine::handleWinSequence() { warning("STUB - handleWinSequence"); } @@ -1564,8 +1691,8 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, _oldMapPosX = _mapPosX = scriptNumberArray[1]; _oldMapPosY = _mapPosY = scriptNumberArray[2]; loadPlacesFile(scriptNumberArray[0], false); - _word2C880 = -1; - _word2C894 = -1; + _word2C880 = true; + _word2C894 = true; } break; case 0x01: @@ -1573,8 +1700,8 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, _largeMapFlag = true; _oldMapPosX = _mapPosX = _techDataId_MapPosX; _oldMapPosY = _mapPosY = _techDataId_MapPosY; - _word2C880 = -1; - _word2C894 = -1; + _word2C880 = true; + _word2C894 = true; } break; case 0x02: @@ -1586,8 +1713,8 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, _oldMapPosY = _mapPosY = scriptNumberArray[2]; loadTechMapImp(scriptNumberArray[0]); _largeMapFlag = true; - _word2C880 = -1; - _word2C894 = -1; + _word2C880 = true; + _word2C894 = true; doneFlag = true; } break; @@ -1599,8 +1726,8 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, _mapPosX = getRandom(var110) + scriptNumberArray[0] - 1; _mapPosY = getRandom(var10E) + scriptNumberArray[1] - 1; - _word2C880 = -1; - _word2C894 = -1; + _word2C880 = true; + _word2C894 = true; } break; case 0x04: @@ -1608,8 +1735,8 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, if (argC != 0) { _mapPosX = scriptNumberArray[0]; _mapPosY = scriptNumberArray[1]; - _word2C880 = -1; - _word2C894 = -1; + _word2C880 = true; + _word2C894 = true; } break; case 0x05: @@ -1776,7 +1903,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, _oldMapPosX = _mapPosX = scriptNumberArray[0]; _oldMapPosY = _mapPosY = scriptNumberArray[1]; _largeMapFlag = true; - _word2C894 = -1; + _word2C894 = true; } break; case 0x16: @@ -1836,7 +1963,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, if (var110 != -1) { _mapUnknownPtr[var110 * 9 + 1] = 0xFF; } - _word2C894 = -1; + _word2C894 = true; } break; case 0x19: @@ -2042,12 +2169,199 @@ void EfhEngine::setTextColor_08h() { _textColor = 0x8; } +bool EfhEngine::isPosOutOfMap(int16 mapPosX, int16 mapPosY) { + int16 maxMapBlocks = _largeMapFlag ? 63 : 23; + + if (mapPosX == 0 && (mapPosY == 0 || mapPosY == maxMapBlocks)) + return true; + + if (mapPosX == maxMapBlocks && (mapPosY == 0 || mapPosY == maxMapBlocks)) + return true; + + return false; +} + +void EfhEngine::goSouth() { + if (_largeMapFlag) { + if (++_mapPosY > 63) + _mapPosY = 63; + } else { + if (++_mapPosY > 23) + _mapPosY = 23; + } + + if (isPosOutOfMap(_mapPosX, _mapPosY)) { + _mapPosX = _oldMapPosX; + _mapPosY = _oldMapPosY; + } +} + +void EfhEngine::goNorth() { + if (--_mapPosY < 0) + _mapPosY = 0; + + if (isPosOutOfMap(_mapPosX, _mapPosY)) { + _mapPosX = _oldMapPosX; + _mapPosY = _oldMapPosY; + } +} + +void EfhEngine::goEast() { + if (_largeMapFlag) { + if (++_mapPosX > 63) + _mapPosX = 63; + } else { + if (++_mapPosX > 23) + _mapPosX = 23; + } + + if (isPosOutOfMap(_mapPosX, _mapPosY)) { + _mapPosX = _oldMapPosX; + _mapPosY = _oldMapPosY; + } +} + +void EfhEngine::goWest() { + if (--_mapPosX < 0) + _mapPosX = 0; + + if (isPosOutOfMap(_mapPosX, _mapPosY)) { + _mapPosX = _oldMapPosX; + _mapPosY = _oldMapPosY; + } +} + +void EfhEngine::goNorthEast() { + if (--_mapPosY < 0) + _mapPosY = 0; + + if (_largeMapFlag) { + if (++_mapPosX > 63) + _mapPosX = 63; + } else { + if (++_mapPosX > 23) + _mapPosX = 23; + } + + if (isPosOutOfMap(_mapPosX, _mapPosY)) { + _mapPosX = _oldMapPosX; + _mapPosY = _oldMapPosY; + } +} + +void EfhEngine::goSouthEast() { + if (_largeMapFlag) { + if (++_mapPosX > 63) + _mapPosX = 63; + } else { + if (++_mapPosX > 23) + _mapPosX = 23; + } + + if (_largeMapFlag) { + if (++_mapPosY > 63) + _mapPosY = 63; + } else { + if (++_mapPosY > 23) + _mapPosY = 23; + } + + if (isPosOutOfMap(_mapPosX, _mapPosY)) { + _mapPosX = _oldMapPosX; + _mapPosY = _oldMapPosY; + } +} + +void EfhEngine::goNorthWest() { + if (--_mapPosY < 0) + _mapPosY = 0; + + if (--_mapPosX < 0) + _mapPosX = 0; + + if (isPosOutOfMap(_mapPosX, _mapPosY)) { + _mapPosX = _oldMapPosX; + _mapPosY = _oldMapPosY; + } +} + +void EfhEngine::goSouthWest() { + if (--_mapPosX < 0) + _mapPosX = 0; + + if (_largeMapFlag) { + if (++_mapPosY > 63) + _mapPosY = 63; + } else { + if (++_mapPosY > 23) + _mapPosY = 23; + } + + if (isPosOutOfMap(_mapPosX, _mapPosY)) { + _mapPosX = _oldMapPosX; + _mapPosY = _oldMapPosY; + } +} + +void EfhEngine::handleNewRoundEffects() { + warning("STUB: handleNewRoundEffects"); +} + +bool EfhEngine::handleDeathMenu() { + warning("STUB: handleDeathMenu"); + return false; +} + void EfhEngine::setNumLock() { // No implementation in ScummVM } -void EfhEngine::unkfct_mapFunction() { - warning("STUB - unkfct_mapFunction"); +void EfhEngine::computeMapAnimation() { + int16 maxMapBlocks = _largeMapFlag ? 63 : 23; + + int16 minMapX = _mapPosX - 5; + int16 minMapY = _mapPosY - 4; + + if (minMapX < 0) + minMapX = 0; + if (minMapY < 0) + minMapY = 0; + + int16 maxMapX = minMapX + 10; + int16 maxMapY = minMapY + 7; + + if (maxMapX > maxMapBlocks) + maxMapX = maxMapBlocks; + if (maxMapY > maxMapBlocks) + maxMapY = maxMapBlocks; + + for (int16 counterY = minMapY; counterY < maxMapY; ++counterY) { + for (int16 counterX = minMapX; counterX < maxMapX; ++counterX) { + if (_largeMapFlag) { + if (_currentTileBankImageSetId[0] != 0) + continue; + int16 var4 = _mapGameMapPtr[counterX * 64 + counterY]; + if (var4 >= 1 && var4 <= 0xF) { + if (getRandom(100) < 50) + _mapGameMapPtr[counterX * 64 + counterY] += 0xC5; + } else if (var4 >= 0xC6 && var4 <= 0xD5) { + if (getRandom(100) < 50) + _mapGameMapPtr[counterX * 64 + counterY] -= 0xC5; + } + } else { + if (_currentTileBankImageSetId[0] != 0) + continue; + int16 var4 = _curPlace[counterX * 24 + counterY]; + if (var4 >= 1 && var4 <= 0xF) { + if (getRandom(100) < 50) + _curPlace[counterX * 24 + counterY] += 0xC5; + } else if (var4 >= 0xC6 && var4 <= 0xD5) { + if (getRandom(100) < 50) + _curPlace[counterX * 24 + counterY] -= 0xC5; + } + } + } + } } void EfhEngine::unkFct_anim() { @@ -2062,7 +2376,7 @@ void EfhEngine::unkFct_anim() { displayAnimFrame(); } - unkfct_mapFunction(); + computeMapAnimation(); } void EfhEngine::setNextCharacterPos() { @@ -2086,6 +2400,15 @@ void EfhEngine::unkFct_displayMenuBox_2(int16 color) { drawColoredRect(16, 152, 302, 189, color); } +void EfhEngine::sub174A0() { + warning("STUB: sub174A0"); +} + +bool EfhEngine::sub16E14() { + warning("STUB: sub16E14"); + return false; +} + void EfhEngine::loadImageSetToTileBank(int16 tileBankId, int16 imageSetId) { // TODO: all the values of titleBankId and imageSetId are hardcoded. When all the calls are implemented, fix the values to avoid to have to decrease them int16 bankId = tileBankId - 1; diff --git a/engines/efh/efh.h b/engines/efh/efh.h index bea50bb78e33..dc6a642e2352 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -306,6 +306,7 @@ class EfhEngine : public Engine { void emptyFunction(int i); void refreshTeamSize(); bool isCharacterATeamMember(int16 id); + bool isTPK(); void handleWinSequence(); bool giveItemTo(int16 charId, int16 objectId, int altCharId); void sub26437(char * str, int16 startX, int16 startY, uint16 unkFl); @@ -329,13 +330,26 @@ class EfhEngine : public Engine { void setTextColorWhite(); void setTextColorRed(); void setTextColor_08h(); + bool isPosOutOfMap(int16 mapPosX, int16 mapPosY); + void goSouth(); + void goNorth(); + void goEast(); + void goWest(); + void goNorthEast(); + void goSouthEast(); + void goNorthWest(); + void goSouthWest(); + void handleNewRoundEffects(); + bool handleDeathMenu(); void setNumLock(); - void unkfct_mapFunction(); + void computeMapAnimation(); void unkFct_anim(); void setNextCharacterPos(); void unkFct_displayString_2(char *message); void unkFct_displayMenuBox_2(int16 color); + void sub174A0(); + bool sub16E14(); uint8 _videoMode; uint8 _bufferCharBM[128]; @@ -407,15 +421,16 @@ class EfhEngine : public Engine { int16 _unkArray2C8AA[3]; int16 _teamSize; int16 _word2C872; - int16 _word2C880; - int16 _word2C894; - int16 _word2C8D7; + bool _word2C880; + bool _word2C894; + bool _word2C8D7; bool _word2C876; bool _word2C878; bool _word2C87A; int16 _unk_sub26437_flag; int16 _imageSetSubFilesIdx; + int16 _oldImageSetSubFilesIdx; int16 _mapPosX, _mapPosY; int16 _oldMapPosX, _oldMapPosY; @@ -424,7 +439,8 @@ class EfhEngine : public Engine { uint16 _word2C86E; uint8 *_dword2C856; - int16 _word2C8D9; + bool _word2C8D9; + bool _word2C8D5; // CHECKME: always 0? }; } // End of namespace Efh From 8874d2f9264910d50fe768fdf518964cb42ef8b6 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Fri, 3 Dec 2021 08:15:46 +0100 Subject: [PATCH 073/412] EFH: Fix event handler, some renaming --- engines/efh/efh.cpp | 36 +++++++++++++----------------------- engines/efh/efh.h | 6 +++--- 2 files changed, 16 insertions(+), 26 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 8041fa5a4253..bd00f95459c9 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -247,7 +247,7 @@ EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst) _teamSize = 1; _word2C872 = 0; _imageSetSubFilesIdx = 144; - _oldImageSetSubFilesIdx = 144; + _oldImageSetSubFilesIdx = 143; _mapPosX = _mapPosY = 31; _oldMapPosX = _oldMapPosY = 31; @@ -353,12 +353,7 @@ Common::Error EfhEngine::run() { } Common::Event event; - _system->getEventManager()->pollEvent(event); - Common::KeyCode retVal = Common::KEYCODE_INVALID; - Common::KeyCode lastInput = getLastCharAfterAnimCount(4); - if (event.type == Common::EVENT_KEYUP) { - retVal = lastInput; - } + Common::KeyCode retVal = getLastCharAfterAnimCount(4); switch (retVal) { case Common::KEYCODE_DOWN: @@ -809,13 +804,8 @@ Common::KeyCode EfhEngine::getLastCharAfterAnimCount(int16 delay) { if (delay == 0) return Common::KEYCODE_INVALID; - Common::Event event; - do { - _system->getEventManager()->pollEvent(event); - } while (event.kbd.keycode != Common::KEYCODE_INVALID); - Common::KeyCode lastChar = Common::KEYCODE_INVALID; - + uint32 lastMs = _system->getMillis(); while (delay > 0 && lastChar == Common::KEYCODE_INVALID) { _system->delayMillis(20); @@ -1327,7 +1317,7 @@ void EfhEngine::displayLowStatusScreen(bool flag) { int16 textPosY = 161 + 9 * i; copyString(_npcBuf[charId]._name, buffer); setTextPos(16, textPosY); - unkFct_displayString_2(buffer); + displayStringAtTextPos(buffer); sprintf(buffer, "%d", getEquipmentDefense(charId, false)); displayCenteredString(buffer, 104, 128, textPosY); sprintf(buffer, "%d", _npcBuf[charId]._hitPoints); @@ -1521,7 +1511,7 @@ bool EfhEngine::giveItemTo(int16 charId, int16 objectId, int altCharId) { return false; } -void EfhEngine::sub26437(char *str, int16 startX, int16 startY, uint16 unkFl) { +void EfhEngine::drawString(char *str, int16 startX, int16 startY, uint16 unkFl) { uint8 *curPtr = (uint8 *)str; uint16 lineHeight = _fontDescr._charHeight + _fontDescr._extraVerticalSpace; _unk_sub26437_flag = unkFl & 0x3FFF; @@ -1530,7 +1520,7 @@ void EfhEngine::sub26437(char *str, int16 startX, int16 startY, uint16 unkFl) { int16 var6 = _fontDescr._extraLines[0] + startY - 1; // Used in case 0x8000 if (unkFl & 0x8000) { - warning("STUB - sub26437 - 0x8000"); + warning("STUB - drawString - 0x8000"); } for (uint8 curChar = *curPtr++; curChar != 0; curChar = *curPtr++) { @@ -1552,7 +1542,7 @@ void EfhEngine::sub26437(char *str, int16 startX, int16 startY, uint16 unkFl) { } uint8 varC = _fontDescr._extraLines[characterId]; - sub252CE(curChar, startX, startY + varC); + drawChar(curChar, startX, startY + varC); startX += charWidth + _fontDescr._extraHorizontalSpace; } @@ -1561,7 +1551,7 @@ void EfhEngine::sub26437(char *str, int16 startX, int16 startY, uint16 unkFl) { void EfhEngine::displayCenteredString(char *str, int16 minX, int16 maxX, int16 posY) { uint16 length = getStringWidth(str); int16 startCenteredDisplayX = minX + (maxX - minX - length) / 2; - sub26437(str, startCenteredDisplayX, posY, _textColor); + drawString(str, startCenteredDisplayX, posY, _textColor); } int16 EfhEngine::chooseCharacterToReplace() { @@ -1654,7 +1644,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, doneFlag = true; } else { if (var_F2 == 0) - unkFct_displayString_2(dest); + displayStringAtTextPos(dest); *dest = 0; strcpy(dest, var_EC); @@ -2034,7 +2024,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, } if (*dest != 0 && curLine < numbLines && var_F2 == 0) - unkFct_displayString_2(dest); + displayStringAtTextPos(dest); if (var_EE != 0xFF) { displayLowStatusScreen(true); @@ -2131,7 +2121,7 @@ int16 EfhEngine::sub151FD(int16 posX, int16 posY) { return -1; } -void EfhEngine::sub252CE(uint8 curChar, int16 posX, int posY) { +void EfhEngine::drawChar(uint8 curChar, int16 posX, int posY) { // Quick hacked display, may require rework uint8 *destPtr = (uint8 *)_mainSurface->getBasePtr(posX, posY); @@ -2390,8 +2380,8 @@ void EfhEngine::setNextCharacterPos() { _textPosY = 0; } -void EfhEngine::unkFct_displayString_2(char *message) { - sub26437(message, _textPosX, _textPosY, _textColor); +void EfhEngine::displayStringAtTextPos(char *message) { + drawString(message, _textPosX, _textPosY, _textColor); _textPosX += getStringWidth(message) + 1; setNextCharacterPos(); } diff --git a/engines/efh/efh.h b/engines/efh/efh.h index dc6a642e2352..e77afa9c6c73 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -309,7 +309,7 @@ class EfhEngine : public Engine { bool isTPK(); void handleWinSequence(); bool giveItemTo(int16 charId, int16 objectId, int altCharId); - void sub26437(char * str, int16 startX, int16 startY, uint16 unkFl); + void drawString(char * str, int16 startX, int16 startY, uint16 unkFl); void displayCenteredString(char * str, int16 minX, int16 maxX, int16 posY); int16 chooseCharacterToReplace(); int16 handleCharacterJoining(); @@ -326,7 +326,7 @@ class EfhEngine : public Engine { void sub2455E(int16 arg0, int16 arg1, int16 arg2); int16 sub1C219(const char *str, int menuType, int arg4, int displayTeamWindowFl); int16 sub151FD(int16 posX, int16 posY); - void sub252CE(uint8 curChar, int16 posX, int posY); + void drawChar(uint8 curChar, int16 posX, int posY); void setTextColorWhite(); void setTextColorRed(); void setTextColor_08h(); @@ -346,7 +346,7 @@ class EfhEngine : public Engine { void computeMapAnimation(); void unkFct_anim(); void setNextCharacterPos(); - void unkFct_displayString_2(char *message); + void displayStringAtTextPos(char *message); void unkFct_displayMenuBox_2(int16 color); void sub174A0(); bool sub16E14(); From f20fd2d935b965323222528ea6ccf04480e908e9 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Fri, 3 Dec 2021 08:53:31 +0100 Subject: [PATCH 074/412] EFH: Some more renaming --- engines/efh/efh.cpp | 32 +++++++++++--------------------- engines/efh/efh.h | 8 ++++---- 2 files changed, 15 insertions(+), 25 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index bd00f95459c9..b167354bb14f 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -190,7 +190,7 @@ EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst) _fontDescr._charHeight = 0; _fontDescr._extraHorizontalSpace = _fontDescr._extraVerticalSpace = 0; - _word31E9E = 0; + _word31E9E = false; _oldAnimImageSetId = -1; _animImageSetId = 254; _paletteTransformationConstant = 10; @@ -262,8 +262,8 @@ EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst) _word2C880 = false; _word2C894 = false; _word2C8D7 = true; - _word2C876 = true; - _word2C878 = true; + _drawHeroOnMapFl = true; + _drawMonstersOnMapFl = true; _word2C87A = false; _unk_sub26437_flag = 0; _word2C8D9 = false; @@ -500,7 +500,7 @@ void EfhEngine::readAnimInfo() { } void EfhEngine::findMapFile(int16 mapId) { - if (_word31E9E == 0) + if (!_word31E9E) return; Common::String fileName = Common::String::format("map.%d", mapId); @@ -974,20 +974,10 @@ void EfhEngine::initEngine() { _fontDescr._charHeight = 8; _fontDescr._extraVerticalSpace = 3; _fontDescr._extraHorizontalSpace = 1; - _word31E9E = 0; + _word31E9E = false; saveAnimImageSetId(); - // Save int 1C - // Set new int 1C: - // TODO: Implement that in the main loop - // static uint8 counter = 0; - // ++counter; - // if (counter == 4) { - // counter = 0; - // tick220Fl = 1; - // } - // Load Title Screen loadImageSet(11, _circleImageBuf, _circleImageSubFileArray, _hiResImageBuf); displayFctFullScreen(); @@ -1031,7 +1021,7 @@ void EfhEngine::initEngine() { loadImageSet(6, _circleImageBuf, _circleImageSubFileArray, _hiResImageBuf); readImpFile(99, false); - _word31E9E = 0xFFFF; + _word31E9E = true; restoreAnimImageSetId(); // Note: The original at this point saves int 24h and sets a new int24 to handle fatal failure @@ -1166,7 +1156,7 @@ void EfhEngine::sub15150(bool flag) { } } -void EfhEngine::drawMap(bool largeMapFl, int16 mapPosX, int16 mapPosY, int mapSize, bool unkFl1, bool unkFl2) { +void EfhEngine::drawMap(bool largeMapFl, int16 mapPosX, int16 mapPosY, int mapSize, bool drawHeroFl, bool drawMonstersFl) { int16 unkPosX = 5; int16 unkPosY = 4; int16 posX = 0; @@ -1216,13 +1206,13 @@ void EfhEngine::drawMap(bool largeMapFl, int16 mapPosX, int16 mapPosY, int mapSi var10 += 16; } - if (unkFl1) { + if (drawHeroFl) { int16 var12 = 128 + unkPosX * 16; var10 = 8 + unkPosY * 16; displayRawDataAtPos(_imageSetSubFilesArray[_imageSetSubFilesIdx], var12, var10); } - if (unkFl2) { + if (drawMonstersFl) { for (int16 var16 = 0; var16 < 64; ++var16) { if ((_largeMapFlag && _mapMonsters[var16]._guess_fullPlaceId == 0xFE) || (!_largeMapFlag && _mapMonsters[var16]._guess_fullPlaceId == _fullPlaceId)){ bool var4 = false; @@ -1260,11 +1250,11 @@ void EfhEngine::drawMap(bool largeMapFl, int16 mapPosX, int16 mapPosY, int mapSi } void EfhEngine::displaySmallMap(int16 posX, int16 posY) { - drawMap(false, posX, posY, 23, _word2C876, _word2C878); + drawMap(false, posX, posY, 23, _drawHeroOnMapFl, _drawMonstersOnMapFl); } void EfhEngine::displayLargeMap(int16 posX, int16 posY) { - drawMap(true, posX, posY, 63, _word2C876, _word2C878); + drawMap(true, posX, posY, 63, _drawHeroOnMapFl, _drawMonstersOnMapFl); } void EfhEngine::sub12A7F() { diff --git a/engines/efh/efh.h b/engines/efh/efh.h index e77afa9c6c73..51075a4f936c 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -291,7 +291,7 @@ class EfhEngine : public Engine { void setTextPos(int16 textPosX, int16 textPosY); void sub15150(bool flag); - void drawMap(bool largeMapFl, int16 mapPosX, int16 mapPosY, int mapSize, bool unkFl1, bool unkFl2); + void drawMap(bool largeMapFl, int16 mapPosX, int16 mapPosY, int mapSize, bool drawHeroFl, bool drawMonstersFl); void displaySmallMap(int16 posX, int16 posY); void displayLargeMap(int16 posX, int16 posY); void sub12A7F(); @@ -389,7 +389,7 @@ class EfhEngine : public Engine { uint8 _defaultBoxColor; FontDescr _fontDescr; - uint16 _word31E9E; + bool _word31E9E; uint16 _textColor; int16 _oldAnimImageSetId; @@ -424,8 +424,8 @@ class EfhEngine : public Engine { bool _word2C880; bool _word2C894; bool _word2C8D7; - bool _word2C876; - bool _word2C878; + bool _drawHeroOnMapFl; + bool _drawMonstersOnMapFl; bool _word2C87A; int16 _unk_sub26437_flag; From 2e2803591f28f75218f039129aa987f53a4ba1bc Mon Sep 17 00:00:00 2001 From: Strangerke Date: Fri, 3 Dec 2021 09:11:27 +0100 Subject: [PATCH 075/412] EFH: Fix map initialization (loading savegame) --- engines/efh/efh.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index b167354bb14f..7679cfdb3469 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -2448,9 +2448,7 @@ void EfhEngine::loadGame() { _teamSize = f.readSint16LE(); - for (int i = 0; i < 3; ++i) { - _unkArray2C8AA[i] = f.readSint16LE(); - } + _unkArray2C8AA[0] = f.readSint16LE(); _word2C872 = f.readSint16LE(); From 28bf1807e7f81ced20b8d888a128126a79f5d3c4 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sat, 4 Dec 2021 00:38:38 +0100 Subject: [PATCH 076/412] EFH: Start implementing interactions with monsters --- engines/efh/efh.cpp | 165 +++++++++++++++++++++++++++++++++++++++++++- engines/efh/efh.h | 8 +++ 2 files changed, 171 insertions(+), 2 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 7679cfdb3469..4a5942116d8e 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -2384,11 +2384,172 @@ void EfhEngine::sub174A0() { warning("STUB: sub174A0"); } -bool EfhEngine::sub16E14() { - warning("STUB: sub16E14"); +bool EfhEngine::checkPictureRefAvailability(int16 monsterId) { + if (_mapMonsters[monsterId]._guess_fullPlaceId == 0xFF) + return false; + + for (int16 counter = 0; counter < 9; ++counter) { + if (_mapMonsters[monsterId]._pictureRef[counter] > 0) + return true; + } + + return false; +} + +bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 arg4) { + warning("STUB - sub21820"); return false; } +void EfhEngine::sub221D2(int16 monsterId) { + if (monsterId != -1) { + _dword2C856 = nullptr; + sub21820(monsterId, 5, -1); + } +} + +int16 EfhEngine::sub15581(int16 mapPosX, int16 mapPosY, int16 arg4) { + warning("STUB - sub15581"); + return 0; +} + +bool EfhEngine::handleFight() { + warning("STUB - handleFight"); + return false; +} + +int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { + warning("STUB - handleStatusMenu"); + return 0; +} + +Common::KeyCode EfhEngine::waitForKey() { + warning("STUB - waitForKey"); + return Common::KEYCODE_INVALID; +} + +Common::KeyCode EfhEngine::mapInputCode(Common::KeyCode input) { + warning("STUB - mapInputCode"); + return Common::KEYCODE_INVALID; +} + +bool EfhEngine::sub16E14() { + int16 var68 = 0; + char dest[20]; + char buffer[80]; + + int16 monsterId; + for (monsterId = 0; monsterId < 64; ++monsterId) { + if (!checkPictureRefAvailability(monsterId)) + continue; + + if (!(_largeMapFlag && _mapMonsters[monsterId]._guess_fullPlaceId == 0xFE) && !(!_largeMapFlag && _mapMonsters[monsterId]._guess_fullPlaceId == _fullPlaceId)) + continue; + + if ((_mapMonsters[monsterId]._field_1 & 0x3F) > 0x3D + && (((_mapMonsters[monsterId]._possessivePronounSHL6 & 0x3F) == 0x3F) || isCharacterATeamMember(_mapMonsters[monsterId]._field_1))) + continue; + + if (_mapMonsters[monsterId]._posX != _mapPosX || _mapMonsters[monsterId]._posY != _mapPosY) + continue; + + if (_word2C8D7 == 0) + return false; + + _mapPosX = _oldMapPosX; + _mapPosY = _oldMapPosY; + if (_imageSetSubFilesIdx != _oldImageSetSubFilesIdx) + _oldImageSetSubFilesIdx = _imageSetSubFilesIdx; + _word2C894 = true; + + int16 var6A = 0; + for (int16 var6C = 0; var6C < 9; ++var6C) { + if (_mapMonsters[monsterId]._pictureRef[var6C]) + ++var6A; + } + + do { + for (int16 var6C = 0; var6C < 2; ++var6C) { + int16 var1 = _mapMonsters[monsterId]._possessivePronounSHL6 & 0x3F; + if (var1 <= 0x3D) { + strcpy(dest, kEncounters[_mapMonsters[monsterId]._MonsterRef]._name); + if (var6A > 1) + strcat(dest, " "); + + sprintf(buffer, "with %d %s", var6A, dest); + } else if (var1 == 0x3E) { + strcpy(buffer, "(NOT DEFINED)"); + } else if (var1 == 0x3F) { // Useless if, it's the last possible value + copyString(_npcBuf[_mapMonsters[monsterId]._MonsterRef]._name, dest); + sprintf(buffer, "with %s", dest); + } + + unkFct_displayMenuBox_2(0); + _textColor = 0xE; + displayCenteredString((char *)"Interaction", 24, 296, 152); + displayCenteredString(buffer, 24, 296, 161); + setTextPos(24, 169); + setTextColorWhite(); + displayStringAtTextPos((char *)"T"); + setTextColorRed(); + sprintf(buffer, "alk to the %s", dest); + displayStringAtTextPos(buffer); + setTextPos(24, 178); + setTextColorWhite(); + displayStringAtTextPos((char *)"A"); + setTextColorRed(); + sprintf(buffer, "ttack the %s", dest); + displayStringAtTextPos(buffer); + setTextPos(198, 169); + setTextColorWhite(); + displayStringAtTextPos((char *)"S"); + setTextColorRed(); + displayStringAtTextPos((char *)"tatus"); + setTextPos(198, 178); + setTextColorWhite(); + displayStringAtTextPos((char *)"L"); + setTextColorRed(); + displayStringAtTextPos((char *)"eave"); + if (var6C == 0) + displayFctFullScreen(); + } + + Common::KeyCode input = mapInputCode(waitForKey()); + + switch (input) { + case Common::KEYCODE_a: // Attack + var6A = handleFight(); + var68 = true; + break; + case Common::KEYCODE_ESCAPE: + case Common::KEYCODE_l: // Leave + var68 = true; + break; + case Common::KEYCODE_s: // Status + var6A = handleStatusMenu(1, _teamCharId[0]); + var68 = true; + _dword2C856 = nullptr; + sub15150(true); + break; + case Common::KEYCODE_t: // Talk + sub221D2(monsterId); + var68 = true; + break; + default: + warning("STUB: sub16E14 - Missing mapping ?"); + break; + } + } while (!var68); + return true; + } + + monsterId = sub15581(_mapPosX, _mapPosY, 1); + if (monsterId == 0 || monsterId == 2) + return false; + + return true; +} + void EfhEngine::loadImageSetToTileBank(int16 tileBankId, int16 imageSetId) { // TODO: all the values of titleBankId and imageSetId are hardcoded. When all the calls are implemented, fix the values to avoid to have to decrease them int16 bankId = tileBankId - 1; diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 51075a4f936c..e9ba0830b8d8 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -349,6 +349,14 @@ class EfhEngine : public Engine { void displayStringAtTextPos(char *message); void unkFct_displayMenuBox_2(int16 color); void sub174A0(); + bool checkPictureRefAvailability(int16 monsterId); + bool sub21820(int16 monsterId, int16 arg2, int16 arg4); + void sub221D2(int16 monsterId); + int16 sub15581(int16 mapPosX, int16 mapPosY, int16 arg4); + bool handleFight(); + int16 handleStatusMenu(int16 gameMode, int16 charId); + Common::KeyCode waitForKey(); + Common::KeyCode mapInputCode(Common::KeyCode input); bool sub16E14(); uint8 _videoMode; From e70972c1707977762686885e6a993d740d4dbcdf Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sat, 4 Dec 2021 21:37:11 +0100 Subject: [PATCH 077/412] EFH: Implement sub174A0 --- engines/efh/efh.cpp | 388 +++++++++++++++++++++++++++++++++++++++++++- engines/efh/efh.h | 15 +- 2 files changed, 398 insertions(+), 5 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 4a5942116d8e..ae9d5de5305c 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -243,6 +243,9 @@ EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst) _unkArray2C8AA[i] = 0; } + for (int i = 0; i < 5; ++i) + _teamMonsterIdArray[i] = -1; + _unkArray2C8AA[2] = 1; _teamSize = 1; _word2C872 = 0; @@ -268,6 +271,7 @@ EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst) _unk_sub26437_flag = 0; _word2C8D9 = false; _word2C8D5 = false; + _word2D0BC = false; memset(_messageToBePrinted, 0, 400); } @@ -2380,8 +2384,384 @@ void EfhEngine::unkFct_displayMenuBox_2(int16 color) { drawColoredRect(16, 152, 302, 189, color); } +int16 EfhEngine::sub16B08(int16 monsterId) { + // Simplified version compared to the original + int16 maxSize = _largeMapFlag ? 63 : 23; + if (_mapMonsters[monsterId]._posX < 0 || _mapMonsters[monsterId]._posY < 0 || _mapMonsters[monsterId]._posX > maxSize || _mapMonsters[monsterId]._posY > maxSize) + return 0; + + if (_mapMonsters[monsterId]._posX == _mapPosX && _mapMonsters[monsterId]._posY == _mapPosY) + return 0; + + for (int16 counter = 0; counter < 64; ++counter) { + if (counter == monsterId) + continue; + + if (!checkPictureRefAvailability(counter)) + continue; + + if (_mapMonsters[monsterId]._guess_fullPlaceId == _mapMonsters[counter]._guess_fullPlaceId + && _mapMonsters[monsterId]._posX == _mapMonsters[counter]._posX + && _mapMonsters[monsterId]._posY == _mapMonsters[counter]._posY) + return 0; + } + + return sub15581(_mapMonsters[monsterId]._posX, _mapMonsters[monsterId]._posY, 0); +} + +bool EfhEngine::moveMonsterGroupTowardsGroup_0(int16 monsterId) { + if (_mapMonsters[monsterId]._posX < _mapPosX) { + --_mapMonsters[monsterId]._posX; + if (_mapMonsters[monsterId]._posY < _mapPosY) + --_mapMonsters[monsterId]._posY; + else if (_mapMonsters[monsterId]._posY > _mapPosY) + ++_mapMonsters[monsterId]._posY; + + return true; + } + + if (_mapMonsters[monsterId]._posX > _mapPosX) { + ++_mapMonsters[monsterId]._posX; + if (_mapMonsters[monsterId]._posY < _mapPosY) + --_mapMonsters[monsterId]._posY; + else if (_mapMonsters[monsterId]._posY > _mapPosY) + ++_mapMonsters[monsterId]._posY; + + return true; + } + + // Original checks for posX equality, which is the only possible option at this point => skipped + if (_mapMonsters[monsterId]._posY < _mapPosY) + --_mapMonsters[monsterId]._posY; + else if (_mapMonsters[monsterId]._posY > _mapPosY) + ++_mapMonsters[monsterId]._posY; + else + return false; + + return true; +} + +bool EfhEngine::moveMonsterGroupTowardsGroup_1(int16 monsterId) { + if (_mapMonsters[monsterId]._posX < _mapPosX) { + ++_mapMonsters[monsterId]._posX; + if (_mapMonsters[monsterId]._posY < _mapPosY) + ++_mapMonsters[monsterId]._posY; + else if (_mapMonsters[monsterId]._posY > _mapPosY) + --_mapMonsters[monsterId]._posY; + + return true; + } + + if (_mapMonsters[monsterId]._posX > _mapPosX) { + --_mapMonsters[monsterId]._posX; + if (_mapMonsters[monsterId]._posY < _mapPosY) + ++_mapMonsters[monsterId]._posY; + else if (_mapMonsters[monsterId]._posY > _mapPosY) + --_mapMonsters[monsterId]._posY; + + return true; + } + + // Original checks for posX equality, which is the only possible option at this point => skipped + if (_mapMonsters[monsterId]._posY < _mapPosY) + ++_mapMonsters[monsterId]._posY; + else if (_mapMonsters[monsterId]._posY > _mapPosY) + --_mapMonsters[monsterId]._posY; + else + return false; + + return true; +} + +bool EfhEngine::moveMonsterGroupOther(int16 monsterId, int16 direction) { + + switch (direction - 1) { + case 0: + --_mapMonsters[monsterId]._posY; + return true; + case 1: + --_mapMonsters[monsterId]._posY; + ++_mapMonsters[monsterId]._posX; + return true; + case 2: + ++_mapMonsters[monsterId]._posX; + return true; + case 3: + ++_mapMonsters[monsterId]._posX; + ++_mapMonsters[monsterId]._posY; + return true; + case 4: + ++_mapMonsters[monsterId]._posY; + return true; + case 5: + ++_mapMonsters[monsterId]._posY; + --_mapMonsters[monsterId]._posX; + return true; + case 6: + --_mapMonsters[monsterId]._posX; + return true; + case 7: + --_mapMonsters[monsterId]._posX; + --_mapMonsters[monsterId]._posY; + return true; + default: + return false; + } +} + +bool EfhEngine::moveMonsterGroup(int16 monsterId) { + int16 rand100 = getRandom(100); + + if (rand100 < 30) + return moveMonsterGroupTowardsGroup_1(monsterId); + + if (rand100 >= 60) + // CHECKME: the original seems to only use 1 param?? + return moveMonsterGroupOther(monsterId, getRandom(8)); + + return moveMonsterGroupTowardsGroup_0(monsterId); +} + +int16 EfhEngine::computeMonsterGroupDistance(int monsterId) { + int16 monsterPosX = _mapMonsters[monsterId]._posX; + int16 monsterPosY = _mapMonsters[monsterId]._posY; + + int16 deltaX = monsterPosX - _mapPosX; + int16 deltaY = monsterPosY - _mapPosY; + + return (int16)sqrt(deltaX * deltaX + deltaY * deltaY); +} + +bool EfhEngine::checkWeaponRange(int16 monsterId, int weaponId) { + static const int16 kRange[5] = {1, 2, 3, 3, 3}; + + assert(_items[weaponId]._range < 5); + if (computeMonsterGroupDistance(monsterId) > kRange[_items[weaponId]._range]) + return false; + + return true; +} + +bool EfhEngine::unkFct_checkMonsterField8(int id, bool teamFlag) { + int16 monsterId = id; + if (teamFlag) + monsterId = _teamMonsterIdArray[id]; + + if ((_mapMonsters[monsterId]._field_8 & 0xF) >= 8) + return true; + + if (_unkArray2C8AA[0] == 0) + return false; + + if ((_mapMonsters[monsterId]._field_8 & 0x80) != 0) + return true; + + return false; +} + +bool EfhEngine::checkTeamWeaponRange(int16 monsterId) { + if (!_word2D0BC) + return true; + + for (int16 counter = 0; counter < 5; ++counter) { + if (_teamMonsterIdArray[counter] == monsterId && unkFct_checkMonsterField8(monsterId, false) && checkWeaponRange(monsterId, _mapMonsters[monsterId]._itemId_Weapon)) + return false; + } + + return true; +} + +bool EfhEngine::checkIfMonsterOnSameLargelMapPlace(int16 monsterId) { + if (_largeMapFlag && _mapMonsters[monsterId]._guess_fullPlaceId == 0xFE) + return true; + + if (!_largeMapFlag && _mapMonsters[monsterId]._guess_fullPlaceId == _fullPlaceId) + return true; + + return false; +} + +bool EfhEngine::checkMonsterWeaponRange(int16 monsterId) { + return checkWeaponRange(monsterId, _mapMonsters[monsterId]._itemId_Weapon); +} + void EfhEngine::sub174A0() { - warning("STUB: sub174A0"); + static int16 sub174A0_monsterPosX = -1; + static int16 sub174A0_monsterPosY = -1; + + int16 var14 = 0; + int16 var6 = 0; + _word2C894 = false; + int16 unkMonsterId = -1; + int16 mapSize = _largeMapFlag ? 63 : 23; + int16 minDisplayedMapX = CLIP(_mapPosX - 10, 0, mapSize); + int16 minDisplayedMapY = CLIP(_mapPosY - 9, 0, mapSize); + int16 maxDisplayedMapX = CLIP(minDisplayedMapX + 20, 0, mapSize); + int16 maxDisplayedMapY = CLIP(minDisplayedMapY + 17, 0, mapSize); + + for (int16 monsterId = 0; monsterId < 64; ++monsterId) { + if (!checkPictureRefAvailability(monsterId)) + continue; + + if (!checkTeamWeaponRange(monsterId)) + continue; + + if (!checkIfMonsterOnSameLargelMapPlace(monsterId)) + continue; + + int16 var4 = _mapMonsters[monsterId]._posX; + int16 var2 = _mapMonsters[monsterId]._posY; + + if (var4 < minDisplayedMapX || var4 > maxDisplayedMapX || var2 < minDisplayedMapY || var2 > maxDisplayedMapY) + continue; + + int16 var1A = 0; + var14 = 0; + + sub174A0_monsterPosX = _mapMonsters[monsterId]._posX; + sub174A0_monsterPosY = _mapMonsters[monsterId]._posY; + int8 var1C = _mapMonsters[monsterId]._field_8 & 0xF; + + if (_unkArray2C8AA[0] != 0 && (_mapMonsters[monsterId]._field_8 & 0x80)) + var1C = 9; + + int16 var1E = _mapMonsters[monsterId]._field_8 & 0x70; + var1E >>= 4; + + int16 var16 = var1E; + do { + switch (var1C - 1) { + case 0: + if (getRandom(100) >= 0xE - var1E) + var1A = moveMonsterGroupTowardsGroup_1(monsterId); + else + var1A = moveMonsterGroup(monsterId); + break; + case 1: + if (getRandom(100) >= 0xE - var1E) + var1A = moveMonsterGroupTowardsGroup_0(monsterId); + else + var1A = moveMonsterGroup(monsterId); + break; + case 2: + var1A = moveMonsterGroupOther(monsterId, getRandom(8)); + break; + case 3: + var1A = moveMonsterGroup(monsterId); + break; + case 4: + if (getRandom(100) > 0x32 - var1E) + var1A = moveMonsterGroupTowardsGroup_1(monsterId); + else + var1A = moveMonsterGroup(monsterId); + break; + case 5: + if (getRandom(100) > 0x32 - var1E) + var1A = moveMonsterGroupTowardsGroup_0(monsterId); + else + var1A = moveMonsterGroup(monsterId); + break; + case 6: + if (getRandom(100) >= 0x32 - var1E) + var1A = moveMonsterGroup(monsterId); + break; + case 7: + // var14 is not a typo. + var14 = checkMonsterWeaponRange(monsterId); + break; + case 8: + var14 = checkMonsterWeaponRange(monsterId); + if (var14 == 0) { + if (getRandom(100) >= 0xE - var1E) + var1A = moveMonsterGroupTowardsGroup_1(monsterId); + else + var1A = moveMonsterGroup(monsterId); + } + break; + case 9: + var14 = checkMonsterWeaponRange(monsterId); + if (var14 == 0) { + if (getRandom(100) >= 0xE - var1E) + var1A = moveMonsterGroupTowardsGroup_0(monsterId); + else + var1A = moveMonsterGroup(monsterId); + } + break; + case 10: + var14 = checkMonsterWeaponRange(monsterId); + if (var14 == 0) { + var1A = moveMonsterGroupOther(monsterId, getRandom(8)); + } + break; + case 11: + var14 = checkMonsterWeaponRange(monsterId); + if (var14 == 0) { + var1A = moveMonsterGroup(monsterId); + } + break; + case 12: + var14 = checkMonsterWeaponRange(monsterId); + if (var14 == 0) { + if (getRandom(100) >= 0x32 - var1E) + var1A = moveMonsterGroupTowardsGroup_1(monsterId); + else + var1A = moveMonsterGroup(monsterId); + } + break; + case 13: + var14 = checkMonsterWeaponRange(monsterId); + if (var14 == 0) { + if (getRandom(100) >= 0x32 - var1E) + var1A = moveMonsterGroupTowardsGroup_0(monsterId); + else + var1A = moveMonsterGroup(monsterId); + } + break; + case 14: + var14 = checkMonsterWeaponRange(monsterId); + if (var14 == 0 && getRandom(100) >= 0x32 - var1E) + var1A = moveMonsterGroup(monsterId); + break; + default: + break; + } + + for (;;) { + if (var1A == 0) { + if (var14 == 0) { + var1A = -1; + } else { + unkMonsterId = monsterId; + var1A = -1; + } + } else { + int16 var18 = sub16B08(monsterId); + + if (var18 == 0) { + _mapMonsters[monsterId]._posX = sub174A0_monsterPosX; + _mapMonsters[monsterId]._posY = sub174A0_monsterPosY; + var1A = 0; + --var16; + } else if (var18 == 2) { + _mapMonsters[monsterId]._posX = sub174A0_monsterPosX; + _mapMonsters[monsterId]._posY = sub174A0_monsterPosY; + } + } + + if (var1A == 0 && var16 == 1 && var1E > 1) { + var1A = moveMonsterGroupOther(monsterId, getRandom(8)); + continue; + } + + break; + } + + } while (var1A == 0 && var16 > 0); + + } + + if (unkMonsterId != -1) + handleFight(unkMonsterId); } bool EfhEngine::checkPictureRefAvailability(int16 monsterId) { @@ -2413,7 +2793,7 @@ int16 EfhEngine::sub15581(int16 mapPosX, int16 mapPosY, int16 arg4) { return 0; } -bool EfhEngine::handleFight() { +bool EfhEngine::handleFight(int16 monsterId) { warning("STUB - handleFight"); return false; } @@ -2453,7 +2833,7 @@ bool EfhEngine::sub16E14() { if (_mapMonsters[monsterId]._posX != _mapPosX || _mapMonsters[monsterId]._posY != _mapPosY) continue; - if (_word2C8D7 == 0) + if (!_word2C8D7) return false; _mapPosX = _oldMapPosX; @@ -2518,7 +2898,7 @@ bool EfhEngine::sub16E14() { switch (input) { case Common::KEYCODE_a: // Attack - var6A = handleFight(); + var6A = handleFight(monsterId); var68 = true; break; case Common::KEYCODE_ESCAPE: diff --git a/engines/efh/efh.h b/engines/efh/efh.h index e9ba0830b8d8..b8a324343cfc 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -348,12 +348,23 @@ class EfhEngine : public Engine { void setNextCharacterPos(); void displayStringAtTextPos(char *message); void unkFct_displayMenuBox_2(int16 color); + int16 sub16B08(int16 monsterId); + bool moveMonsterGroupTowardsGroup_0(int16 monsterId); + bool moveMonsterGroupTowardsGroup_1(int16 monsterId); + bool moveMonsterGroupOther(int16 monsterId, int16 direction); + bool moveMonsterGroup(int16 monsterId); + int16 computeMonsterGroupDistance(int monsterId); + bool checkWeaponRange(int16 monsterId, int weaponId); + bool unkFct_checkMonsterField8(int id, bool teamFlag); + bool checkTeamWeaponRange(int16 monsterId); + bool checkIfMonsterOnSameLargelMapPlace(int16 monsterId); + bool checkMonsterWeaponRange(int16 monsterId); void sub174A0(); bool checkPictureRefAvailability(int16 monsterId); bool sub21820(int16 monsterId, int16 arg2, int16 arg4); void sub221D2(int16 monsterId); int16 sub15581(int16 mapPosX, int16 mapPosY, int16 arg4); - bool handleFight(); + bool handleFight(int16 monsterId); int16 handleStatusMenu(int16 gameMode, int16 charId); Common::KeyCode waitForKey(); Common::KeyCode mapInputCode(Common::KeyCode input); @@ -425,6 +436,7 @@ class EfhEngine : public Engine { bool _engineInitPending; bool _protectionPassed; + int16 _teamMonsterIdArray[5]; CharStatus _teamCharStatus[3]; int16 _unkArray2C8AA[3]; int16 _teamSize; @@ -449,6 +461,7 @@ class EfhEngine : public Engine { uint8 *_dword2C856; bool _word2C8D9; bool _word2C8D5; // CHECKME: always 0? + bool _word2D0BC; }; } // End of namespace Efh From c51010ccdf135be27ed6f8db6b0bfbc57d277a03 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sun, 5 Dec 2021 16:54:02 +0100 Subject: [PATCH 078/412] EFH: Fix redraw, implement sub15581, renaming --- engines/efh/efh.cpp | 122 ++++++++++++++++++++++++++++---------------- engines/efh/efh.h | 13 ++--- 2 files changed, 84 insertions(+), 51 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index ae9d5de5305c..c4d1166951a2 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -263,7 +263,7 @@ EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst) _word2C86E = 0; _dword2C856 = nullptr; _word2C880 = false; - _word2C894 = false; + _redrawNeededFl = false; _word2C8D7 = true; _drawHeroOnMapFl = true; _drawMonstersOnMapFl = true; @@ -339,7 +339,7 @@ Common::Error EfhEngine::run() { */ initEngine(); sub15150(true); - sub12A7F(); + redrawScreen(); displayLowStatusScreen(true); if (!_protectionPassed) @@ -413,12 +413,12 @@ Common::Error EfhEngine::run() { _oldMapPosX = _mapPosX; _oldMapPosY = _mapPosY; _oldImageSetSubFilesIdx = _imageSetSubFilesIdx; - _word2C894 = true; + _redrawNeededFl = true; } else { _mapPosX = _oldMapPosX; _mapPosY = _oldMapPosY; if (_oldImageSetSubFilesIdx != _imageSetSubFilesIdx) { - _word2C894 = true; + _redrawNeededFl = true; _oldImageSetSubFilesIdx = _imageSetSubFilesIdx; } } @@ -432,8 +432,8 @@ Common::Error EfhEngine::run() { sub174A0(); } - if (_word2C894 && !_shouldQuit) { - sub12A7F(); + if (_redrawNeededFl && !_shouldQuit) { + redrawScreen(); displayLowStatusScreen(true); } @@ -1261,9 +1261,9 @@ void EfhEngine::displayLargeMap(int16 posX, int16 posY) { drawMap(true, posX, posY, 63, _drawHeroOnMapFl, _drawMonstersOnMapFl); } -void EfhEngine::sub12A7F() { +void EfhEngine::redrawScreen() { for (int16 counter = 0; counter < 2; ++counter) { - _word2C894 = false; + _redrawNeededFl = false; if (!_largeMapFlag) { if (_fullPlaceId != 0xFF) displaySmallMap(_mapPosX, _mapPosY); @@ -1385,7 +1385,8 @@ void EfhEngine::rImageFile(Common::String filename, uint8 *targetBuffer, uint8 * void EfhEngine::displayFctFullScreen() { // CHECKME: 319 is in the original but looks suspicious. // copyDirtyRect(0, 0, 319, 200); - + + warning("Char pos %d %d old pos %d %d", _mapPosX, _mapPosY, _oldMapPosX, _oldMapPosY); _system->copyRectToScreen((uint8 *)_mainSurface->getPixels(), 320, 0, 0, 320, 200); _system->updateScreen(); } @@ -1676,7 +1677,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, _oldMapPosY = _mapPosY = scriptNumberArray[2]; loadPlacesFile(scriptNumberArray[0], false); _word2C880 = true; - _word2C894 = true; + _redrawNeededFl = true; } break; case 0x01: @@ -1685,7 +1686,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, _oldMapPosX = _mapPosX = _techDataId_MapPosX; _oldMapPosY = _mapPosY = _techDataId_MapPosY; _word2C880 = true; - _word2C894 = true; + _redrawNeededFl = true; } break; case 0x02: @@ -1698,7 +1699,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, loadTechMapImp(scriptNumberArray[0]); _largeMapFlag = true; _word2C880 = true; - _word2C894 = true; + _redrawNeededFl = true; doneFlag = true; } break; @@ -1711,7 +1712,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, _mapPosX = getRandom(var110) + scriptNumberArray[0] - 1; _mapPosY = getRandom(var10E) + scriptNumberArray[1] - 1; _word2C880 = true; - _word2C894 = true; + _redrawNeededFl = true; } break; case 0x04: @@ -1720,7 +1721,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, _mapPosX = scriptNumberArray[0]; _mapPosY = scriptNumberArray[1]; _word2C880 = true; - _word2C894 = true; + _redrawNeededFl = true; } break; case 0x05: @@ -1887,7 +1888,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, _oldMapPosX = _mapPosX = scriptNumberArray[0]; _oldMapPosY = _mapPosY = scriptNumberArray[1]; _largeMapFlag = true; - _word2C894 = true; + _redrawNeededFl = true; } break; case 0x16: @@ -1947,7 +1948,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, if (var110 != -1) { _mapUnknownPtr[var110 * 9 + 1] = 0xFF; } - _word2C894 = true; + _redrawNeededFl = true; } break; case 0x19: @@ -2384,7 +2385,7 @@ void EfhEngine::unkFct_displayMenuBox_2(int16 color) { drawColoredRect(16, 152, 302, 189, color); } -int16 EfhEngine::sub16B08(int16 monsterId) { +int8 EfhEngine::sub16B08(int16 monsterId) { // Simplified version compared to the original int16 maxSize = _largeMapFlag ? 63 : 23; if (_mapMonsters[monsterId]._posX < 0 || _mapMonsters[monsterId]._posY < 0 || _mapMonsters[monsterId]._posX > maxSize || _mapMonsters[monsterId]._posY > maxSize) @@ -2409,7 +2410,7 @@ int16 EfhEngine::sub16B08(int16 monsterId) { return sub15581(_mapMonsters[monsterId]._posX, _mapMonsters[monsterId]._posY, 0); } -bool EfhEngine::moveMonsterGroupTowardsGroup_0(int16 monsterId) { +bool EfhEngine::moveMonsterAwayFromTeam(int16 monsterId) { if (_mapMonsters[monsterId]._posX < _mapPosX) { --_mapMonsters[monsterId]._posX; if (_mapMonsters[monsterId]._posY < _mapPosY) @@ -2441,7 +2442,7 @@ bool EfhEngine::moveMonsterGroupTowardsGroup_0(int16 monsterId) { return true; } -bool EfhEngine::moveMonsterGroupTowardsGroup_1(int16 monsterId) { +bool EfhEngine::moveMonsterTowardsTeam(int16 monsterId) { if (_mapMonsters[monsterId]._posX < _mapPosX) { ++_mapMonsters[monsterId]._posX; if (_mapMonsters[monsterId]._posY < _mapPosY) @@ -2513,13 +2514,13 @@ bool EfhEngine::moveMonsterGroup(int16 monsterId) { int16 rand100 = getRandom(100); if (rand100 < 30) - return moveMonsterGroupTowardsGroup_1(monsterId); + return moveMonsterTowardsTeam(monsterId); if (rand100 >= 60) // CHECKME: the original seems to only use 1 param?? return moveMonsterGroupOther(monsterId, getRandom(8)); - return moveMonsterGroupTowardsGroup_0(monsterId); + return moveMonsterAwayFromTeam(monsterId); } int16 EfhEngine::computeMonsterGroupDistance(int monsterId) { @@ -2591,7 +2592,7 @@ void EfhEngine::sub174A0() { int16 var14 = 0; int16 var6 = 0; - _word2C894 = false; + _redrawNeededFl = true; int16 unkMonsterId = -1; int16 mapSize = _largeMapFlag ? 63 : 23; int16 minDisplayedMapX = CLIP(_mapPosX - 10, 0, mapSize); @@ -2615,7 +2616,7 @@ void EfhEngine::sub174A0() { if (var4 < minDisplayedMapX || var4 > maxDisplayedMapX || var2 < minDisplayedMapY || var2 > maxDisplayedMapY) continue; - int16 var1A = 0; + bool var1A = false; var14 = 0; sub174A0_monsterPosX = _mapMonsters[monsterId]._posX; @@ -2633,13 +2634,13 @@ void EfhEngine::sub174A0() { switch (var1C - 1) { case 0: if (getRandom(100) >= 0xE - var1E) - var1A = moveMonsterGroupTowardsGroup_1(monsterId); + var1A = moveMonsterTowardsTeam(monsterId); else var1A = moveMonsterGroup(monsterId); break; case 1: if (getRandom(100) >= 0xE - var1E) - var1A = moveMonsterGroupTowardsGroup_0(monsterId); + var1A = moveMonsterAwayFromTeam(monsterId); else var1A = moveMonsterGroup(monsterId); break; @@ -2651,13 +2652,13 @@ void EfhEngine::sub174A0() { break; case 4: if (getRandom(100) > 0x32 - var1E) - var1A = moveMonsterGroupTowardsGroup_1(monsterId); + var1A = moveMonsterTowardsTeam(monsterId); else var1A = moveMonsterGroup(monsterId); break; case 5: if (getRandom(100) > 0x32 - var1E) - var1A = moveMonsterGroupTowardsGroup_0(monsterId); + var1A = moveMonsterAwayFromTeam(monsterId); else var1A = moveMonsterGroup(monsterId); break; @@ -2673,7 +2674,7 @@ void EfhEngine::sub174A0() { var14 = checkMonsterWeaponRange(monsterId); if (var14 == 0) { if (getRandom(100) >= 0xE - var1E) - var1A = moveMonsterGroupTowardsGroup_1(monsterId); + var1A = moveMonsterTowardsTeam(monsterId); else var1A = moveMonsterGroup(monsterId); } @@ -2682,7 +2683,7 @@ void EfhEngine::sub174A0() { var14 = checkMonsterWeaponRange(monsterId); if (var14 == 0) { if (getRandom(100) >= 0xE - var1E) - var1A = moveMonsterGroupTowardsGroup_0(monsterId); + var1A = moveMonsterAwayFromTeam(monsterId); else var1A = moveMonsterGroup(monsterId); } @@ -2703,7 +2704,7 @@ void EfhEngine::sub174A0() { var14 = checkMonsterWeaponRange(monsterId); if (var14 == 0) { if (getRandom(100) >= 0x32 - var1E) - var1A = moveMonsterGroupTowardsGroup_1(monsterId); + var1A = moveMonsterTowardsTeam(monsterId); else var1A = moveMonsterGroup(monsterId); } @@ -2712,7 +2713,7 @@ void EfhEngine::sub174A0() { var14 = checkMonsterWeaponRange(monsterId); if (var14 == 0) { if (getRandom(100) >= 0x32 - var1E) - var1A = moveMonsterGroupTowardsGroup_0(monsterId); + var1A = moveMonsterAwayFromTeam(monsterId); else var1A = moveMonsterGroup(monsterId); } @@ -2727,20 +2728,20 @@ void EfhEngine::sub174A0() { } for (;;) { - if (var1A == 0) { + if (!var1A) { if (var14 == 0) { - var1A = -1; + var1A = true; } else { unkMonsterId = monsterId; - var1A = -1; + var1A = true; } } else { - int16 var18 = sub16B08(monsterId); + int8 var18 = sub16B08(monsterId); if (var18 == 0) { _mapMonsters[monsterId]._posX = sub174A0_monsterPosX; _mapMonsters[monsterId]._posY = sub174A0_monsterPosY; - var1A = 0; + var1A = false; --var16; } else if (var18 == 2) { _mapMonsters[monsterId]._posX = sub174A0_monsterPosX; @@ -2748,16 +2749,14 @@ void EfhEngine::sub174A0() { } } - if (var1A == 0 && var16 == 1 && var1E > 1) { + if (!var1A && var16 == 1 && var1E > 1) { var1A = moveMonsterGroupOther(monsterId, getRandom(8)); continue; } break; } - - } while (var1A == 0 && var16 > 0); - + } while (!var1A && var16 > 0); } if (unkMonsterId != -1) @@ -2788,9 +2787,42 @@ void EfhEngine::sub221D2(int16 monsterId) { } } -int16 EfhEngine::sub15581(int16 mapPosX, int16 mapPosY, int16 arg4) { +bool EfhEngine::sub22293(int16 mapPosX, int16 mapPosY, int16 arg4, int16 _arg6, int16 arg8, int16 imageSetId) { + warning("STUB - sub22293"); + return false; +} + +int8 EfhEngine::sub15581(int16 mapPosX, int16 mapPosY, int16 arg4) { warning("STUB - sub15581"); - return 0; + int16 curTileInfo = getMapTileInfo(mapPosX, mapPosY); + int16 imageSetId = _currentTileBankImageSetId[curTileInfo / 72]; + imageSetId *= 72; + imageSetId += curTileInfo % 72; + + if (arg4 == 1 && _word2C8D7) { + int16 var2 = sub22293(mapPosX, mapPosY, -1, 0x7FFF, 0, imageSetId); + } + + if (_word2C880) { + _word2C880 = false; + return -1; + } + if (_tileFact[imageSetId * 2 + 1] != 0xFF && !_word2C8D5) { + if ((arg4 == 1 && _word2C8D7) || (arg4 == 0 && _word2C8D7 && imageSetId != 128 && imageSetId != 121)) { + if (_largeMapFlag) { + _mapGameMapPtr[mapPosX * 64 + mapPosY] = _tileFact[imageSetId * 2 + 1]; + } else { + _curPlace[mapPosX * 24 + mapPosY] = _tileFact[imageSetId * 2 + 1]; + } + + _redrawNeededFl = true; + if (_tileFact[imageSetId * 2] == 0) + return 2; + return 1; + } + } + + return _tileFact[imageSetId * 2]; } bool EfhEngine::handleFight(int16 monsterId) { @@ -2840,7 +2872,7 @@ bool EfhEngine::sub16E14() { _mapPosY = _oldMapPosY; if (_imageSetSubFilesIdx != _oldImageSetSubFilesIdx) _oldImageSetSubFilesIdx = _imageSetSubFilesIdx; - _word2C894 = true; + _redrawNeededFl = true; int16 var6A = 0; for (int16 var6C = 0; var6C < 9; ++var6C) { @@ -2923,8 +2955,8 @@ bool EfhEngine::sub16E14() { return true; } - monsterId = sub15581(_mapPosX, _mapPosY, 1); - if (monsterId == 0 || monsterId == 2) + int8 check = sub15581(_mapPosX, _mapPosY, 1); + if (check == 0 || check == 2) return false; return true; diff --git a/engines/efh/efh.h b/engines/efh/efh.h index b8a324343cfc..5b2eb1f6120b 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -294,7 +294,7 @@ class EfhEngine : public Engine { void drawMap(bool largeMapFl, int16 mapPosX, int16 mapPosY, int mapSize, bool drawHeroFl, bool drawMonstersFl); void displaySmallMap(int16 posX, int16 posY); void displayLargeMap(int16 posX, int16 posY); - void sub12A7F(); + void redrawScreen(); void displayRawDataAtPos(uint8 *imagePtr, int16 posX, int16 posY); void displayBufferBmAtPos(BufferBM *bufferBM, int16 posX, int16 posY); uint8 *script_readNumberArray(uint8 *buffer, int16 destArraySize, int16 *destArray); @@ -348,9 +348,9 @@ class EfhEngine : public Engine { void setNextCharacterPos(); void displayStringAtTextPos(char *message); void unkFct_displayMenuBox_2(int16 color); - int16 sub16B08(int16 monsterId); - bool moveMonsterGroupTowardsGroup_0(int16 monsterId); - bool moveMonsterGroupTowardsGroup_1(int16 monsterId); + int8 sub16B08(int16 monsterId); + bool moveMonsterAwayFromTeam(int16 monsterId); + bool moveMonsterTowardsTeam(int16 monsterId); bool moveMonsterGroupOther(int16 monsterId, int16 direction); bool moveMonsterGroup(int16 monsterId); int16 computeMonsterGroupDistance(int monsterId); @@ -363,7 +363,8 @@ class EfhEngine : public Engine { bool checkPictureRefAvailability(int16 monsterId); bool sub21820(int16 monsterId, int16 arg2, int16 arg4); void sub221D2(int16 monsterId); - int16 sub15581(int16 mapPosX, int16 mapPosY, int16 arg4); + bool sub22293(int16 mapPosX, int16 mapPosY, int16 arg4, int16 _arg6, int16 arg8, int16 imageSetId); + int8 sub15581(int16 mapPosX, int16 mapPosY, int16 arg4); bool handleFight(int16 monsterId); int16 handleStatusMenu(int16 gameMode, int16 charId); Common::KeyCode waitForKey(); @@ -442,7 +443,7 @@ class EfhEngine : public Engine { int16 _teamSize; int16 _word2C872; bool _word2C880; - bool _word2C894; + bool _redrawNeededFl; bool _word2C8D7; bool _drawHeroOnMapFl; bool _drawMonstersOnMapFl; From 51d4c3f9d1545aa5f68ae0ef5a97230eb0c6aa91 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sun, 5 Dec 2021 21:21:59 +0100 Subject: [PATCH 079/412] EFH: Implement handleWinSequence and getInput --- engines/efh/efh.cpp | 103 +++++++++++++++++++++++++++++++++++++++++++- engines/efh/efh.h | 1 + 2 files changed, 103 insertions(+), 1 deletion(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index c4d1166951a2..506c34616ac0 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -1496,8 +1496,109 @@ bool EfhEngine::isTPK() { return zeroedChar == _teamSize; } +Common::KeyCode EfhEngine::getInput(int16 delay) { + if (delay == 0) + return Common::KEYCODE_INVALID; + + Common::KeyCode lastChar = Common::KEYCODE_INVALID; + Common::KeyCode retVal = Common::KEYCODE_INVALID; + + uint32 lastMs = _system->getMillis(); + while (delay > 0) { + _system->delayMillis(20); + uint32 newMs = _system->getMillis(); + + if (newMs - lastMs >= 200) { + lastMs = newMs; + --delay; + unkFct_anim(); + } + + lastChar = handleAndMapInput(false); + if (lastChar != Common::KEYCODE_INVALID) + retVal = lastChar; + } + + return retVal; +} + void EfhEngine::handleWinSequence() { - warning("STUB - handleWinSequence"); + saveAnimImageSetId(); + findMapFile(18); + // clearMemory(); + uint8 *decompBuffer = (uint8 *)malloc(41000); + uint8 *winSeqBuf3 = (uint8 *)malloc(40100); + uint8 *winSeqBuf4 = (uint8 *)malloc(40100); + + uint8 *winSeqSubFilesArray1[10]; + uint8 *winSeqSubFilesArray2[20]; + loadImageSet(64, winSeqBuf3, winSeqSubFilesArray1, decompBuffer); + loadImageSet(65, winSeqBuf4, winSeqSubFilesArray2, decompBuffer); + + for (int16 counter = 0; counter < 2; ++counter) { + displayRawDataAtPos(winSeqSubFilesArray1[0], 0, 0); + displayRawDataAtPos(winSeqSubFilesArray2[0], 136, 48); + if (counter == 0) + displayFctFullScreen(); + } + + getInput(12); + for (int16 counter2 = 1; counter2 < 8; ++counter2) { + for (int16 counter = 0; counter < 2; ++counter) { + displayRawDataAtPos(winSeqSubFilesArray1[0], 0, 0); + displayRawDataAtPos(winSeqSubFilesArray2[counter2], 136, 48); + if (counter == 0) + displayFctFullScreen(); + } + getInput(1); + } + + Common::KeyCode var59 = Common::KEYCODE_INVALID; + + while(var59 != Common::KEYCODE_ESCAPE) { + displayRawDataAtPos(winSeqSubFilesArray1[0], 0, 0); + displayFctFullScreen(); + displayRawDataAtPos(winSeqSubFilesArray1[0], 0, 0); + var59 = getInput(32); + if (var59 != Common::KEYCODE_ESCAPE) { + displayRawDataAtPos(winSeqSubFilesArray2[10], 136, 72); + displayFctFullScreen(); + displayRawDataAtPos(winSeqSubFilesArray2[10], 136, 72); + var59 = getInput(1); + } + + if (var59 != Common::KEYCODE_ESCAPE) { + displayRawDataAtPos(winSeqSubFilesArray2[11], 136, 72); + displayFctFullScreen(); + displayRawDataAtPos(winSeqSubFilesArray2[11], 136, 72); + var59 = getInput(1); + } + + if (var59 != Common::KEYCODE_ESCAPE) { + displayRawDataAtPos(winSeqSubFilesArray2[12], 136, 72); + displayFctFullScreen(); + displayRawDataAtPos(winSeqSubFilesArray2[12], 136, 72); + var59 = getInput(1); + } + + if (var59 != Common::KEYCODE_ESCAPE) { + displayRawDataAtPos(winSeqSubFilesArray2[13], 136, 72); + displayFctFullScreen(); + displayRawDataAtPos(winSeqSubFilesArray2[13], 136, 72); + var59 = getInput(1); + } + + if (var59 != Common::KEYCODE_ESCAPE) { + displayRawDataAtPos(winSeqSubFilesArray2[14], 136, 72); + displayFctFullScreen(); + displayRawDataAtPos(winSeqSubFilesArray2[14], 136, 72); + var59 = getInput(1); + } + } + + free(decompBuffer); + free(winSeqBuf3); + free(winSeqBuf4); } bool EfhEngine::giveItemTo(int16 charId, int16 objectId, int altCharId) { diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 5b2eb1f6120b..4644a424b623 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -307,6 +307,7 @@ class EfhEngine : public Engine { void refreshTeamSize(); bool isCharacterATeamMember(int16 id); bool isTPK(); + Common::KeyCode getInput(int16 delay); void handleWinSequence(); bool giveItemTo(int16 charId, int16 objectId, int altCharId); void drawString(char * str, int16 startX, int16 startY, uint16 unkFl); From cc86b83031ed340793fb57b5d582ba1055edc150 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Mon, 6 Dec 2021 00:06:07 +0100 Subject: [PATCH 080/412] EFH: Implement handleNewRoundEffetcs --- engines/efh/efh.cpp | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 506c34616ac0..d81d90ffbe9b 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -1386,7 +1386,6 @@ void EfhEngine::displayFctFullScreen() { // CHECKME: 319 is in the original but looks suspicious. // copyDirtyRect(0, 0, 319, 200); - warning("Char pos %d %d old pos %d %d", _mapPosX, _mapPosY, _oldMapPosX, _oldMapPosY); _system->copyRectToScreen((uint8 *)_mainSurface->getPixels(), 320, 0, 0, 320, 200); _system->updateScreen(); } @@ -2390,7 +2389,28 @@ void EfhEngine::goSouthWest() { } void EfhEngine::handleNewRoundEffects() { - warning("STUB: handleNewRoundEffects"); + static int16 regenCounter = 0; + + if (!_word2C8D7) + return; + + for (int16 counter = 0; counter < _teamSize; ++counter) { + if (_teamCharStatus[counter]._status == 0) // normal + continue; + if (--_teamCharStatus[counter]._duration <= 0) { + _teamCharStatus[counter]._status = 0; + _teamCharStatus[counter]._duration = 0; + } + } + + if (++regenCounter <= 8) + return; + + for (int16 counter = 0; counter < _teamSize; ++counter) { + if (++_npcBuf[_teamCharId[counter]]._hitPoints > _npcBuf[_teamCharId[counter]]._maxHP) + _npcBuf[_teamCharId[counter]]._hitPoints = _npcBuf[_teamCharId[counter]]._maxHP; + } + regenCounter = 0; } bool EfhEngine::handleDeathMenu() { @@ -2894,7 +2914,6 @@ bool EfhEngine::sub22293(int16 mapPosX, int16 mapPosY, int16 arg4, int16 _arg6, } int8 EfhEngine::sub15581(int16 mapPosX, int16 mapPosY, int16 arg4) { - warning("STUB - sub15581"); int16 curTileInfo = getMapTileInfo(mapPosX, mapPosY); int16 imageSetId = _currentTileBankImageSetId[curTileInfo / 72]; imageSetId *= 72; From 50803c32e2038aec28eca36759f5ec1303a33f5a Mon Sep 17 00:00:00 2001 From: Strangerke Date: Wed, 8 Dec 2021 01:19:02 +0100 Subject: [PATCH 081/412] EFH: Implement various menu functions --- engines/efh/constants.cpp | 1 + engines/efh/efh.cpp | 767 ++++++++++++++++++++++++++++++++++---- engines/efh/efh.h | 27 +- 3 files changed, 729 insertions(+), 66 deletions(-) diff --git a/engines/efh/constants.cpp b/engines/efh/constants.cpp index 1e3bda56d24d..0547cbc14dab 100644 --- a/engines/efh/constants.cpp +++ b/engines/efh/constants.cpp @@ -25,6 +25,7 @@ #include "engine.h" namespace Efh { + const uint8 kFontWidthArray[96] = { 3, 2, 3, 5, 5, 5, 5, 2, 3, 3, 5, 5, 3, 3, 2, 7, 4, 3, 4, 4, 5, 4, 4, 4, 4, 4, 3, 4, 4, 5, 4, 5, 1, 4, 4, 4, 4, 4, 4, 4, 4, 3, 4, 4, 4, 7, 5, 4, 4, 4, 4, 4, 5, 4, 5, 7, 5, 5, 5, 3, 7, 3, 5, 0, 2, 4, 4, 4, 4, 4, 4, 4, diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index d81d90ffbe9b..922262504694 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -272,6 +272,14 @@ EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst) _word2C8D9 = false; _word2C8D5 = false; _word2D0BC = false; + _word2C8D2 = false; + _word2D0BE = 0; + _word2D0BA = 0; + + + for (int i = 0; i < 15; ++i) { + _word3273A[i] = 0; + } memset(_messageToBePrinted, 0, 400); } @@ -804,29 +812,6 @@ void EfhEngine::readImpFile(int16 id, bool techMapFl) { decryptImpFile(techMapFl); } -Common::KeyCode EfhEngine::getLastCharAfterAnimCount(int16 delay) { - if (delay == 0) - return Common::KEYCODE_INVALID; - - Common::KeyCode lastChar = Common::KEYCODE_INVALID; - - uint32 lastMs = _system->getMillis(); - while (delay > 0 && lastChar == Common::KEYCODE_INVALID) { - _system->delayMillis(20); - uint32 newMs = _system->getMillis(); - - if (newMs - lastMs >= 200) { - lastMs = newMs; - --delay; - unkFct_anim(); - } - - lastChar = handleAndMapInput(false); - } - - return lastChar; -} - void EfhEngine::playIntro() { displayRawDataAtPos(_circleImageSubFileArray[0], 0, 0); displayFctFullScreen(); @@ -1495,32 +1480,6 @@ bool EfhEngine::isTPK() { return zeroedChar == _teamSize; } -Common::KeyCode EfhEngine::getInput(int16 delay) { - if (delay == 0) - return Common::KEYCODE_INVALID; - - Common::KeyCode lastChar = Common::KEYCODE_INVALID; - Common::KeyCode retVal = Common::KEYCODE_INVALID; - - uint32 lastMs = _system->getMillis(); - while (delay > 0) { - _system->delayMillis(20); - uint32 newMs = _system->getMillis(); - - if (newMs - lastMs >= 200) { - lastMs = newMs; - --delay; - unkFct_anim(); - } - - lastChar = handleAndMapInput(false); - if (lastChar != Common::KEYCODE_INVALID) - retVal = lastChar; - } - - return retVal; -} - void EfhEngine::handleWinSequence() { saveAnimImageSetId(); findMapFile(18); @@ -2423,7 +2382,7 @@ void EfhEngine::setNumLock() { } void EfhEngine::computeMapAnimation() { - int16 maxMapBlocks = _largeMapFlag ? 63 : 23; + const int16 maxMapBlocks = _largeMapFlag ? 63 : 23; int16 minMapX = _mapPosX - 5; int16 minMapY = _mapPosY - 4; @@ -2446,7 +2405,7 @@ void EfhEngine::computeMapAnimation() { if (_largeMapFlag) { if (_currentTileBankImageSetId[0] != 0) continue; - int16 var4 = _mapGameMapPtr[counterX * 64 + counterY]; + uint8 var4 = _mapGameMapPtr[counterX * 64 + counterY]; if (var4 >= 1 && var4 <= 0xF) { if (getRandom(100) < 50) _mapGameMapPtr[counterX * 64 + counterY] += 0xC5; @@ -2457,7 +2416,7 @@ void EfhEngine::computeMapAnimation() { } else { if (_currentTileBankImageSetId[0] != 0) continue; - int16 var4 = _curPlace[counterX * 24 + counterY]; + uint8 var4 = _curPlace[counterX * 24 + counterY]; if (var4 >= 1 && var4 <= 0xF) { if (getRandom(100) < 50) _curPlace[counterX * 24 + counterY] += 0xC5; @@ -2908,8 +2867,89 @@ void EfhEngine::sub221D2(int16 monsterId) { } } -bool EfhEngine::sub22293(int16 mapPosX, int16 mapPosY, int16 arg4, int16 _arg6, int16 arg8, int16 imageSetId) { - warning("STUB - sub22293"); +void EfhEngine::sub22AA8(uint16 arg0) { + warning("STUB - sub22AA8"); +} + +bool EfhEngine::sub22293(int16 mapPosX, int16 mapPosY, int16 arg4, int16 arg6, int16 arg8, int16 imageSetId) { + int16 var8 = sub151FD(mapPosX, mapPosY); + + if (var8 == -1) { + if (imageSetId != -1 && *_imp2PtrArray[imageSetId] != 0x30) + sub221FA(_imp2PtrArray[imageSetId], true); + } else if (var8 == 0) { + if (_mapUnknownPtr[var8 * 9 + 3] == 0xFF) { + sub22AA8(_mapUnknownPtr[var8 * 9 + 5]); // word! + return true; + } else if (_mapUnknownPtr[var8 * 9 + 3] == 0xFE) { + for (int16 counter = 0; counter < _teamSize; ++counter) { + if (_teamCharId[counter] == -1) + continue; + if (_teamCharId[counter] == _mapUnknownPtr[var8 * 9 + 4]) { + sub22AA8(_mapUnknownPtr[var8 * 9 + 5]); + return true; + } + } + } else if (_mapUnknownPtr[var8 * 9 + 3] == 0xFD) { + for (int16 counter = 0; counter < _teamSize; ++counter) { + if (_teamCharId[counter] == -1) + continue; + + for (int16 var2 = 0; var2 < 10; ++var2) { + if (_npcBuf[_teamCharId[counter]]._inventory[var2]._ref == _mapUnknownPtr[var8 * 9 + 4]) { + sub22AA8(_mapUnknownPtr[var8 * 9 + 5]); + return true; + } + } + } + // original makes a useless check on (_mapUnknownPtr[var8 * 9 + 3] > 0x7F) + } else if (_mapUnknownPtr[var8 * 9 + 3] <= 0x77) { + int16 var6 = _mapUnknownPtr[var8 * 9 + 3]; + for (int counter = 0; counter < _teamSize; ++counter) { + if (_teamCharId[counter] == -1) + continue; + + for (int16 var2 = 0; var2 < 39; ++var2) { + if (_npcBuf[_teamCharId[counter]]._activeScore[var2] >= _mapUnknownPtr[var8 * 9 + 4]) { + sub22AA8(_mapUnknownPtr[var8 * 9 + 5]); + return true; + } + } + } + } + } else { + if ((_mapUnknownPtr[var8 * 9 + 3] == 0xFA && arg8 == 1) + || (_mapUnknownPtr[var8 * 9 + 3] == 0xFC && arg8 == 2) + || (_mapUnknownPtr[var8 * 9 + 3] == 0xFB && arg8 == 3)) { + if (_mapUnknownPtr[var8 * 9 + 4] == arg6) { + sub22AA8(_mapUnknownPtr[var8 * 9 + 5]); + return true; + } + } else if (arg8 == 4) { + int16 var6 = _mapUnknownPtr[var8 * 9 + 3]; + if (var6 >= 0x7B && var6 <= 0xEF) { + var6 -= 0x78; + if (var6 >= 0 && var6 <= 0x8B && var6 == arg6 && _mapUnknownPtr[var8 * 9 + 4] <= _npcBuf[arg4]._activeScore[arg6]) { + sub22AA8(_mapUnknownPtr[var8 * 9 + 5]); + return true; + } + } + } + } + + for (int16 counter = 0; counter < 64; ++counter) { + if (!sub21820(counter, arg8, arg6)) + return true; + } + + if ((arg8 == 4 && _mapUnknownPtr[var8 * 9 + 3] < 0xFA) || arg8 != 4) { + if (_mapUnknownPtr[var8 * 9 + 7] > 0xFE) // word!! + return false; + sub22AA8(_mapUnknownPtr[var8 * 9 + 7]); + return true; + } else + return false; + return false; } @@ -2950,19 +2990,538 @@ bool EfhEngine::handleFight(int16 monsterId) { return false; } -int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { - warning("STUB - handleStatusMenu"); - return 0; +void EfhEngine::displayMenuItemString(int16 menuBoxId, int thisBoxId, int minX, int maxX, int minY, const char *str) { + char buffer[20]; + memset(buffer, 0, 20); + + if (menuBoxId == thisBoxId) { + if (_word2D0BE == 0) + setTextColorWhite(); + else + setTextColor_08h(); + + sprintf(buffer, "> %s <", str); + displayCenteredString(buffer, minX, maxX, minY); + setTextColorRed(); + } else { + if (_word2D0BE == 0) + setTextColorRed(); + else + setTextColor_08h(); + + displayCenteredString((char *)str, minX, maxX, minY); + } } -Common::KeyCode EfhEngine::waitForKey() { - warning("STUB - waitForKey"); - return Common::KEYCODE_INVALID; +void EfhEngine::displayStatusMenu(int16 windowId) { + for (int16 counter = 0; counter < 9; ++counter) { + drawColoredRect(80, 39 + 14 * counter, 134, 47 + 14 * counter, 0); + } + + if (_word2D0BE != 0) + setTextColor_08h(); + + displayMenuItemString(windowId, 0, 80, 134, 39, "EQUIP"); + displayMenuItemString(windowId, 1, 80, 134, 53, "USE"); + displayMenuItemString(windowId, 2, 80, 134, 67, "GIVE"); + displayMenuItemString(windowId, 3, 80, 134, 81, "TRADE"); + displayMenuItemString(windowId, 4, 80, 134, 95, "DROP"); + displayMenuItemString(windowId, 5, 80, 134, 109, "INFO."); + displayMenuItemString(windowId, 6, 80, 134, 123, "PASSIVE"); + displayMenuItemString(windowId, 7, 80, 134, 137, "ACTIVE"); + displayMenuItemString(windowId, 8, 80, 134, 151, "LEAVE"); + + setTextColorRed(); } -Common::KeyCode EfhEngine::mapInputCode(Common::KeyCode input) { - warning("STUB - mapInputCode"); - return Common::KEYCODE_INVALID; +void EfhEngine::countRightWindowItems(int16 menuId, int16 charId) { + warning("STUB: countRightWindowItems"); +} + +void EfhEngine::displayCharacterSummary(int16 curMenuLine, int16 npcId) { + warning("STUB: displayCharacterSummary"); +} + +void EfhEngine::displayCharacterInformationOrSkills(int16 curMenuLine, int16 npcId) { + warning("STUB: displayCharacterInformationOrSkills"); +} + +void EfhEngine::displayStatusMenuActions(int16 menuId, int16 curMenuLine, int16 npcId) { + drawColoredRect(144, 15, 310, 184, 0); + displayCenteredString((char *)"(ESCape Aborts)", 144, 310, 175); + _textColor = 0x0E; + switch (menuId) { + case 0: + displayCenteredString((char *)"Select Item to Equip", 144, 310, 15); + displayCharacterSummary(curMenuLine, npcId); + break; + case 1: + displayCenteredString((char *)"Select Item to Use", 144, 310, 15); + displayCharacterSummary(curMenuLine, npcId); + break; + case 2: + displayCenteredString((char *)"Select Item to Give", 144, 310, 15); + displayCharacterSummary(curMenuLine, npcId); + break; + case 3: + displayCenteredString((char *)"Select Item to Trade", 144, 310, 15); + displayCharacterSummary(curMenuLine, npcId); + break; + case 4: + displayCenteredString((char *)"Select Item to Drop", 144, 310, 15); + displayCharacterSummary(curMenuLine, npcId); + break; + case 5: + displayCenteredString((char *)"Character Information", 144, 310, 15); + displayCharacterInformationOrSkills(curMenuLine, npcId); + break; + case 6: + displayCenteredString((char *)"Passive Skills", 144, 310, 15); + displayCharacterInformationOrSkills(curMenuLine, npcId); + break; + case 7: + displayCenteredString((char *)"Active Skills", 144, 310, 15); + displayCharacterInformationOrSkills(curMenuLine, npcId); + break; + case 8: + case 9: + displayCenteredString((char *)"Character Summary", 144, 310, 15); + displayCharacterSummary(curMenuLine, npcId); + break; + } +} + +void EfhEngine::unk_StatusMenu(int16 windowId, int16 menuId, int16 curMenuLine, int16 charId, bool unusedFl, bool refreshFl) { + displayStatusMenu(windowId); + + countRightWindowItems(menuId, charId); + displayStatusMenuActions(menuId, curMenuLine, charId); + + if (refreshFl) + displayFctFullScreen(); +} + +void EfhEngine::displayWindow(uint8 *buffer, int16 posX, int16 posY, uint8 *dest) { + if (buffer == nullptr) { + warning("Target Buffer Not Defined...DCImage!"); // That's the original message... And yes, it's wrong: it's checking the source buffer :) + return; + } + + // Only MCGA handled, the rest is skipped + uncompressBuffer(buffer, dest); + displayRawDataAtPos(dest, posX, posY); + displayFctFullScreen(); + displayRawDataAtPos(dest, posX, posY); +} + +void EfhEngine::sub18E80(int16 charId, int16 windowId, int16 menuId, int16 curMenuLine) { + for (int counter = 0; counter < 2; ++counter) { + displayWindow(_menuBuf, 0, 0, _hiResImageBuf); + unk_StatusMenu(windowId, menuId, curMenuLine, charId, true, false); + + if (counter == 0) + displayFctFullScreen(); + } +} + +int16 EfhEngine::_guess_displayString_3(const char *str, int16 arg2, int16 charId, int16 windowId, int16 menuId, int16 curMenuLine) { + int16 var2 = 0; + + for (int16 counter = 0; counter < 2; ++counter) { + unk_StatusMenu(windowId, menuId, curMenuLine, charId, true, false); + displayWindow(_windowWithBorderBuf, 19, 113, _hiResImageBuf); + + if (counter == 0) { + script_parse((uint8 *)str, 28, 122, 105, 166, 0); + displayFctFullScreen(); + } else { + var2 = script_parse((uint8 *)str, 28, 122, 105, 166, -1); + } + } + + getLastCharAfterAnimCount(_guessAnimationAmount); + sub18E80(charId, windowId, menuId, curMenuLine); + + return var2; +} + +bool EfhEngine::isItemCursed(int16 itemId) { + if (_items[itemId].field_16 == 21 || _items[itemId].field_16 == 22 || _items[itemId].field_16 == 23) + return true; + + return false; +} + +bool EfhEngine::hasObjectEquipped(int16 charId, int16 _objectId) { + if ((_npcBuf[charId]._inventory[_objectId]._stat1 & 0x80) == 0) + return false; + + return true; +} + +void EfhEngine::sub191FF(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine) { + warning("STUB: sub191FF"); +} + +int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine, int16 argA) { + warning("STUB: sub19E2E"); + + return -1; +} + +bool EfhEngine::getValidationFromUser() { + Common::KeyCode input = handleAndMapInput(true); + if (input == Common::KEYCODE_y) // or if joystick button 1 + return true; + + return false; +} + +int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { + int16 menuId = 9; + int16 var16 = -1; + int16 windowId = -1; + int16 curMenuLine = -1; + int16 var10 = 0; + int16 var2 = 0; + + saveAnimImageSetId(); + + _word2C8D2 = true; + _word2D0BE = 0; + + sub18E80(charId, windowId, menuId, curMenuLine); + + for (;;) { + if (windowId != -1) + unk_StatusMenu(windowId, menuId, curMenuLine, charId, true, true); + else + windowId = 0; + + do { + Common::KeyCode var19 = handleAndMapInput(false); + if (_word2D0BE == 0) { + switch (var19) { + case Common::KEYCODE_ESCAPE: + if (_word2D0BE == 0) { // ?? Useless case ? + windowId = 8; + var19 = Common::KEYCODE_RETURN; + } + break; + case Common::KEYCODE_a: + windowId = 7; + var19 = Common::KEYCODE_RETURN; + break; + case Common::KEYCODE_d: + windowId = 4; + var19 = Common::KEYCODE_RETURN; + break; + case Common::KEYCODE_e: + windowId = 0; + var19 = Common::KEYCODE_RETURN; + break; + case Common::KEYCODE_g: + windowId = 2; + var19 = Common::KEYCODE_RETURN; + break; + case Common::KEYCODE_i: + windowId = 5; + var19 = Common::KEYCODE_RETURN; + break; + case Common::KEYCODE_l: + windowId = 8; + var19 = Common::KEYCODE_RETURN; + break; + case Common::KEYCODE_p: + windowId = 6; + var19 = Common::KEYCODE_RETURN; + break; + case Common::KEYCODE_t: + windowId = 3; + var19 = Common::KEYCODE_RETURN; + break; + case Common::KEYCODE_u: + windowId = 1; + var19 = Common::KEYCODE_RETURN; + break; + // case 0xFB: Joystick button 2 + default: + warning("handleStatusMenu - unhandled keys 0xBA, 0xBB, 0xBC"); + break; + } + } else if (_word2D0BE == 1) { + if (var19 >= Common::KEYCODE_a && var19 <= Common::KEYCODE_z) { + int16 var8 = var19 - Common::KEYCODE_a; + if (var8 < _word2D0BA) { + curMenuLine = var8; + var19 = Common::KEYCODE_RETURN; + } + } + + } + + switch (var19) { + case Common::KEYCODE_RETURN: + // case 0xFA: Joystick button 1 + if (_word2D0BE == 0) { + menuId = windowId; + if (menuId > 7) + var10 = -1; + else { + _word2D0BE = 1; + curMenuLine = 0; + } + } else if (_word2D0BE == 1) { + if (_word2D0BA == 0) { + _word2D0BE = 0; + curMenuLine = -1; + menuId = 9; + unk_StatusMenu(windowId, menuId, curMenuLine, charId, true, true); + } else { + var16 = curMenuLine; + var10 = -1; + } + } + break; + case Common::KEYCODE_ESCAPE: + _word2D0BE = 0; + curMenuLine = -1; + menuId = 9; + unk_StatusMenu(windowId, menuId, curMenuLine, charId, true, true); + break; + case Common::KEYCODE_2: + case Common::KEYCODE_6: + // case 0xCC, 0xCF + if (_word2D0BE == 0) { + if (++windowId == 8) + windowId = 0; + } else if (_word2D0BE == 1) { + if (_word2D0BA != 0) { + ++curMenuLine; + if (curMenuLine > _word2D0BA - 1) + curMenuLine = 0; + } + } + break; + case Common::KEYCODE_4: + case Common::KEYCODE_8: + // case 0xC7, 0xCA + if (_word2D0BE == 0) { + if (--windowId < 0) + windowId = 8; + } else if (_word2D0BE == 1) { + if (_word2D0BA != 0) { + --curMenuLine; + if (curMenuLine < 0) + curMenuLine = _word2D0BA - 1; + } + } + break; + } + + if (curMenuLine == -1) + unk_StatusMenu(windowId, menuId, curMenuLine, charId, false, true); + else + unk_StatusMenu(windowId, menuId, curMenuLine, charId, true, true); + + } while (var10 == 0); + + bool validationFl = true; + + int16 objectId; + int16 itemId; + switch (menuId) { + case 0: + objectId = _word3273A[var16]; + itemId = _npcBuf[charId]._inventory[objectId]._ref; + sub191FF(charId, objectId, windowId, menuId, curMenuLine); + if (gameMode == 2) { + restoreAnimImageSetId(); + _word2C8D2 = false; + return 0x7D00; + } + break; + case 1: + objectId = _word3273A[var16]; + itemId = _npcBuf[charId]._inventory[objectId]._ref; + if (gameMode == 2) { + restoreAnimImageSetId(); + _word2C8D2 = false; + return objectId; + } else { + if (sub22293(_mapPosX, _mapPosY, charId, itemId, 2, -1)) { + _word2C8D2 = false; + return -1; + } else { + int16 var8 = sub19E2E(charId, objectId, windowId, menuId, curMenuLine, 2); + } + } + break; + case 2: + objectId = _word3273A[var16]; + itemId = _npcBuf[charId]._inventory[objectId]._ref; + if (hasObjectEquipped(charId, objectId) && isItemCursed(itemId)) { + _guess_displayString_3("The item is cursed! IT IS EVIL!!!!!!!!", -1, charId, windowId, menuId, curMenuLine); + } else if (hasObjectEquipped(charId, objectId)){ + _guess_displayString_3("Item is Equipped! Give anyway?", 0, charId, windowId, menuId, curMenuLine); + if (!getValidationFromUser()) + validationFl = false; + sub18E80(charId, windowId, menuId, curMenuLine); + + if (validationFl) { + if (gameMode == 2) { + _guess_displayString_3("Not a Combat Option !", -1, charId, windowId, menuId, curMenuLine); + } else { + removeObject(charId, objectId); + int16 var8 = sub22293(_mapPosX, _mapPosY, charId, itemId, 3, -1); + if (var8 != 0) { + _word2C8D2 = false; + return -1; + } + } + } + } + + break; + case 3: + objectId = _word3273A[var16]; + itemId = _npcBuf[charId]._inventory[objectId]._ref; + if (hasObjectEquipped(charId, objectId) && isItemCursed(itemId)) { + _guess_displayString_3("The item is cursed! IT IS EVIL!!!!!!!!", -1, charId, windowId, menuId, curMenuLine); + } else if (hasObjectEquipped(charId, objectId)) { + _guess_displayString_3("Item is Equipped! Trade anyway?", 0, charId, windowId, menuId, curMenuLine); + if (!getValidationFromUser()) + validationFl = false; + sub18E80(charId, windowId, menuId, curMenuLine); + + if (validationFl) { + int16 var6; + int16 var8; + do { + if (_teamCharId[2] != -1) { + var8 = _guess_displayString_3("Who will you give the item to?", 0, charId, windowId, menuId, curMenuLine); + var2 = 0; + } else if (_teamCharId[1]) { + var8 = 0x1A; + var2 = 0; + } else { + var2 = -1; + if (_teamCharId[0] == charId) + var8 = 1; + else + var8 = 0; + } + + if (var8 != 0x1A && var8 != 0x1B) { + var6 = giveItemTo(_teamCharId[var8], objectId, charId); + if (var6 == 0) { + _guess_displayString_3("That character cannot carry anymore!", 0, charId, windowId, menuId, curMenuLine); + Common::KeyCode var4 = getLastCharAfterAnimCount(_guessAnimationAmount); + } + } else { + if (var8 == 0x1A) { + _guess_displayString_3("No one to trade with!", 0, charId, windowId, menuId, curMenuLine); + Common::KeyCode var4 = getLastCharAfterAnimCount(_guessAnimationAmount); + var8 = 0x1B; + } + var6 = 0; + } + } while (var6 == 0 && var2 == 0 && var8 != 0x1B); + + if (var6) { + removeObject(charId, objectId); + if (gameMode == 2) { + restoreAnimImageSetId(); + _word2C8D2 = false; + return 0x7D00; + } + } + + sub18E80(charId, windowId, menuId, curMenuLine); + } + } + break; + case 4: + objectId = _word3273A[var16]; + itemId = _npcBuf[charId]._inventory[objectId]._ref; + if (hasObjectEquipped(charId, objectId) && isItemCursed(itemId)) { + _guess_displayString_3("The item is cursed! IT IS EVIL!!!!!!!!", -1, charId, windowId, menuId, curMenuLine); + } else if (hasObjectEquipped(charId, objectId)) { + _guess_displayString_3("Item Is Equipped! Drop Anyway?", 0, charId, windowId, menuId, curMenuLine); + if (!getValidationFromUser()) + validationFl = false; + sub18E80(charId, windowId, menuId, curMenuLine); + + if (validationFl) { + removeObject(charId, objectId); + if (gameMode == 2) { + restoreAnimImageSetId(); + _word2C8D2 = false; + return 0x7D00; + } + + bool var8 = sub22293(_mapPosX, _mapPosY, charId, itemId, 1, -1); + if (var8) { + _word2C8D2 = false; + return -1; + } + } + } + break; + case 5: + objectId = _word3273A[var16]; + if (gameMode == 2) { + _guess_displayString_3("Not a Combat Option!", 0xFFFF, charId, windowId, menuId, curMenuLine); + } else { + bool var8 = sub22293(_mapPosX, _mapPosY, charId, objectId, 4, -1); + if (var8) { + _word2C8D2 = false; + return 0xFFFF; + } + } + break; + case 6: // Identical to case 5? + objectId = _word3273A[var16]; + if (gameMode == 2) { + _guess_displayString_3("Not a Combat Option!", 0xFFFF, charId, windowId, menuId, curMenuLine); + } else { + bool var8 = sub22293(_mapPosX, _mapPosY, charId, objectId, 4, -1); + if (var8) { + _word2C8D2 = false; + return 0xFFFF; + } + } + break; + case 7: // Identical to case 5? + objectId = _word3273A[var16]; + if (gameMode == 2) { + _guess_displayString_3("Not a Combat Option!", 0xFFFF, charId, windowId, menuId, curMenuLine); + } else { + bool var8 = sub22293(_mapPosX, _mapPosY, charId, objectId, 4, -1); + if (var8) { + _word2C8D2 = false; + return -1; + } + } + break; + } + + if (menuId != 8) { + var10 = 0; + _word2D0BE = 0; + menuId = 9; + var16 = -1; + curMenuLine = -1; + } + + if (menuId == 8) { + restoreAnimImageSetId(); + _word2C8D2 = false; + return 0x7FFF; + } + } + + return 0; } bool EfhEngine::sub16E14() { @@ -3281,6 +3840,88 @@ Common::KeyCode EfhEngine::handleAndMapInput(bool animFl) { return retVal; } +Common::KeyCode EfhEngine::waitForKey() { + Common::KeyCode retVal = Common::KEYCODE_INVALID; + Common::Event event; + + uint32 lastMs = _system->getMillis(); + while (retVal == Common::KEYCODE_INVALID) { // TODO: Check shouldquit() + _system->delayMillis(20); + uint32 newMs = _system->getMillis(); + + if (newMs - lastMs >= 200) { + lastMs = newMs; + unkFct_anim(); + } + + _system->getEventManager()->pollEvent(event); + if (event.type == Common::EVENT_KEYUP) { + retVal = event.kbd.keycode; + } + } + + return retVal; +} + +Common::KeyCode EfhEngine::mapInputCode(Common::KeyCode input) { + // Original is doing: + // if input < a or > z : return input + // else return (input + 0xE0) + // ex: 'a' = 0x61 + 0xE0 = 0x0141, but it's a uint8 so it's 0x41 which is 'A'. + // So basically the original works with uppercase letters and do not alter the other inputs. + // => no implementation needed. + return input; +} + +Common::KeyCode EfhEngine::getLastCharAfterAnimCount(int16 delay) { + if (delay == 0) + return Common::KEYCODE_INVALID; + + Common::KeyCode lastChar = Common::KEYCODE_INVALID; + + uint32 lastMs = _system->getMillis(); + while (delay > 0 && lastChar == Common::KEYCODE_INVALID) { + _system->delayMillis(20); + uint32 newMs = _system->getMillis(); + + if (newMs - lastMs >= 200) { + lastMs = newMs; + --delay; + unkFct_anim(); + } + + lastChar = handleAndMapInput(false); + } + + return lastChar; +} + +Common::KeyCode EfhEngine::getInput(int16 delay) { + if (delay == 0) + return Common::KEYCODE_INVALID; + + Common::KeyCode lastChar = Common::KEYCODE_INVALID; + Common::KeyCode retVal = Common::KEYCODE_INVALID; + + uint32 lastMs = _system->getMillis(); + while (delay > 0) { + _system->delayMillis(20); + uint32 newMs = _system->getMillis(); + + if (newMs - lastMs >= 200) { + lastMs = newMs; + --delay; + unkFct_anim(); + } + + lastChar = handleAndMapInput(false); + if (lastChar != Common::KEYCODE_INVALID) + retVal = lastChar; + } + + return retVal; +} + void EfhEngine::displayNextAnimFrame() { if (++_unkAnimRelatedIndex >= 15) _unkAnimRelatedIndex = 0; diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 4644a424b623..39f9abc9936e 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -310,8 +310,8 @@ class EfhEngine : public Engine { Common::KeyCode getInput(int16 delay); void handleWinSequence(); bool giveItemTo(int16 charId, int16 objectId, int altCharId); - void drawString(char * str, int16 startX, int16 startY, uint16 unkFl); - void displayCenteredString(char * str, int16 minX, int16 maxX, int16 posY); + void drawString(char *str, int16 startX, int16 startY, uint16 unkFl); + void displayCenteredString(char *str, int16 minX, int16 maxX, int16 posY); int16 chooseCharacterToReplace(); int16 handleCharacterJoining(); void drawMapWindow(); @@ -364,9 +364,25 @@ class EfhEngine : public Engine { bool checkPictureRefAvailability(int16 monsterId); bool sub21820(int16 monsterId, int16 arg2, int16 arg4); void sub221D2(int16 monsterId); - bool sub22293(int16 mapPosX, int16 mapPosY, int16 arg4, int16 _arg6, int16 arg8, int16 imageSetId); + void sub22AA8(uint16 arg0); + bool sub22293(int16 mapPosX, int16 mapPosY, int16 arg4, int16 arg6, int16 arg8, int16 imageSetId); int8 sub15581(int16 mapPosX, int16 mapPosY, int16 arg4); bool handleFight(int16 monsterId); + void displayMenuItemString(int16 menuBoxId, int thisBoxId, int minX, int maxX, int minY, const char *str); + void displayStatusMenu(int16 windowId); + void countRightWindowItems(int16 menuId, int16 charId); + void displayCharacterSummary(int16 curMenuLine, int16 npcId); + void displayCharacterInformationOrSkills(int16 curMenuLine, int16 npcId); + void displayStatusMenuActions(int16 menuId, int16 curMenuLine, int16 npcId); + void unk_StatusMenu(int16 windowId, int16 menuId, int16 curMenuLine, int16 charId, bool unusedFl, bool refreshFl); + void displayWindow(uint8 *buffer, int16 posX, int16 posY, uint8 *dest); + void sub18E80(int16 charId, int16 windowId, int16 menuId, int16 curMenuLine); + int16 _guess_displayString_3(const char * str, int16 arg2, int16 charId, int16 windowId, int16 menuId, int16 curMenuLine); + bool isItemCursed(int16 itemId); + bool hasObjectEquipped(int16 charId, int16 _objectId); + void sub191FF(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine); + int16 sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine, int16 argA); + bool getValidationFromUser(); int16 handleStatusMenu(int16 gameMode, int16 charId); Common::KeyCode waitForKey(); Common::KeyCode mapInputCode(Common::KeyCode input); @@ -464,6 +480,11 @@ class EfhEngine : public Engine { bool _word2C8D9; bool _word2C8D5; // CHECKME: always 0? bool _word2D0BC; + bool _word2C8D2; + int16 _word2D0BE; + int16 _word2D0BA; + + int16 _word3273A[15]; }; } // End of namespace Efh From 40ad50f161e800ce5a8d40fafd5139066816317f Mon Sep 17 00:00:00 2001 From: Strangerke Date: Wed, 8 Dec 2021 08:58:21 +0100 Subject: [PATCH 082/412] EFH: Fix number of menu lines, add some convenient keycodes in the menus, some small renaming and clean up --- engines/efh/efh.cpp | 148 ++++++++++++++++++++++++-------------------- engines/efh/efh.h | 14 ++--- 2 files changed, 87 insertions(+), 75 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 922262504694..e7f37939a78f 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -273,7 +273,7 @@ EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst) _word2C8D5 = false; _word2D0BC = false; _word2C8D2 = false; - _word2D0BE = 0; + _menuDepth = 0; _word2D0BA = 0; @@ -1565,7 +1565,7 @@ bool EfhEngine::giveItemTo(int16 charId, int16 objectId, int altCharId) { return false; } -void EfhEngine::drawString(char *str, int16 startX, int16 startY, uint16 unkFl) { +void EfhEngine::drawString(const char *str, int16 startX, int16 startY, uint16 unkFl) { uint8 *curPtr = (uint8 *)str; uint16 lineHeight = _fontDescr._charHeight + _fontDescr._extraVerticalSpace; _unk_sub26437_flag = unkFl & 0x3FFF; @@ -1602,7 +1602,7 @@ void EfhEngine::drawString(char *str, int16 startX, int16 startY, uint16 unkFl) } -void EfhEngine::displayCenteredString(char *str, int16 minX, int16 maxX, int16 posY) { +void EfhEngine::displayCenteredString(const char *str, int16 minX, int16 maxX, int16 posY) { uint16 length = getStringWidth(str); int16 startCenteredDisplayX = minX + (maxX - minX - length) / 2; drawString(str, startCenteredDisplayX, posY, _textColor); @@ -1665,7 +1665,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, uint16 curLine = 0; int16 numbLines = (1 + maxY - posY) / 9; int16 width = maxX - posX; - int16 var_114 = getStringWidth((char *)stringToDisplay); + int16 var_114 = getStringWidth(stringToDisplay); uint8 *buffer = stringBuffer; char var_EC[80]; char dest[150]; @@ -2206,7 +2206,7 @@ void EfhEngine::setTextColorRed() { _textColor = 0xC; } -void EfhEngine::setTextColor_08h() { +void EfhEngine::setTextColorGrey() { if (_videoMode == 8) // CGA _textColor = 0x1; else @@ -2455,7 +2455,7 @@ void EfhEngine::setNextCharacterPos() { _textPosY = 0; } -void EfhEngine::displayStringAtTextPos(char *message) { +void EfhEngine::displayStringAtTextPos(const char *message) { drawString(message, _textPosX, _textPosY, _textColor); _textPosX += getStringWidth(message) + 1; setNextCharacterPos(); @@ -2995,21 +2995,21 @@ void EfhEngine::displayMenuItemString(int16 menuBoxId, int thisBoxId, int minX, memset(buffer, 0, 20); if (menuBoxId == thisBoxId) { - if (_word2D0BE == 0) + if (_menuDepth == 0) setTextColorWhite(); else - setTextColor_08h(); + setTextColorGrey(); sprintf(buffer, "> %s <", str); displayCenteredString(buffer, minX, maxX, minY); setTextColorRed(); } else { - if (_word2D0BE == 0) + if (_menuDepth == 0) setTextColorRed(); else - setTextColor_08h(); + setTextColorGrey(); - displayCenteredString((char *)str, minX, maxX, minY); + displayCenteredString(str, minX, maxX, minY); } } @@ -3018,8 +3018,8 @@ void EfhEngine::displayStatusMenu(int16 windowId) { drawColoredRect(80, 39 + 14 * counter, 134, 47 + 14 * counter, 0); } - if (_word2D0BE != 0) - setTextColor_08h(); + if (_menuDepth != 0) + setTextColorGrey(); displayMenuItemString(windowId, 0, 80, 134, 39, "EQUIP"); displayMenuItemString(windowId, 1, 80, 134, 53, "USE"); @@ -3048,44 +3048,44 @@ void EfhEngine::displayCharacterInformationOrSkills(int16 curMenuLine, int16 npc void EfhEngine::displayStatusMenuActions(int16 menuId, int16 curMenuLine, int16 npcId) { drawColoredRect(144, 15, 310, 184, 0); - displayCenteredString((char *)"(ESCape Aborts)", 144, 310, 175); + displayCenteredString("(ESCape Aborts)", 144, 310, 175); _textColor = 0x0E; switch (menuId) { case 0: - displayCenteredString((char *)"Select Item to Equip", 144, 310, 15); + displayCenteredString("Select Item to Equip", 144, 310, 15); displayCharacterSummary(curMenuLine, npcId); break; case 1: - displayCenteredString((char *)"Select Item to Use", 144, 310, 15); + displayCenteredString("Select Item to Use", 144, 310, 15); displayCharacterSummary(curMenuLine, npcId); break; case 2: - displayCenteredString((char *)"Select Item to Give", 144, 310, 15); + displayCenteredString("Select Item to Give", 144, 310, 15); displayCharacterSummary(curMenuLine, npcId); break; case 3: - displayCenteredString((char *)"Select Item to Trade", 144, 310, 15); + displayCenteredString("Select Item to Trade", 144, 310, 15); displayCharacterSummary(curMenuLine, npcId); break; case 4: - displayCenteredString((char *)"Select Item to Drop", 144, 310, 15); + displayCenteredString("Select Item to Drop", 144, 310, 15); displayCharacterSummary(curMenuLine, npcId); break; case 5: - displayCenteredString((char *)"Character Information", 144, 310, 15); + displayCenteredString("Character Information", 144, 310, 15); displayCharacterInformationOrSkills(curMenuLine, npcId); break; case 6: - displayCenteredString((char *)"Passive Skills", 144, 310, 15); + displayCenteredString("Passive Skills", 144, 310, 15); displayCharacterInformationOrSkills(curMenuLine, npcId); break; case 7: - displayCenteredString((char *)"Active Skills", 144, 310, 15); + displayCenteredString("Active Skills", 144, 310, 15); displayCharacterInformationOrSkills(curMenuLine, npcId); break; case 8: case 9: - displayCenteredString((char *)"Character Summary", 144, 310, 15); + displayCenteredString("Character Summary", 144, 310, 15); displayCharacterSummary(curMenuLine, npcId); break; } @@ -3124,7 +3124,7 @@ void EfhEngine::sub18E80(int16 charId, int16 windowId, int16 menuId, int16 curMe } } -int16 EfhEngine::_guess_displayString_3(const char *str, int16 arg2, int16 charId, int16 windowId, int16 menuId, int16 curMenuLine) { +int16 EfhEngine::displayString_3(const char *str, bool animFl, int16 charId, int16 windowId, int16 menuId, int16 curMenuLine) { int16 var2 = 0; for (int16 counter = 0; counter < 2; ++counter) { @@ -3139,9 +3139,11 @@ int16 EfhEngine::_guess_displayString_3(const char *str, int16 arg2, int16 charI } } - getLastCharAfterAnimCount(_guessAnimationAmount); - sub18E80(charId, windowId, menuId, curMenuLine); - + if (animFl) { + getLastCharAfterAnimCount(_guessAnimationAmount); + sub18E80(charId, windowId, menuId, curMenuLine); + } + return var2; } @@ -3188,7 +3190,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { saveAnimImageSetId(); _word2C8D2 = true; - _word2D0BE = 0; + _menuDepth = 0; sub18E80(charId, windowId, menuId, curMenuLine); @@ -3200,10 +3202,10 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { do { Common::KeyCode var19 = handleAndMapInput(false); - if (_word2D0BE == 0) { + if (_menuDepth == 0) { switch (var19) { case Common::KEYCODE_ESCAPE: - if (_word2D0BE == 0) { // ?? Useless case ? + if (_menuDepth == 0) { // ?? Useless case ? windowId = 8; var19 = Common::KEYCODE_RETURN; } @@ -3249,7 +3251,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { warning("handleStatusMenu - unhandled keys 0xBA, 0xBB, 0xBC"); break; } - } else if (_word2D0BE == 1) { + } else if (_menuDepth == 1) { if (var19 >= Common::KEYCODE_a && var19 <= Common::KEYCODE_z) { int16 var8 = var19 - Common::KEYCODE_a; if (var8 < _word2D0BA) { @@ -3263,17 +3265,17 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { switch (var19) { case Common::KEYCODE_RETURN: // case 0xFA: Joystick button 1 - if (_word2D0BE == 0) { + if (_menuDepth == 0) { menuId = windowId; if (menuId > 7) var10 = -1; else { - _word2D0BE = 1; + _menuDepth = 1; curMenuLine = 0; } - } else if (_word2D0BE == 1) { + } else if (_menuDepth == 1) { if (_word2D0BA == 0) { - _word2D0BE = 0; + _menuDepth = 0; curMenuLine = -1; menuId = 9; unk_StatusMenu(windowId, menuId, curMenuLine, charId, true, true); @@ -3284,18 +3286,23 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { } break; case Common::KEYCODE_ESCAPE: - _word2D0BE = 0; + _menuDepth = 0; curMenuLine = -1; menuId = 9; unk_StatusMenu(windowId, menuId, curMenuLine, charId, true, true); break; case Common::KEYCODE_2: case Common::KEYCODE_6: - // case 0xCC, 0xCF - if (_word2D0BE == 0) { - if (++windowId == 8) + // Added for ScummVM + case Common::KEYCODE_DOWN: + case Common::KEYCODE_RIGHT: + case Common::KEYCODE_KP2: + case Common::KEYCODE_KP6: + // Original checks joystick axis: case 0xCC, 0xCF + if (_menuDepth == 0) { + if (++windowId > 8) windowId = 0; - } else if (_word2D0BE == 1) { + } else if (_menuDepth == 1) { if (_word2D0BA != 0) { ++curMenuLine; if (curMenuLine > _word2D0BA - 1) @@ -3305,11 +3312,16 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { break; case Common::KEYCODE_4: case Common::KEYCODE_8: - // case 0xC7, 0xCA - if (_word2D0BE == 0) { + // Added for ScummVM + case Common::KEYCODE_LEFT: + case Common::KEYCODE_UP: + case Common::KEYCODE_KP4: + case Common::KEYCODE_KP8: + // Original checks joystick axis: case 0xC7, 0xCA + if (_menuDepth == 0) { if (--windowId < 0) windowId = 8; - } else if (_word2D0BE == 1) { + } else if (_menuDepth == 1) { if (_word2D0BA != 0) { --curMenuLine; if (curMenuLine < 0) @@ -3353,7 +3365,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { _word2C8D2 = false; return -1; } else { - int16 var8 = sub19E2E(charId, objectId, windowId, menuId, curMenuLine, 2); + sub19E2E(charId, objectId, windowId, menuId, curMenuLine, 2); } } break; @@ -3361,16 +3373,16 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { objectId = _word3273A[var16]; itemId = _npcBuf[charId]._inventory[objectId]._ref; if (hasObjectEquipped(charId, objectId) && isItemCursed(itemId)) { - _guess_displayString_3("The item is cursed! IT IS EVIL!!!!!!!!", -1, charId, windowId, menuId, curMenuLine); + displayString_3("The item is cursed! IT IS EVIL!!!!!!!!", true, charId, windowId, menuId, curMenuLine); } else if (hasObjectEquipped(charId, objectId)){ - _guess_displayString_3("Item is Equipped! Give anyway?", 0, charId, windowId, menuId, curMenuLine); + displayString_3("Item is Equipped! Give anyway?", false, charId, windowId, menuId, curMenuLine); if (!getValidationFromUser()) validationFl = false; sub18E80(charId, windowId, menuId, curMenuLine); if (validationFl) { if (gameMode == 2) { - _guess_displayString_3("Not a Combat Option !", -1, charId, windowId, menuId, curMenuLine); + displayString_3("Not a Combat Option !", true, charId, windowId, menuId, curMenuLine); } else { removeObject(charId, objectId); int16 var8 = sub22293(_mapPosX, _mapPosY, charId, itemId, 3, -1); @@ -3387,9 +3399,9 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { objectId = _word3273A[var16]; itemId = _npcBuf[charId]._inventory[objectId]._ref; if (hasObjectEquipped(charId, objectId) && isItemCursed(itemId)) { - _guess_displayString_3("The item is cursed! IT IS EVIL!!!!!!!!", -1, charId, windowId, menuId, curMenuLine); + displayString_3("The item is cursed! IT IS EVIL!!!!!!!!", true, charId, windowId, menuId, curMenuLine); } else if (hasObjectEquipped(charId, objectId)) { - _guess_displayString_3("Item is Equipped! Trade anyway?", 0, charId, windowId, menuId, curMenuLine); + displayString_3("Item is Equipped! Trade anyway?", false, charId, windowId, menuId, curMenuLine); if (!getValidationFromUser()) validationFl = false; sub18E80(charId, windowId, menuId, curMenuLine); @@ -3399,7 +3411,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { int16 var8; do { if (_teamCharId[2] != -1) { - var8 = _guess_displayString_3("Who will you give the item to?", 0, charId, windowId, menuId, curMenuLine); + var8 = displayString_3("Who will you give the item to?", false, charId, windowId, menuId, curMenuLine); var2 = 0; } else if (_teamCharId[1]) { var8 = 0x1A; @@ -3415,13 +3427,13 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { if (var8 != 0x1A && var8 != 0x1B) { var6 = giveItemTo(_teamCharId[var8], objectId, charId); if (var6 == 0) { - _guess_displayString_3("That character cannot carry anymore!", 0, charId, windowId, menuId, curMenuLine); - Common::KeyCode var4 = getLastCharAfterAnimCount(_guessAnimationAmount); + displayString_3("That character cannot carry anymore!", false, charId, windowId, menuId, curMenuLine); + getLastCharAfterAnimCount(_guessAnimationAmount); } } else { if (var8 == 0x1A) { - _guess_displayString_3("No one to trade with!", 0, charId, windowId, menuId, curMenuLine); - Common::KeyCode var4 = getLastCharAfterAnimCount(_guessAnimationAmount); + displayString_3("No one to trade with!", false, charId, windowId, menuId, curMenuLine); + getLastCharAfterAnimCount(_guessAnimationAmount); var8 = 0x1B; } var6 = 0; @@ -3445,9 +3457,9 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { objectId = _word3273A[var16]; itemId = _npcBuf[charId]._inventory[objectId]._ref; if (hasObjectEquipped(charId, objectId) && isItemCursed(itemId)) { - _guess_displayString_3("The item is cursed! IT IS EVIL!!!!!!!!", -1, charId, windowId, menuId, curMenuLine); + displayString_3("The item is cursed! IT IS EVIL!!!!!!!!", true, charId, windowId, menuId, curMenuLine); } else if (hasObjectEquipped(charId, objectId)) { - _guess_displayString_3("Item Is Equipped! Drop Anyway?", 0, charId, windowId, menuId, curMenuLine); + displayString_3("Item Is Equipped! Drop Anyway?", false, charId, windowId, menuId, curMenuLine); if (!getValidationFromUser()) validationFl = false; sub18E80(charId, windowId, menuId, curMenuLine); @@ -3471,7 +3483,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { case 5: objectId = _word3273A[var16]; if (gameMode == 2) { - _guess_displayString_3("Not a Combat Option!", 0xFFFF, charId, windowId, menuId, curMenuLine); + displayString_3("Not a Combat Option!", true, charId, windowId, menuId, curMenuLine); } else { bool var8 = sub22293(_mapPosX, _mapPosY, charId, objectId, 4, -1); if (var8) { @@ -3483,7 +3495,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { case 6: // Identical to case 5? objectId = _word3273A[var16]; if (gameMode == 2) { - _guess_displayString_3("Not a Combat Option!", 0xFFFF, charId, windowId, menuId, curMenuLine); + displayString_3("Not a Combat Option!", true, charId, windowId, menuId, curMenuLine); } else { bool var8 = sub22293(_mapPosX, _mapPosY, charId, objectId, 4, -1); if (var8) { @@ -3495,7 +3507,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { case 7: // Identical to case 5? objectId = _word3273A[var16]; if (gameMode == 2) { - _guess_displayString_3("Not a Combat Option!", 0xFFFF, charId, windowId, menuId, curMenuLine); + displayString_3("Not a Combat Option!", true, charId, windowId, menuId, curMenuLine); } else { bool var8 = sub22293(_mapPosX, _mapPosY, charId, objectId, 4, -1); if (var8) { @@ -3508,7 +3520,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { if (menuId != 8) { var10 = 0; - _word2D0BE = 0; + _menuDepth = 0; menuId = 9; var16 = -1; curMenuLine = -1; @@ -3577,30 +3589,30 @@ bool EfhEngine::sub16E14() { unkFct_displayMenuBox_2(0); _textColor = 0xE; - displayCenteredString((char *)"Interaction", 24, 296, 152); + displayCenteredString("Interaction", 24, 296, 152); displayCenteredString(buffer, 24, 296, 161); setTextPos(24, 169); setTextColorWhite(); - displayStringAtTextPos((char *)"T"); + displayStringAtTextPos("T"); setTextColorRed(); sprintf(buffer, "alk to the %s", dest); displayStringAtTextPos(buffer); setTextPos(24, 178); setTextColorWhite(); - displayStringAtTextPos((char *)"A"); + displayStringAtTextPos("A"); setTextColorRed(); sprintf(buffer, "ttack the %s", dest); displayStringAtTextPos(buffer); setTextPos(198, 169); setTextColorWhite(); - displayStringAtTextPos((char *)"S"); + displayStringAtTextPos("S"); setTextColorRed(); - displayStringAtTextPos((char *)"tatus"); + displayStringAtTextPos("tatus"); setTextPos(198, 178); setTextColorWhite(); - displayStringAtTextPos((char *)"L"); + displayStringAtTextPos("L"); setTextColorRed(); - displayStringAtTextPos((char *)"eave"); + displayStringAtTextPos("eave"); if (var6C == 0) displayFctFullScreen(); } @@ -3933,7 +3945,7 @@ void EfhEngine::writeTechAndMapFiles() { warning("STUB - writeTechAndMapFiles"); } -uint16 EfhEngine::getStringWidth(char *buffer) { +uint16 EfhEngine::getStringWidth(const char *buffer) { uint16 retVal = 0; for (;;) { diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 39f9abc9936e..48ba285bf475 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -287,7 +287,7 @@ class EfhEngine : public Engine { Common::KeyCode handleAndMapInput(bool animFl); void displayNextAnimFrame(); void writeTechAndMapFiles(); - uint16 getStringWidth(char *buffer); + uint16 getStringWidth(const char *buffer); void setTextPos(int16 textPosX, int16 textPosY); void sub15150(bool flag); @@ -310,8 +310,8 @@ class EfhEngine : public Engine { Common::KeyCode getInput(int16 delay); void handleWinSequence(); bool giveItemTo(int16 charId, int16 objectId, int altCharId); - void drawString(char *str, int16 startX, int16 startY, uint16 unkFl); - void displayCenteredString(char *str, int16 minX, int16 maxX, int16 posY); + void drawString(const char *str, int16 startX, int16 startY, uint16 unkFl); + void displayCenteredString(const char *str, int16 minX, int16 maxX, int16 posY); int16 chooseCharacterToReplace(); int16 handleCharacterJoining(); void drawMapWindow(); @@ -330,7 +330,7 @@ class EfhEngine : public Engine { void drawChar(uint8 curChar, int16 posX, int posY); void setTextColorWhite(); void setTextColorRed(); - void setTextColor_08h(); + void setTextColorGrey(); bool isPosOutOfMap(int16 mapPosX, int16 mapPosY); void goSouth(); void goNorth(); @@ -347,7 +347,7 @@ class EfhEngine : public Engine { void computeMapAnimation(); void unkFct_anim(); void setNextCharacterPos(); - void displayStringAtTextPos(char *message); + void displayStringAtTextPos(const char *message); void unkFct_displayMenuBox_2(int16 color); int8 sub16B08(int16 monsterId); bool moveMonsterAwayFromTeam(int16 monsterId); @@ -377,7 +377,7 @@ class EfhEngine : public Engine { void unk_StatusMenu(int16 windowId, int16 menuId, int16 curMenuLine, int16 charId, bool unusedFl, bool refreshFl); void displayWindow(uint8 *buffer, int16 posX, int16 posY, uint8 *dest); void sub18E80(int16 charId, int16 windowId, int16 menuId, int16 curMenuLine); - int16 _guess_displayString_3(const char * str, int16 arg2, int16 charId, int16 windowId, int16 menuId, int16 curMenuLine); + int16 displayString_3(const char * str, bool animFl, int16 charId, int16 windowId, int16 menuId, int16 curMenuLine); bool isItemCursed(int16 itemId); bool hasObjectEquipped(int16 charId, int16 _objectId); void sub191FF(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine); @@ -481,7 +481,7 @@ class EfhEngine : public Engine { bool _word2C8D5; // CHECKME: always 0? bool _word2D0BC; bool _word2C8D2; - int16 _word2D0BE; + int16 _menuDepth; int16 _word2D0BA; int16 _word3273A[15]; From bc88c24707e69ed789a13511566bf249eb548dbb Mon Sep 17 00:00:00 2001 From: Strangerke Date: Thu, 9 Dec 2021 08:39:06 +0100 Subject: [PATCH 083/412] EFH: More work on status menu --- engines/efh/constants.cpp | 40 +++++ engines/efh/constants.h | 1 + engines/efh/efh.cpp | 302 +++++++++++++++++++++++++++++++++++--- engines/efh/efh.h | 14 +- 4 files changed, 333 insertions(+), 24 deletions(-) diff --git a/engines/efh/constants.cpp b/engines/efh/constants.cpp index 0547cbc14dab..2a9f580e07d7 100644 --- a/engines/efh/constants.cpp +++ b/engines/efh/constants.cpp @@ -344,4 +344,44 @@ const Encounter kEncounters[] { { "XXXXXXXXXXXXX", 0xFF, 0xFFFF, 0xFFFF, {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF}, 0, 0 } }; +const char kSkillArray[37][20] = { + "Flying", + "Swimming", + "Electrical", + "Mechanical", + "Hacking", + "Bluffing", + "Boatman", + "Pilot", + "Bureaucracy", + "Find Trap", + "Parachuting", + "Pick Lock", + "Explosives", + "Chemistry", + "Steal", + "Dueling", + "Marksmanship", + "Fist Fighting", + "Martial Arts", + "Acrobatics", + "Melee Weapon", + "Pistol Combat", + "Rifle Combat", + "Automatic/SMG", + "Archery", + "Rocket Lncher", + "Strength", + "Intelligence", + "Piety", + "Agility", + "Stamina", + "Stealth", + "Evasion", + "Comprehension", + "Perception", + "Psychic Force", + "Alignment" +}; + } // End of namespace Efh diff --git a/engines/efh/constants.h b/engines/efh/constants.h index 7b49ecdfdf04..6ade27d0447f 100644 --- a/engines/efh/constants.h +++ b/engines/efh/constants.h @@ -44,6 +44,7 @@ extern const uint8 kFontWidthArray[96]; extern const uint8 kFontExtraLinesArray[96]; extern const Font kFontData[96]; extern const Encounter kEncounters[]; +extern const char kSkillArray[37][20]; } // End of namespace Efh diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index e7f37939a78f..6e77bcd07125 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -216,6 +216,7 @@ EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst) for (int i = 0; i < 20; ++i) { _portraitSubFilesArray[i] = nullptr; _ennemyNamePt2[i] = 0; + _characterNamePt2[i] = 0; _nameBuffer[i] = 0; } @@ -538,7 +539,6 @@ void EfhEngine::loadNewPortrait() { } void EfhEngine::loadAnimImageSet() { - warning("STUB - loadAnimImageSet"); if (_currentAnimImageSetId == _animImageSetId || _animImageSetId == 0xFF) return; @@ -602,8 +602,8 @@ void EfhEngine::loadPlacesFile(uint16 fullPlaceId, bool forceReloadFl) { copyCurrentPlaceToBuffer(_fullPlaceId / 20); } -void EfhEngine::drawUnknownMenuBox() { - warning("STUB - drawUnknownMenuBox"); +void EfhEngine::drawLeftCenterBox() { + drawColoredRect(16, 8, 111, 135, 0); } void EfhEngine::displayAnimFrame() { @@ -640,7 +640,7 @@ void EfhEngine::displayAnimFrames(int16 animId, bool displayMenuBoxFl) { return; for (int i = 0; i < 2; ++i) { - drawUnknownMenuBox(); + drawLeftCenterBox(); displayAnimFrame(); if (i == 0) @@ -1065,7 +1065,7 @@ void EfhEngine::loadMapMonsters() { _mapMonsters[i]._field_9 = _mapMonstersPtr[29 * i + 9]; _mapMonsters[i]._groupSize = _mapMonstersPtr[29 * i + 10]; for (int j = 0; j < 9; ++j) - _mapMonsters[i]._pictureRef[j] = READ_LE_UINT16(&_mapMonstersPtr[29 * i + 11 + j * 2]); + _mapMonsters[i]._pictureRef[j] = READ_LE_INT16(&_mapMonstersPtr[29 * i + 11 + j * 2]); } } @@ -2855,9 +2855,196 @@ bool EfhEngine::checkPictureRefAvailability(int16 monsterId) { return false; } -bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 arg4) { - warning("STUB - sub21820"); - return false; +void EfhEngine::displayMonsterAnim(int16 monsterId) { + int16 animId = kEncounters[_mapMonsters[monsterId]._MonsterRef]._animId; + displayAnimFrames(animId, true); +} + +int16 EfhEngine::countPictureRef(int16 id, bool teamMemberFl) { + int16 count = 0; + int16 monsterId; + + if (teamMemberFl) + monsterId = _teamMonsterIdArray[id]; + else + monsterId = id; + + for (int16 counter = 0; counter < 9; ++counter) { + if (_mapMonsters[monsterId]._pictureRef[counter] > 0) + ++count; + } + + return count; +} + +bool EfhEngine::checkMonsterGroupDistance1OrLess(int16 monsterId) { + if (computeMonsterGroupDistance(monsterId) > 1) + return false; + + return true; +} + +bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { + char buffer[80]; + memset(buffer, 0, 80); + + int8 var51 = _mapMonsters[monsterId]._possessivePronounSHL6; + if (_mapMonsters[monsterId]._guess_fullPlaceId == 0xFF) + return false; + + if (countPictureRef(monsterId, false) < 1) + return false; + + if (!checkIfMonsterOnSameLargelMapPlace(monsterId)) + return false; + + if (!checkMonsterGroupDistance1OrLess(monsterId)) + return false; + + if (var51 != 0x3F) { + if (_mapMonsters[monsterId]._field_9 == 0xFF || arg2 != 5) { + return false; + } + displayMonsterAnim(monsterId); + sub22AA8(_mapMonsters[monsterId]._field_9); + displayAnimFrames(0xFE, true); + return true; + } + + if (isCharacterATeamMember(_mapMonsters[monsterId]._field_1)) + return false; + + int16 var58 = isCharacterATeamMember(_mapMonsters[monsterId]._field_1); + switch (_npcBuf[var58].field_10 - 0xEE) { + case 0: + if (arg2 == 4 && _npcBuf[var58].field_11 == itemId) { + displayMonsterAnim(monsterId); + sub22AA8(_npcBuf[var58].field_14); + displayAnimFrames(0xFE, true); + return true; + } + break; + case 1: + if (arg2 == 2 && _npcBuf[var58].field_11 == itemId) { + displayMonsterAnim(monsterId); + sub22AA8(_npcBuf[var58].field_14); + displayAnimFrames(0xFE, true); + return true; + } + break; + case 2: + if (arg2 == 1 && _npcBuf[var58].field_11 == itemId) { + displayMonsterAnim(monsterId); + sub22AA8(_npcBuf[var58].field_14); + displayAnimFrames(0xFE, true); + return true; + } + break; + case 3: + if (_history[_npcBuf[var58].field_11] != 0) { + displayMonsterAnim(monsterId); + sub22AA8(_npcBuf[var58].field_14); + displayAnimFrames(0xFE, true); + return true; + } + break; + case 4: + for (int16 counter = 0; counter < _teamSize; ++counter) { + for (int16 charId = 0; charId < 10; ++charId) { + if (_npcBuf[_teamCharId[counter]]._inventory[charId]._ref == _npcBuf[var58].field_11) { + removeObject(_teamCharId[counter], charId); + displayMonsterAnim(monsterId); + sub22AA8(_npcBuf[var58].field_14); + displayAnimFrames(0xFE, true); + return true; + } + } + } + break; + case 5: + if (arg2 == 2 && _npcBuf[var58].field_11 == itemId) { + displayMonsterAnim(monsterId); + sub22AA8(_npcBuf[var58].field_14); + displayAnimFrames(0xFE, true); + return true; + } + break; + case 6: + for (int16 counter = 0; counter < _teamSize; ++counter) { + for (int16 charId = 0; charId < 10; ++charId) { + if (_npcBuf[_teamCharId[counter]]._inventory[charId]._ref == _npcBuf[var58].field_11) { + displayMonsterAnim(monsterId); + sub22AA8(_npcBuf[var58].field_14); + displayAnimFrames(0xFE, true); + return true; + } + } + } + break; + case 7: + for (int16 counter = 0; counter < _teamSize; ++counter) { + if (_npcBuf[var58].field_11 == _teamCharId[counter]) { + removeCharacterFromTeam(counter); + displayMonsterAnim(monsterId); + sub22AA8(_npcBuf[var58].field_14); + displayAnimFrames(0xFE, true); + return true; + } + } + break; + case 8: + for (int16 counter = 0; counter < _teamSize; ++counter) { + if (_npcBuf[var58].field_11 == _teamCharId[counter]) { + displayMonsterAnim(monsterId); + copyString(_npcBuf[var58]._name, _ennemyNamePt2); + copyString(_npcBuf[_teamCharId[counter]]._name, _characterNamePt2); + sprintf(buffer, "%s asks that %s leave your party.", _ennemyNamePt2, _characterNamePt2); + for (int16 i = 0; i < 2; ++i) { + unkFct_displayMenuBox_2(0); + _textColor = 0xE; + displayCenteredString(buffer, 24, 296, 161); + setTextPos(24, 169); + displayStringAtTextPos("Will you do this?"); + if (i == 0) + displayFctFullScreen(); + } + setTextColorRed(); + Common::KeyCode input = mapInputCode(waitForKey()); + if (input == Common::KEYCODE_y) { + removeCharacterFromTeam(counter); + sub22AA8(_npcBuf[var58].field_14); + } + displayAnimFrames(0xFE, true); + return true; + } + } + break; + case 9: + for (int16 counter = 0; counter < _teamSize; ++counter) { + if (_npcBuf[var58].field_11 == _teamCharId[counter]) { + displayMonsterAnim(monsterId); + sub22AA8(_npcBuf[var58].field_14); + displayAnimFrames(0xFE, true); + return true; + } + } + break; + case 16: + displayMonsterAnim(monsterId); + sub22AA8(_npcBuf[var58].field_14); + displayAnimFrames(0xFE, true); + return true; + default: + break; + } + + if (_npcBuf[var58].field_12 == 0x7FFF || arg2 != 5) + return false; + + displayMonsterAnim(monsterId); + sub22AA8(_npcBuf[var58].field_12); + displayAnimFrames(0xFE, true); + return true; } void EfhEngine::sub221D2(int16 monsterId) { @@ -2867,11 +3054,11 @@ void EfhEngine::sub221D2(int16 monsterId) { } } -void EfhEngine::sub22AA8(uint16 arg0) { - warning("STUB - sub22AA8"); +void EfhEngine::sub22AA8(int16 arg0) { + warning("STUB: sub22AA8"); } -bool EfhEngine::sub22293(int16 mapPosX, int16 mapPosY, int16 arg4, int16 arg6, int16 arg8, int16 imageSetId) { +bool EfhEngine::sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemId, int16 arg8, int16 imageSetId) { int16 var8 = sub151FD(mapPosX, mapPosY); if (var8 == -1) { @@ -2921,7 +3108,7 @@ bool EfhEngine::sub22293(int16 mapPosX, int16 mapPosY, int16 arg4, int16 arg6, i if ((_mapUnknownPtr[var8 * 9 + 3] == 0xFA && arg8 == 1) || (_mapUnknownPtr[var8 * 9 + 3] == 0xFC && arg8 == 2) || (_mapUnknownPtr[var8 * 9 + 3] == 0xFB && arg8 == 3)) { - if (_mapUnknownPtr[var8 * 9 + 4] == arg6) { + if (_mapUnknownPtr[var8 * 9 + 4] == itemId) { sub22AA8(_mapUnknownPtr[var8 * 9 + 5]); return true; } @@ -2929,7 +3116,7 @@ bool EfhEngine::sub22293(int16 mapPosX, int16 mapPosY, int16 arg4, int16 arg6, i int16 var6 = _mapUnknownPtr[var8 * 9 + 3]; if (var6 >= 0x7B && var6 <= 0xEF) { var6 -= 0x78; - if (var6 >= 0 && var6 <= 0x8B && var6 == arg6 && _mapUnknownPtr[var8 * 9 + 4] <= _npcBuf[arg4]._activeScore[arg6]) { + if (var6 >= 0 && var6 <= 0x8B && var6 == itemId && _mapUnknownPtr[var8 * 9 + 4] <= _npcBuf[charId]._activeScore[itemId]) { sub22AA8(_mapUnknownPtr[var8 * 9 + 5]); return true; } @@ -2938,7 +3125,7 @@ bool EfhEngine::sub22293(int16 mapPosX, int16 mapPosY, int16 arg4, int16 arg6, i } for (int16 counter = 0; counter < 64; ++counter) { - if (!sub21820(counter, arg8, arg6)) + if (!sub21820(counter, arg8, itemId)) return true; } @@ -3035,15 +3222,92 @@ void EfhEngine::displayStatusMenu(int16 windowId) { } void EfhEngine::countRightWindowItems(int16 menuId, int16 charId) { - warning("STUB: countRightWindowItems"); + int16 var2 = 0; + int16 var4 = 0; + _word2D0BA = 0; + + switch (menuId) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 9: + var4 = -1; + break; + case 5: + var4 = 26; + var2 = 36; + break; + case 6: + var4 = 15; + var2 = 25; + break; + case 7: + var4 = 0; + var2 = 14; + break; + default: // Case 8 + Default + var4 = -1; + _word2D0BA = 0; + break; + } + + if (var4 == -1) { + for (int16 counter = 0; counter < 10; ++counter) { + if (_npcBuf[charId]._inventory[counter]._ref != 0x7FFF) { + _word3273A[_word2D0BA++] = counter; + } + } + } else { + for (int16 counter = var4; counter < var2; ++counter) { + if (_npcBuf[charId]._activeScore[counter] != 0) { + _word3273A[_word2D0BA++] = counter; + } + } + } } void EfhEngine::displayCharacterSummary(int16 curMenuLine, int16 npcId) { warning("STUB: displayCharacterSummary"); } -void EfhEngine::displayCharacterInformationOrSkills(int16 curMenuLine, int16 npcId) { - warning("STUB: displayCharacterInformationOrSkills"); +void EfhEngine::displayCharacterInformationOrSkills(int16 curMenuLine, int16 charId) { + char buffer[40]; + memset(buffer, 0, 40); + + setTextColorRed(); + copyString(_npcBuf[charId]._name, buffer); + setTextPos(146, 27); + displayStringAtTextPos("Name: "); + displayStringAtTextPos(buffer); + if (_word2D0BA <= 0) { + if (curMenuLine != -1) + setTextColorWhite(); + displayCenteredString("No Skills To Select", 144, 310, 96); + setTextColorRed(); + return; + } + + for (int16 counter = 0; counter < _word2D0BA; ++counter) { + if (counter == curMenuLine) + setTextColorWhite(); + int16 textPosY = 38 + counter * 9; + setTextPos(146, textPosY); + if (counter == curMenuLine) { + sprintf(buffer, "%c>", 'A' + counter); + } else { + sprintf(buffer, "%c)", 'A' + counter); + } + + displayStringAtTextPos(buffer); + setTextPos(163, textPosY); + displayStringAtTextPos(kSkillArray[_word3273A[counter]]); + sprintf(buffer, "%d", _npcBuf[charId]._activeScore[_word3273A[counter]]); + setTextPos(278, textPosY); + displayStringAtTextPos(buffer); + setTextColorRed(); + } } void EfhEngine::displayStatusMenuActions(int16 menuId, int16 curMenuLine, int16 npcId) { @@ -3488,7 +3752,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { bool var8 = sub22293(_mapPosX, _mapPosY, charId, objectId, 4, -1); if (var8) { _word2C8D2 = false; - return 0xFFFF; + return -1; } } break; @@ -3500,7 +3764,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { bool var8 = sub22293(_mapPosX, _mapPosY, charId, objectId, 4, -1); if (var8) { _word2C8D2 = false; - return 0xFFFF; + return -1; } } break; diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 48ba285bf475..9edd47afd375 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -199,7 +199,7 @@ struct MapMonster { uint8 _field_8; uint8 _field_9; uint8 _groupSize; - uint16 _pictureRef[9]; + int16 _pictureRef[9]; }; class EfhEngine : public Engine { @@ -250,7 +250,7 @@ class EfhEngine : public Engine { void loadHistory(); void loadTechMapImp(int16 fileId); void loadPlacesFile(uint16 fullPlaceId, bool forceReloadFl); - void drawUnknownMenuBox(); + void drawLeftCenterBox(); void displayAnimFrame(); void displayAnimFrames(int16 animId, bool displayMenuBoxFl); void readTileFact(); @@ -362,10 +362,13 @@ class EfhEngine : public Engine { bool checkMonsterWeaponRange(int16 monsterId); void sub174A0(); bool checkPictureRefAvailability(int16 monsterId); - bool sub21820(int16 monsterId, int16 arg2, int16 arg4); + void displayMonsterAnim(int16 monsterId); + int16 countPictureRef(int16 id, bool teamMemberFl); + bool checkMonsterGroupDistance1OrLess(int16 monsterId); + bool sub21820(int16 monsterId, int16 arg2, int16 itemId); void sub221D2(int16 monsterId); - void sub22AA8(uint16 arg0); - bool sub22293(int16 mapPosX, int16 mapPosY, int16 arg4, int16 arg6, int16 arg8, int16 imageSetId); + void sub22AA8(int16 arg0); + bool sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemId, int16 arg8, int16 imageSetId); int8 sub15581(int16 mapPosX, int16 mapPosY, int16 arg4); bool handleFight(int16 monsterId); void displayMenuItemString(int16 menuBoxId, int thisBoxId, int minX, int maxX, int minY, const char *str); @@ -414,6 +417,7 @@ class EfhEngine : public Engine { uint8 _history[256]; uint8 _techData[4096]; char _ennemyNamePt2[20]; + char _characterNamePt2[20]; char _nameBuffer[20]; uint8 _messageToBePrinted[400]; From a3cbeb5857aab23d7e8e6dde6e8af1bcb9429090 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Thu, 9 Dec 2021 23:28:51 +0100 Subject: [PATCH 084/412] EFH: Implement displayCharacterSummary --- engines/efh/efh.cpp | 155 +++++++++++++++++++++++++++++++++++++++++++- engines/efh/efh.h | 3 + 2 files changed, 155 insertions(+), 3 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 6e77bcd07125..0e51f7a0baae 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -3268,8 +3268,132 @@ void EfhEngine::countRightWindowItems(int16 menuId, int16 charId) { } } +int16 EfhEngine::getXPLevel(int32 xp) { + int16 level = 0; + int16 var6 = 1500; + + int32 wrkXp = xp; + + while (wrkXp > 0) { + wrkXp -= var6; + if (wrkXp >= 0) + ++level; + + var6 += 1500; + if (var6 > 15000) + var6 = 15000; + } + + return level; +} + +void EfhEngine::displayChar(char character) { + char buffer[2]; + buffer[0] = character; + buffer[1] = 0; + + drawString(buffer, _textPosX, _textPosY, _textColor); + _textPosX += getStringWidth(buffer) + 1; + setNextCharacterPos(); +} + void EfhEngine::displayCharacterSummary(int16 curMenuLine, int16 npcId) { - warning("STUB: displayCharacterSummary"); + char buffer1[40]; + char buffer2[40]; + memset(buffer1, 0, 40); + memset(buffer2, 0, 40); + + setTextColorRed(); + copyString(_npcBuf[npcId]._name, buffer1); + setTextPos(146, 27); + displayStringAtTextPos("Name: "); + displayStringAtTextPos(buffer1); + sprintf(buffer1, "Level: %d", getXPLevel(_npcBuf[npcId]._xp)); + setTextPos(146, 36); + displayStringAtTextPos(buffer1); + sprintf(buffer1, "XP: %lu", _npcBuf[npcId]._xp); + setTextPos(227, 36); + displayStringAtTextPos(buffer1); + sprintf(buffer1, "Speed: %d", _npcBuf[npcId]._speed); + setTextPos(146, 45); + displayStringAtTextPos(buffer1); + sprintf(buffer1, "Defense: %d", getEquipmentDefense(npcId, false)); + setTextPos(146, 54); + displayStringAtTextPos(buffer1); + sprintf(buffer1, "Hit Points: %d", _npcBuf[npcId]._hitPoints); + setTextPos(146, 63); + displayStringAtTextPos(buffer1); + sprintf(buffer1, "Max HP: %d", _npcBuf[npcId]._maxHP); + setTextPos(227, 63); + displayStringAtTextPos(buffer1); + displayCenteredString("Inventory", 144, 310, 72); + + if (_word2D0BA == 0) { + if (curMenuLine != -1) + setTextColorWhite(); + + displayCenteredString("Nothing Carried", 144, 310, 117); + setTextColorRed(); + return; + } + + for (int16 counter = 0; counter < _word2D0BA; ++counter) { + if (_menuDepth == 0) + setTextColorGrey(); + else { + if (counter == curMenuLine) + setTextColorWhite(); + } + int16 textPosY = 81 + counter * 9; + int16 itemId = _npcBuf[npcId]._inventory[_word3273A[counter]]._ref; + if (itemId != 0x7FFF) { + if (_npcBuf[npcId]._inventory[_word3273A[counter]]._stat1 & 0x80) { + setTextPos(146, textPosY); + displayChar('E'); + } + } + + setTextPos(152, textPosY); + if (counter == curMenuLine) { + sprintf(buffer1, "%c>", 'A' + counter); + } else { + sprintf(buffer1, "%c)", 'A' + counter); + } + displayStringAtTextPos(buffer1); + + if (itemId != 0x7FFF) { + setTextPos(168, textPosY); + copyString(_items[itemId]._name, buffer2); + sprintf(buffer1, " %s", buffer2); + displayStringAtTextPos(buffer1); + setTextPos(262, textPosY); + + if (_items[itemId]._defense > 0) { + int16 var54 = _npcBuf[npcId]._inventory[_word3273A[counter]]._stat2; + if (var54 == 0xFF) { + // useless? + var54 = _items[_npcBuf[npcId]._inventory[_word3273A[counter]]._ref]._defense; + } else { + sprintf(buffer1, "%d", 1 + var54 / 8); + displayStringAtTextPos(buffer1); + setTextPos(286, textPosY); + displayStringAtTextPos("Def"); + } + } else if (_items[itemId]._uses != 0x7F) { + int16 var52 = _npcBuf[npcId]._inventory[_word3273A[counter]]._stat1; + if (var52 != 0x7F) { + sprintf(buffer1, "%d", var52); + displayStringAtTextPos(buffer1); + setTextPos(286, textPosY); + if (var52 == 1) + displayStringAtTextPos("Use"); + else + displayStringAtTextPos("Uses"); + } + } + } + setTextColorRed(); + } } void EfhEngine::displayCharacterInformationOrSkills(int16 curMenuLine, int16 charId) { @@ -3425,8 +3549,33 @@ bool EfhEngine::hasObjectEquipped(int16 charId, int16 _objectId) { return true; } +void EfhEngine::equipCursedItem(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine) { + int16 itemId = _npcBuf[charId]._inventory[objectId]._ref; + + if (isItemCursed(itemId)) { + _npcBuf[charId]._inventory[objectId]._stat1 &= 0x7F; + } else { + displayString_3("Cursed Item Already Equipped!", true, charId, windowId, menuId, curMenuLine); + } + +} + void EfhEngine::sub191FF(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine) { - warning("STUB: sub191FF"); + int16 itemId = _npcBuf[charId]._inventory[objectId]._ref; + + if (hasObjectEquipped(charId, objectId)) { + equipCursedItem(charId, objectId, windowId, menuId, curMenuLine); + } else { + int16 var2 = _items[itemId].field_18; + if (var2 != 4) { + for (int16 counter = 0; counter < 10; ++counter) { + if (var2 != _items[_npcBuf[charId]._inventory[counter]._ref].field_18) + equipCursedItem(charId, objectId, windowId, menuId, curMenuLine); + } + } + + _npcBuf[charId]._inventory[objectId]._stat1 |= 0x80; + } } int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine, int16 argA) { @@ -3512,7 +3661,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { break; // case 0xFB: Joystick button 2 default: - warning("handleStatusMenu - unhandled keys 0xBA, 0xBB, 0xBC"); + // warning("handleStatusMenu - unhandled keys (or joystick event?) 0xBA, 0xBB, 0xBC"); break; } } else if (_menuDepth == 1) { diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 9edd47afd375..7fbe5ef54db2 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -374,6 +374,8 @@ class EfhEngine : public Engine { void displayMenuItemString(int16 menuBoxId, int thisBoxId, int minX, int maxX, int minY, const char *str); void displayStatusMenu(int16 windowId); void countRightWindowItems(int16 menuId, int16 charId); + int16 getXPLevel(int32 xp); + void displayChar(char character); void displayCharacterSummary(int16 curMenuLine, int16 npcId); void displayCharacterInformationOrSkills(int16 curMenuLine, int16 npcId); void displayStatusMenuActions(int16 menuId, int16 curMenuLine, int16 npcId); @@ -383,6 +385,7 @@ class EfhEngine : public Engine { int16 displayString_3(const char * str, bool animFl, int16 charId, int16 windowId, int16 menuId, int16 curMenuLine); bool isItemCursed(int16 itemId); bool hasObjectEquipped(int16 charId, int16 _objectId); + void equipCursedItem(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine); void sub191FF(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine); int16 sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine, int16 argA); bool getValidationFromUser(); From 902b1398ce0a527dcc28695f276a18ac6e13fda2 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Fri, 10 Dec 2021 09:02:40 +0100 Subject: [PATCH 085/412] EFH: Implement some stubs --- engines/efh/constants.cpp | 9 +++ engines/efh/constants.h | 1 + engines/efh/efh.cpp | 139 +++++++++++++++++++++++++++++++++++--- engines/efh/efh.h | 2 +- 4 files changed, 140 insertions(+), 11 deletions(-) diff --git a/engines/efh/constants.cpp b/engines/efh/constants.cpp index 2a9f580e07d7..0e94b67c90f6 100644 --- a/engines/efh/constants.cpp +++ b/engines/efh/constants.cpp @@ -384,4 +384,13 @@ const char kSkillArray[37][20] = { "Alignment" }; +const uint8 kByte2C7D0[60] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 2, 0, 2, 2, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + } // End of namespace Efh diff --git a/engines/efh/constants.h b/engines/efh/constants.h index 6ade27d0447f..4112f4ee4242 100644 --- a/engines/efh/constants.h +++ b/engines/efh/constants.h @@ -45,6 +45,7 @@ extern const uint8 kFontExtraLinesArray[96]; extern const Font kFontData[96]; extern const Encounter kEncounters[]; extern const char kSkillArray[37][20]; +extern const uint8 kByte2C7D0[60]; } // End of namespace Efh diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 0e51f7a0baae..aa94a0ea44c8 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -1446,7 +1446,22 @@ int16 EfhEngine::getRandom(int16 maxVal) { } void EfhEngine::removeCharacterFromTeam(int16 teamMemberId) { - warning("STUB - removeCharacterFromTeam"); + int16 charId = _teamCharId[teamMemberId]; + _npcBuf[charId].field_12 = _npcBuf[charId].field_B; + _npcBuf[charId].field_14 = _npcBuf[charId].field_E; + _npcBuf[charId].field_10 = _npcBuf[charId].field_C; + _npcBuf[charId].field_11 = _npcBuf[charId].field_D; + + _teamCharId[teamMemberId] = -1; + _teamCharStatus[teamMemberId]._status = 0; + _teamCharStatus[teamMemberId]._duration = 0; + + for (int16 var4 = teamMemberId; var4 < 2; ++var4) { + _teamCharId[var4] = _teamCharId[var4 + 1]; + _teamCharId[var4 + 1] = -1; + } + + refreshTeamSize(); } void EfhEngine::emptyFunction(int i) { @@ -1560,7 +1575,22 @@ void EfhEngine::handleWinSequence() { } bool EfhEngine::giveItemTo(int16 charId, int16 objectId, int altCharId) { - warning("STUB - giveItemTo"); + for (int16 newObjectId = 0; newObjectId < 10; ++newObjectId) { + if (_npcBuf[charId]._inventory[newObjectId]._ref != 0x7FFF) + continue; + + if (altCharId == 0xFF) { + _npcBuf[charId]._inventory[newObjectId]._ref = objectId; + _npcBuf[charId]._inventory[newObjectId]._stat2 = _items[objectId]._defense; + _npcBuf[charId]._inventory[newObjectId]._stat1 = _items[objectId]._uses; + } else { + _npcBuf[charId]._inventory[newObjectId]._ref = _npcBuf[altCharId]._inventory[newObjectId]._ref; + _npcBuf[charId]._inventory[newObjectId]._stat2 = _npcBuf[altCharId]._inventory[newObjectId]._stat2; + _npcBuf[charId]._inventory[newObjectId]._stat1 = _npcBuf[altCharId]._inventory[newObjectId]._stat1 & 0x7F; + } + + return true; + } return false; } @@ -1990,7 +2020,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, drawMapWindow(); displayFctFullScreen(); drawMapWindow(); - var110 = sub1C219("Nothing...", 1, 2, 0xFFFF); + var110 = sub1C219((char *)"Nothing...", 1, 2, true); displayFctFullScreen(); } else { copyString(_npcBuf[_teamCharId[counter]]._name, _ennemyNamePt2); @@ -1999,7 +2029,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, drawMapWindow(); displayFctFullScreen(); drawMapWindow(); - var110 = sub1C219(dest, 1, 2, 0xFFFF); + var110 = sub1C219(dest, 1, 2, true); displayFctFullScreen(); } @@ -2161,17 +2191,106 @@ void EfhEngine::sub15A28(int16 arg0, int16 arg2) { warning("STUB: sub15A28"); } -void EfhEngine::sub2455E(int16 arg0, int16 arg1, int16 arg2) { - warning("STUB: sub2455E"); +void EfhEngine::sub2455E(int16 arg0, int16 arg2, int16 arg4) { + warning("TODO: sub2455E - check behavior"); + uint8 varD = kByte2C7D0[arg0]; + int16 varC = arg2 - 11; + int16 varA = arg4 - 11; + + if (varC < 0) + varC = 0; + + if (varA < 0) + varA = 0; + + int16 var8 = varC + 23; + int16 var6 = varA + 23; + + for (int16 var4 = varC; var4 <= var8; ++var4) { + for (int16 var2 = varA; var2 <= var6; ++var2) { + _techData[var2 + var4 * 64] = varD; + } + } } -int16 EfhEngine::sub1C219(const char *str, int menuType, int arg4, int displayTeamWindowFl) { - warning("STUB: sub1C219"); - return -1; +int16 EfhEngine::sub1C219(char *str, int menuType, int arg4, bool displayTeamWindowFl) { + int16 varA = 0xFF; + int16 minX, maxX, minY, maxY; + + switch (menuType) { + case 0: + minX = 129; + minY = 9; + maxX = 302; + maxY = 18; + break; + case 1: + minX = 129; + minY = 9; + maxX = 302; + maxY = 110; + break; + case 2: + minX = 129; + minY = 112; + maxX = 302; + maxY = 132; + break; + case 3: + minX = 129; + minY = 79; + maxX = 303; + maxY = 107; + break; + default: + minX = minY = 0; + maxX = 320; + maxY = 200; + break; + } + + drawColoredRect(minX, maxX, minY, maxY, 0); + if (str) + varA = script_parse((uint8 *)str, minX, minY, maxX, maxY, -1); + + if (displayTeamWindowFl) + displayLowStatusScreen(false); + + if (arg4 != 0) { + displayFctFullScreen(); + if (_word2C87A != 0) + _word2C87A = 0; + else { + drawColoredRect(minX, maxX, minY, maxY, 0); + if (str) + int16 varC = script_parse((uint8 *)str, minX, minY, maxX, maxY, -1); + } + + if (displayTeamWindowFl) + displayLowStatusScreen(false); + + if (arg4 >= 2) + int16 varC = getLastCharAfterAnimCount(_guessAnimationAmount); + + if (arg4 == 3) + drawColoredRect(minX, maxX, minY, maxY, 0); + } + + return varA; } int16 EfhEngine::sub151FD(int16 posX, int16 posY) { - warning("STUB: sub151FD"); + if (_largeMapFlag) { + for (int16 counter = 0; counter < 100; ++counter) { + if (_mapUnknownPtr[counter * 9 + 1] == posX && _mapUnknownPtr[counter * 9 + 2] == posY && _mapUnknownPtr[counter * 9] == 0xFE) + return counter; + } + } else { + for (int16 counter = 0; counter < 100; ++counter) { + if (_mapUnknownPtr[counter * 9 + 1] == posX && _mapUnknownPtr[counter * 9 + 2] == posY && _mapUnknownPtr[counter * 9] == _fullPlaceId) + return counter; + } + } return -1; } diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 7fbe5ef54db2..3e07c01af275 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -325,7 +325,7 @@ class EfhEngine : public Engine { void drawBottomBorders(); void sub15A28(int16 arg0, int16 arg2); void sub2455E(int16 arg0, int16 arg1, int16 arg2); - int16 sub1C219(const char *str, int menuType, int arg4, int displayTeamWindowFl); + int16 sub1C219(char *str, int menuType, int arg4, bool displayTeamWindowFl); int16 sub151FD(int16 posX, int16 posY); void drawChar(uint8 curChar, int16 posX, int posY); void setTextColorWhite(); From 6357fd7b6664fc0b4b476f7ec30fc332883536ed Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sat, 11 Dec 2021 01:00:39 +0100 Subject: [PATCH 086/412] EFH: Implement sub22AA8, refactor _mapUnknownPtr --- engines/efh/efh.cpp | 247 ++++++++++++++++++++++++++++++++++---------- engines/efh/efh.h | 18 +++- 2 files changed, 206 insertions(+), 59 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index aa94a0ea44c8..3c15a5070d28 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -65,6 +65,11 @@ void InvObject::init() { _stat2 = 0; } +void UnkMapStruct::init() { + _field0 = _field1 = _field2 = _field3 = _field4 = 0; + _field5 = _field7 = 0; +} + void UnkAnimStruct::init() { field0 = field1 = field2 = field3 = 0; } @@ -178,8 +183,6 @@ EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst) _videoMode = 0; _graphicsStruct = nullptr; _mapBitmapRef = nullptr; - _mapUnknownPtr = nullptr; - _mapMonstersPtr = nullptr; _mapGameMapPtr = nullptr; _defaultBoxColor = 0; @@ -220,8 +223,10 @@ EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst) _nameBuffer[i] = 0; } - for (int i = 0; i < 100; ++i) + for (int i = 0; i < 100; ++i) { _imp1PtrArray[i] = nullptr; + _mapUnknown[i].init(); + } for (int i = 0; i < 432; ++i) _imp2PtrArray[i] = nullptr; @@ -928,7 +933,6 @@ void EfhEngine::initEngine() { memset(_techData, 0, sizeof(_techData)); _mapBitmapRef = &_map[0]; - _mapUnknownPtr = &_map[2]; // Replaces _mapMonstersPtr which was equal to &_map[902]; for (int i = 0; i < 64; ++i) { @@ -1050,22 +1054,34 @@ void EfhEngine::initMapMonsters() { } void EfhEngine::loadMapMonsters() { - _mapMonstersPtr = &_map[902]; + uint8 *_mapUnknownPtr = &_map[2]; + + for (int i = 0; i < 100; ++i) { + _mapUnknown[i]._field0 = _mapUnknownPtr[9 * i]; + _mapUnknown[i]._field1 = _mapUnknownPtr[9 * i + 1]; + _mapUnknown[i]._field2 = _mapUnknownPtr[9 * i + 2]; + _mapUnknown[i]._field3 = _mapUnknownPtr[9 * i + 3]; + _mapUnknown[i]._field4 = _mapUnknownPtr[9 * i + 4]; + _mapUnknown[i]._field5 = READ_LE_UINT16(&_mapUnknownPtr[9 * i + 5]); + _mapUnknown[i]._field7 = READ_LE_UINT16(&_mapUnknownPtr[9 * i + 7]); + } + + uint8 *mapMonstersPtr = &_map[902]; for (int i = 0; i < 64; ++i) { - _mapMonsters[i]._possessivePronounSHL6 = _mapMonstersPtr[29 * i]; - _mapMonsters[i]._field_1 = _mapMonstersPtr[29 * i + 1]; - _mapMonsters[i]._guess_fullPlaceId = _mapMonstersPtr[29 * i + 2]; - _mapMonsters[i]._posX = _mapMonstersPtr[29 * i + 3]; - _mapMonsters[i]._posY = _mapMonstersPtr[29 * i + 4]; - _mapMonsters[i]._itemId_Weapon = _mapMonstersPtr[29 * i + 5]; - _mapMonsters[i]._field_6 = _mapMonstersPtr[29 * i + 6]; - _mapMonsters[i]._MonsterRef = _mapMonstersPtr[29 * i + 7]; - _mapMonsters[i]._field_8 = _mapMonstersPtr[29 * i + 8]; - _mapMonsters[i]._field_9 = _mapMonstersPtr[29 * i + 9]; - _mapMonsters[i]._groupSize = _mapMonstersPtr[29 * i + 10]; + _mapMonsters[i]._possessivePronounSHL6 = mapMonstersPtr[29 * i]; + _mapMonsters[i]._field_1 = mapMonstersPtr[29 * i + 1]; + _mapMonsters[i]._guess_fullPlaceId = mapMonstersPtr[29 * i + 2]; + _mapMonsters[i]._posX = mapMonstersPtr[29 * i + 3]; + _mapMonsters[i]._posY = mapMonstersPtr[29 * i + 4]; + _mapMonsters[i]._itemId_Weapon = mapMonstersPtr[29 * i + 5]; + _mapMonsters[i]._field_6 = mapMonstersPtr[29 * i + 6]; + _mapMonsters[i]._MonsterRef = mapMonstersPtr[29 * i + 7]; + _mapMonsters[i]._field_8 = mapMonstersPtr[29 * i + 8]; + _mapMonsters[i]._field_9 = mapMonstersPtr[29 * i + 9]; + _mapMonsters[i]._groupSize = mapMonstersPtr[29 * i + 10]; for (int j = 0; j < 9; ++j) - _mapMonsters[i]._pictureRef[j] = READ_LE_INT16(&_mapMonstersPtr[29 * i + 11 + j * 2]); + _mapMonsters[i]._pictureRef[j] = READ_LE_INT16(&mapMonstersPtr[29 * i + 11 + j * 2]); } } @@ -1949,7 +1965,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, if (argC != 0) { int16 var110 = sub151FD(_mapPosX, _mapPosY); if (var110 != -1) - _mapUnknownPtr[9 * var110 + 1] = 0xFF; + _mapUnknown[var110]._field1 = 0xFF; } break; case 0x13: @@ -2020,7 +2036,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, drawMapWindow(); displayFctFullScreen(); drawMapWindow(); - var110 = sub1C219((char *)"Nothing...", 1, 2, true); + var110 = sub1C219((uint8 *)"Nothing...", 1, 2, true); displayFctFullScreen(); } else { copyString(_npcBuf[_teamCharId[counter]]._name, _ennemyNamePt2); @@ -2029,13 +2045,13 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, drawMapWindow(); displayFctFullScreen(); drawMapWindow(); - var110 = sub1C219(dest, 1, 2, true); + var110 = sub1C219((uint8 *)dest, 1, 2, true); displayFctFullScreen(); } var110 = sub151FD(_mapPosX, _mapPosY); if (var110 != -1) { - _mapUnknownPtr[var110 * 9 + 1] = 0xFF; + _mapUnknown[var110]._field1 = 0xFF; } _redrawNeededFl = true; } @@ -2055,7 +2071,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, if (argC != 0) { int16 var110 = sub151FD(scriptNumberArray[0], scriptNumberArray[1]); if (var110 != -1) { - _mapUnknownPtr[9 * var110 + 1] = 0xFF; + _mapUnknown[var110]._field1 = 0xFF; } } break; @@ -2064,10 +2080,10 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, if (argC != 0) { int16 var110 = sub151FD(scriptNumberArray[0], scriptNumberArray[1]); if (var110 != -1) { - _mapUnknownPtr[9 * var110 + 1] = 0xFF; + _mapUnknown[var110]._field1 = 0xFF; } - _mapUnknownPtr[9 * scriptNumberArray[2] + 1] = scriptNumberArray[0]; - _mapUnknownPtr[9 * scriptNumberArray[2] + 2] = scriptNumberArray[1]; + _mapUnknown[scriptNumberArray[2]]._field1 = scriptNumberArray[0]; + _mapUnknown[scriptNumberArray[2]]._field2 = scriptNumberArray[1]; } break; case 0x1C: @@ -2213,7 +2229,7 @@ void EfhEngine::sub2455E(int16 arg0, int16 arg2, int16 arg4) { } } -int16 EfhEngine::sub1C219(char *str, int menuType, int arg4, bool displayTeamWindowFl) { +int16 EfhEngine::sub1C219(uint8 *str, int menuType, int arg4, bool displayTeamWindowFl) { int16 varA = 0xFF; int16 minX, maxX, minY, maxY; @@ -2251,7 +2267,7 @@ int16 EfhEngine::sub1C219(char *str, int menuType, int arg4, bool displayTeamWin drawColoredRect(minX, maxX, minY, maxY, 0); if (str) - varA = script_parse((uint8 *)str, minX, minY, maxX, maxY, -1); + varA = script_parse(str, minX, minY, maxX, maxY, -1); if (displayTeamWindowFl) displayLowStatusScreen(false); @@ -2263,7 +2279,7 @@ int16 EfhEngine::sub1C219(char *str, int menuType, int arg4, bool displayTeamWin else { drawColoredRect(minX, maxX, minY, maxY, 0); if (str) - int16 varC = script_parse((uint8 *)str, minX, minY, maxX, maxY, -1); + int16 varC = script_parse(str, minX, minY, maxX, maxY, -1); } if (displayTeamWindowFl) @@ -2282,12 +2298,12 @@ int16 EfhEngine::sub1C219(char *str, int menuType, int arg4, bool displayTeamWin int16 EfhEngine::sub151FD(int16 posX, int16 posY) { if (_largeMapFlag) { for (int16 counter = 0; counter < 100; ++counter) { - if (_mapUnknownPtr[counter * 9 + 1] == posX && _mapUnknownPtr[counter * 9 + 2] == posY && _mapUnknownPtr[counter * 9] == 0xFE) + if (_mapUnknown[counter]._field1 == posX && _mapUnknown[counter]._field2 == posY && _mapUnknown[counter]._field0 == 0xFE) return counter; } } else { for (int16 counter = 0; counter < 100; ++counter) { - if (_mapUnknownPtr[counter * 9 + 1] == posX && _mapUnknownPtr[counter * 9 + 2] == posY && _mapUnknownPtr[counter * 9] == _fullPlaceId) + if (_mapUnknown[counter]._field1 == posX && _mapUnknown[counter]._field2 == posY && _mapUnknown[counter]._field0 == _fullPlaceId) return counter; } } @@ -3173,8 +3189,130 @@ void EfhEngine::sub221D2(int16 monsterId) { } } +Common::KeyCode EfhEngine::getInputBlocking() { + // The original checks for the joystick input + Common::Event event; + _system->getEventManager()->pollEvent(event); + Common::KeyCode retVal = Common::KEYCODE_INVALID; + + uint32 lastMs = _system->getMillis(); + while (retVal == Common::KEYCODE_INVALID) { + if (event.type == Common::EVENT_KEYUP) { + retVal = event.kbd.keycode; + } + + _system->delayMillis(20); + uint32 newMs = _system->getMillis(); + + if (newMs - lastMs >= 220) { + lastMs = newMs; + unkFct_anim(); + } + } + return retVal; +} + void EfhEngine::sub22AA8(int16 arg0) { - warning("STUB: sub22AA8"); + int16 var8, varA, varC, varE; + var8 = varA = varC = varE = 0; + + if (arg0 <= 0xFE) { + if (_dword2C856) { + _dword2C856 = nullptr; + sub221FA(_dword2C856, true); + } + if (_word2C8D2) + sub15150(true); + + int16 var4 = arg0; + + for (;;) { + uint8 *var12 = nullptr; + if (var4 >= 0 && var4 <= 0xFE) { + var12 = _imp1PtrArray[var4]; + } + + var4 = 0xFF; + if (var12 == nullptr) + break; + + do { + if (varE == 0) + memset(_messageToBePrinted, 0, 400); + switch (*var12) { + case 0x00: + case 0x0A: + break; + case 0x0D: + case 0x20: + _messageToBePrinted[varE++] = 0x20; + if (++varC >= 350) { + _messageToBePrinted[varE] = 0; + var8 = -1; + } + break; + case 0x40: + case 0x60: + varA = -1; + break; + case 0x7C: + _messageToBePrinted[varE++] = 0x7C; + varC += 20; + if (varC >= 350) { + _messageToBePrinted[varE] = 0; + var8 = -1; + } + break; + case 0x7E: + var8 = -1; + break; + default: + break; + } + var12 += 1; + int16 var2; + if (var8 != 0 || varA != 0) { + var8 = 0; + _messageToBePrinted[varE] = 0; + varE = 0; + varC = 0; + if (*_messageToBePrinted == 0x5E || *_messageToBePrinted == 0) { + if (*_messageToBePrinted == 0x5E) { + var2 = script_parse(_messageToBePrinted, 0, 0, 319, 199, true); + _word2C87A = false; + } + } else { + for (int16 counter = 0; counter < 2; ++counter) { + drawMapWindow(); + if (counter == 0) + displayFctFullScreen(); + } + + var2 = sub1C219(_messageToBePrinted, 1, 1, true); + if (var2 != 0xFF) + var4 = var2; + + if (var4 != 0xFFFF) { + for (int16 counter = 0; counter < 2; ++counter) { + if (varA) { + displayCenteredString("[DONE]", 128, 303, 117); + } else { + displayCenteredString("[MORE]", 128, 303, 117); + } + if (counter == 0) + displayFctFullScreen(); + } + getInputBlocking(); + } + } + if (var2 != 0xFF) + var4 = var2; + } + } while (var4 != -1 && var4 != 0xFF); + } + } + + displayAnimFrames(0xFE, true); } bool EfhEngine::sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemId, int16 arg8, int16 imageSetId) { @@ -3184,59 +3322,57 @@ bool EfhEngine::sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemI if (imageSetId != -1 && *_imp2PtrArray[imageSetId] != 0x30) sub221FA(_imp2PtrArray[imageSetId], true); } else if (var8 == 0) { - if (_mapUnknownPtr[var8 * 9 + 3] == 0xFF) { - sub22AA8(_mapUnknownPtr[var8 * 9 + 5]); // word! + if (_mapUnknown[var8]._field3 == 0xFF) { + sub22AA8(_mapUnknown[var8]._field5); // word! return true; - } else if (_mapUnknownPtr[var8 * 9 + 3] == 0xFE) { + } else if (_mapUnknown[var8]._field3 == 0xFE) { for (int16 counter = 0; counter < _teamSize; ++counter) { if (_teamCharId[counter] == -1) continue; - if (_teamCharId[counter] == _mapUnknownPtr[var8 * 9 + 4]) { - sub22AA8(_mapUnknownPtr[var8 * 9 + 5]); + if (_teamCharId[counter] == _mapUnknown[var8]._field4) { + sub22AA8(_mapUnknown[var8]._field5); return true; } } - } else if (_mapUnknownPtr[var8 * 9 + 3] == 0xFD) { + } else if (_mapUnknown[var8]._field3 == 0xFD) { for (int16 counter = 0; counter < _teamSize; ++counter) { if (_teamCharId[counter] == -1) continue; for (int16 var2 = 0; var2 < 10; ++var2) { - if (_npcBuf[_teamCharId[counter]]._inventory[var2]._ref == _mapUnknownPtr[var8 * 9 + 4]) { - sub22AA8(_mapUnknownPtr[var8 * 9 + 5]); + if (_npcBuf[_teamCharId[counter]]._inventory[var2]._ref == _mapUnknown[var8]._field4) { + sub22AA8(_mapUnknown[var8]._field5); return true; } } } // original makes a useless check on (_mapUnknownPtr[var8 * 9 + 3] > 0x7F) - } else if (_mapUnknownPtr[var8 * 9 + 3] <= 0x77) { - int16 var6 = _mapUnknownPtr[var8 * 9 + 3]; + } else if (_mapUnknown[var8]._field3 <= 0x77) { + int16 var6 = _mapUnknown[var8]._field3; for (int counter = 0; counter < _teamSize; ++counter) { if (_teamCharId[counter] == -1) continue; for (int16 var2 = 0; var2 < 39; ++var2) { - if (_npcBuf[_teamCharId[counter]]._activeScore[var2] >= _mapUnknownPtr[var8 * 9 + 4]) { - sub22AA8(_mapUnknownPtr[var8 * 9 + 5]); + if (_npcBuf[_teamCharId[counter]]._activeScore[var2] >= _mapUnknown[var8]._field4) { + sub22AA8(_mapUnknown[var8]._field5); return true; } } } } } else { - if ((_mapUnknownPtr[var8 * 9 + 3] == 0xFA && arg8 == 1) - || (_mapUnknownPtr[var8 * 9 + 3] == 0xFC && arg8 == 2) - || (_mapUnknownPtr[var8 * 9 + 3] == 0xFB && arg8 == 3)) { - if (_mapUnknownPtr[var8 * 9 + 4] == itemId) { - sub22AA8(_mapUnknownPtr[var8 * 9 + 5]); + if ((_mapUnknown[var8]._field3 == 0xFA && arg8 == 1) || (_mapUnknown[var8]._field3 == 0xFC && arg8 == 2) || (_mapUnknown[var8]._field3 == 0xFB && arg8 == 3)) { + if (_mapUnknown[var8]._field4 == itemId) { + sub22AA8(_mapUnknown[var8]._field5); return true; } } else if (arg8 == 4) { - int16 var6 = _mapUnknownPtr[var8 * 9 + 3]; + int16 var6 = _mapUnknown[var8]._field3; if (var6 >= 0x7B && var6 <= 0xEF) { var6 -= 0x78; - if (var6 >= 0 && var6 <= 0x8B && var6 == itemId && _mapUnknownPtr[var8 * 9 + 4] <= _npcBuf[charId]._activeScore[itemId]) { - sub22AA8(_mapUnknownPtr[var8 * 9 + 5]); + if (var6 >= 0 && var6 <= 0x8B && var6 == itemId && _mapUnknown[var8]._field4 <= _npcBuf[charId]._activeScore[itemId]) { + sub22AA8(_mapUnknown[var8]._field5); return true; } } @@ -3248,13 +3384,12 @@ bool EfhEngine::sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemI return true; } - if ((arg8 == 4 && _mapUnknownPtr[var8 * 9 + 3] < 0xFA) || arg8 != 4) { - if (_mapUnknownPtr[var8 * 9 + 7] > 0xFE) // word!! + if ((arg8 == 4 && _mapUnknown[var8]._field3 < 0xFA) || arg8 != 4) { + if (_mapUnknown[var8]._field7 > 0xFE) return false; - sub22AA8(_mapUnknownPtr[var8 * 9 + 7]); + sub22AA8(_mapUnknown[var8]._field7); return true; - } else - return false; + } return false; } diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 3e07c01af275..cb33cdc8cf45 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -79,6 +79,18 @@ struct InvObject { void init(); }; +struct UnkMapStruct { + uint8 _field0; + uint8 _field1; + uint8 _field2; + uint8 _field3; + uint8 _field4; + uint16 _field5; + uint16 _field7; + + void init(); +}; + struct UnkAnimStruct { uint8 field0; uint8 field1; @@ -325,7 +337,7 @@ class EfhEngine : public Engine { void drawBottomBorders(); void sub15A28(int16 arg0, int16 arg2); void sub2455E(int16 arg0, int16 arg1, int16 arg2); - int16 sub1C219(char *str, int menuType, int arg4, bool displayTeamWindowFl); + int16 sub1C219(uint8 *str, int menuType, int arg4, bool displayTeamWindowFl); int16 sub151FD(int16 posX, int16 posY); void drawChar(uint8 curChar, int16 posX, int posY); void setTextColorWhite(); @@ -367,6 +379,7 @@ class EfhEngine : public Engine { bool checkMonsterGroupDistance1OrLess(int16 monsterId); bool sub21820(int16 monsterId, int16 arg2, int16 itemId); void sub221D2(int16 monsterId); + Common::KeyCode getInputBlocking(); void sub22AA8(int16 arg0); bool sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemId, int16 arg8, int16 imageSetId); int8 sub15581(int16 mapPosX, int16 mapPosY, int16 arg4); @@ -425,8 +438,7 @@ class EfhEngine : public Engine { uint8 _messageToBePrinted[400]; uint8 *_mapBitmapRef; - uint8 *_mapUnknownPtr; - uint8 *_mapMonstersPtr; + UnkMapStruct _mapUnknown[100]; MapMonster _mapMonsters[64]; uint8 *_mapGameMapPtr; From c6ae134051f6e5f6071365705a18f863704b60e9 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sun, 12 Dec 2021 19:47:04 +0100 Subject: [PATCH 087/412] EFH: Implement object manipulation (sub19E2E), move some functions to graphics and utils --- engines/efh/efh.cpp | 1228 +++++++++++++++++++------------------- engines/efh/efh.h | 111 ++-- engines/efh/graphics.cpp | 346 +++++++++++ engines/efh/module.mk | 2 + engines/efh/utils.cpp | 318 ++++++++++ 5 files changed, 1348 insertions(+), 657 deletions(-) create mode 100644 engines/efh/graphics.cpp create mode 100644 engines/efh/utils.cpp diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 3c15a5070d28..2dde75fa0b35 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -26,7 +26,6 @@ #include "common/config-manager.h" #include "common/events.h" #include "engines/util.h" -#include "graphics/palette.h" #include "efh/efh.h" #include "efh/constants.h" @@ -159,6 +158,13 @@ void NPCStruct::init() { field_85 = 0; } +void Stru32686::init() { + for (int i = 0; i < 9; ++i) { + _field0[i] = 0; + _field2[i] = 0; + } +} + EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst), _gameDescription(gd) { const Common::FSNode gameDataDir(ConfMan.get("path")); @@ -247,11 +253,15 @@ EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst) _teamCharStatus[i]._status = 0; _teamCharStatus[i]._duration = 0; _unkArray2C8AA[i] = 0; + _word32680[i] = 0; + _word32482[i] = 0; } - for (int i = 0; i < 5; ++i) + for (int i = 0; i < 5; ++i) { _teamMonsterIdArray[i] = -1; - + _stru32686[i].init(); + } + _unkArray2C8AA[2] = 1; _teamSize = 1; _word2C872 = 0; @@ -313,30 +323,6 @@ Common::Platform EfhEngine::getPlatform() const { return _platform; } -void EfhEngine::initPalette() { - const uint8 pal[3 * 16] = { - 0, 0, 0, - 0, 0, 170, - 0, 170, 0, - 0, 170, 170, - 170, 0, 0, - 170, 0, 170, - 170, 85, 0, - 170, 170, 170, - 85, 85, 85, - 85, 85, 255, - 1, 1, 1, - 85, 255, 255, - 255, 85, 85, - 255, 85, 255, - 255, 255, 85, - 255, 255, 255 - }; - - _system->getPaletteManager()->setPalette(pal, 0, 16); - _system->updateScreen(); -} - Common::Error EfhEngine::run() { s_Engine = this; initialize(); @@ -482,16 +468,6 @@ void EfhEngine::initialize() { _shouldQuit = false; } -int32 EfhEngine::readFileToBuffer(Common::String &filename, uint8 *destBuffer) { - Common::File f; - if (!f.open(filename)) - error("Unable to find file %s", filename.c_str()); - - int size = f.size(); - - return f.read(destBuffer, size); -} - void EfhEngine::readAnimInfo() { Common::String fileName = "animinfo"; uint8 animInfoBuf[9000]; @@ -607,52 +583,6 @@ void EfhEngine::loadPlacesFile(uint16 fullPlaceId, bool forceReloadFl) { copyCurrentPlaceToBuffer(_fullPlaceId / 20); } -void EfhEngine::drawLeftCenterBox() { - drawColoredRect(16, 8, 111, 135, 0); -} - -void EfhEngine::displayAnimFrame() { - // The original had a parameter. As it was always equal to zero, it was removed in ScummVM - - if (_animImageSetId == 0xFF) - return; - - if (_animImageSetId == 0xFE) { - displayRawDataAtPos(_portraitSubFilesArray[0], 16, 8); - return; - } - - displayRawDataAtPos(_portraitSubFilesArray[0], 16, 8); - for (int i = 0; i < 4; ++i) { - int16 var2 = _animInfo[_animImageSetId]._unkAnimArray[_unkAnimRelatedIndex].field0; - if (var2 == 0xFF) - continue; - displayRawDataAtPos(_portraitSubFilesArray[var2 + 1], _animInfo[_animImageSetId]._field46_startX[var2] + 16, _animInfo[_animImageSetId]._field3C_startY[var2] + 8); - } -} - -void EfhEngine::displayAnimFrames(int16 animId, bool displayMenuBoxFl) { - if (animId == 0xFF) - return; - - _animImageSetId = animId; - if (_animImageSetId == 0xFE) - loadNewPortrait(); - else - loadAnimImageSet(); - - if (!displayMenuBoxFl) - return; - - for (int i = 0; i < 2; ++i) { - drawLeftCenterBox(); - displayAnimFrame(); - - if (i == 0) - displayFctFullScreen(); - } -} - void EfhEngine::readTileFact() { Common::String fileName = "tilefact"; readFileToBuffer(fileName, _tileFact); @@ -754,15 +684,6 @@ void EfhEngine::loadNPCS() { } } -void EfhEngine::setDefaultNoteDuration() { - // Original implementation is based on the int1C, which is triggered at 18.2065Hz. - // Every 4 times, it sets a flag (thus, approx every 220ms) - // The function was checking the keyboard in a loop, incrementing a counter and setting the last character read - // The "_defaultNoteDuration" was then set to 7 times this counter - // - // No implementation required in ScummVM -} - Common::KeyCode EfhEngine::playSong(uint8 *buffer) { warning("STUB: playSong"); _system->delayMillis(1000); @@ -770,42 +691,6 @@ Common::KeyCode EfhEngine::playSong(uint8 *buffer) { return Common::KEYCODE_INVALID; } -void EfhEngine::decryptImpFile(bool techMapFl) { - uint16 counter = 0; - uint16 target; - uint8 *curPtr; - - if (!techMapFl) { - _imp2PtrArray[counter++] = curPtr = _imp2; - target = 431; - } else { - _imp2PtrArray[counter++] = curPtr = _imp1; - target = 99; - } - - do { - *curPtr = (*curPtr - 3) ^ 0xD7; - if (*curPtr == 0x40) { - curPtr += 3; - if (!techMapFl) - _imp2PtrArray[counter++] = curPtr; - else - _imp1PtrArray[counter++] = curPtr; - } else - ++curPtr; - } while (*curPtr != 0x60 && counter <= target); - - Common::DumpFile dump; - if (!techMapFl) { - dump.open("imp2_unc.dump"); - dump.write(_imp2, curPtr - _imp2); - } else { - dump.open("imp1_unc.dump"); - dump.write(_imp1, curPtr - _imp1); - } - dump.close(); -} - void EfhEngine::readImpFile(int16 id, bool techMapFl) { Common::String fileName = Common::String::format("imp.%d", id); @@ -1354,70 +1239,6 @@ void EfhEngine::displayLowStatusScreen(bool flag) { } } -void EfhEngine::loadImageSet(int imageSetId, uint8 *buffer, uint8 **subFilesArray, uint8 *destBuffer) { - Common::String fileName = Common::String::format("imageset.%d", imageSetId); - rImageFile(fileName, buffer, subFilesArray, destBuffer); -} - -void EfhEngine::rImageFile(Common::String filename, uint8 *targetBuffer, uint8 **subFilesArray, uint8 *packedBuffer) { - readFileToBuffer(filename, packedBuffer); - uint32 size = uncompressBuffer(packedBuffer, targetBuffer); - // TODO: Keep this dump for debug purposes only - Common::DumpFile dump; - dump.open(filename + ".dump"); - dump.write(targetBuffer, size); - // End of dump - - // TODO: Refactoring: once uncompressed, the container contains for each image its width, its height, and raw data (4 Bpp) - // => Write a class to handle that more properly - uint8 *ptr = targetBuffer; - uint16 counter = 0; - while (READ_LE_INT16(ptr) != 0) { - subFilesArray[counter] = ptr; - ++counter; - int16 imageWidth = READ_LE_INT16(ptr); - ptr += 2; - int16 imageHeight = READ_LE_INT16(ptr); - ptr += 2; - ptr += (imageWidth * imageHeight); - } -} - -void EfhEngine::displayFctFullScreen() { - // CHECKME: 319 is in the original but looks suspicious. - // copyDirtyRect(0, 0, 319, 200); - - _system->copyRectToScreen((uint8 *)_mainSurface->getPixels(), 320, 0, 0, 320, 200); - _system->updateScreen(); -} - -void EfhEngine::copyDirtyRect(int16 minX, int16 minY, int16 maxX, int16 maxY) { - _graphicsStruct->copy(_vgaGraphicsStruct2); - _initRect = Common::Rect(minX, minY, maxX, maxY); - copyGraphicBufferFromTo(_vgaGraphicsStruct2, _vgaGraphicsStruct1, _initRect, minX, minY); -} - -void EfhEngine::copyGraphicBufferFromTo(EfhGraphicsStruct *efh_graphics_struct, EfhGraphicsStruct *efh_graphics_struct1, const Common::Rect &rect, int16 min_x, int16 min_y) { - warning("STUB - copyGraphicBufferFromTo"); -} - -void EfhEngine::displayBufferBmAtPos(BufferBM *bufferBM, int16 posX, int16 posY) { - // TODO: Quick code to display stuff, may require to really reverse the actual function - uint8 *destPtr = (uint8 *)_mainSurface->getBasePtr(posX, posY); - // warning("%d %d - startX %d startY %d width %d height %d lineDataSize %d fieldD %d", posX, posY, bufferBM->_startX, bufferBM->_startY, bufferBM->_width, bufferBM->_height, bufferBM->_lineDataSize, bufferBM->_fieldD); - int counter = 0; - for (int line = 0; line < bufferBM->_height; ++line) { - for (int col = 0; col < bufferBM->_lineDataSize; ++col) { // _lineDataSize = _width / 2 - destPtr[320 * line + 2 * col] = bufferBM->_dataPtr[counter] >> 4; - destPtr[320 * line + 2 * col + 1] = bufferBM->_dataPtr[counter] & 0xF; - ++counter; - } - } - -// _system->copyRectToScreen((uint8 *)_mainSurface->getPixels(), 320, 0, 0, 320, 200); -// _system->updateScreen(); -} - uint8 *EfhEngine::script_readNumberArray(uint8 *srcBuffer, int16 destArraySize, int16 *destArray) { uint8 *buffer = srcBuffer; @@ -1454,13 +1275,6 @@ void EfhEngine::totalPartyKill() { } } -int16 EfhEngine::getRandom(int16 maxVal) { - if (maxVal == 0) - return 0; - - return 1 + _rnd->getRandomNumber(maxVal - 1); -} - void EfhEngine::removeCharacterFromTeam(int16 teamMemberId) { int16 charId = _teamCharId[teamMemberId]; _npcBuf[charId].field_12 = _npcBuf[charId].field_B; @@ -1480,10 +1294,6 @@ void EfhEngine::removeCharacterFromTeam(int16 teamMemberId) { refreshTeamSize(); } -void EfhEngine::emptyFunction(int i) { - // TODO: Eventually remove this useless function -} - void EfhEngine::refreshTeamSize() { _teamSize = 0; for (int16 counter = 0; counter < 3; ++counter) { @@ -1611,49 +1421,6 @@ bool EfhEngine::giveItemTo(int16 charId, int16 objectId, int altCharId) { return false; } -void EfhEngine::drawString(const char *str, int16 startX, int16 startY, uint16 unkFl) { - uint8 *curPtr = (uint8 *)str; - uint16 lineHeight = _fontDescr._charHeight + _fontDescr._extraVerticalSpace; - _unk_sub26437_flag = unkFl & 0x3FFF; - int16 minX = startX; - int16 minY = startY; // Used in case 0x8000 - int16 var6 = _fontDescr._extraLines[0] + startY - 1; // Used in case 0x8000 - - if (unkFl & 0x8000) { - warning("STUB - drawString - 0x8000"); - } - - for (uint8 curChar = *curPtr++; curChar != 0; curChar = *curPtr++) { - if (curChar == 0x0A) { - startX = minX; - startY += lineHeight; - continue; - } - - if (curChar < 0x20) - continue; - - uint16 characterId = (curChar + 0xE0) & 0xFF; - uint8 charWidth = _fontDescr._widthArray[characterId]; - - if (startX + charWidth >= 319) { - startX = minX; - startY += lineHeight; - } - - uint8 varC = _fontDescr._extraLines[characterId]; - drawChar(curChar, startX, startY + varC); - startX += charWidth + _fontDescr._extraHorizontalSpace; - } - -} - -void EfhEngine::displayCenteredString(const char *str, int16 minX, int16 maxX, int16 posY) { - uint16 length = getStringWidth(str); - int16 startCenteredDisplayX = minX + (maxX - minX - length) / 2; - drawString(str, startCenteredDisplayX, posY, _textColor); -} - int16 EfhEngine::chooseCharacterToReplace() { warning("STUB - chooseCharacterToReplace"); return 0x1B; @@ -1688,20 +1455,6 @@ int16 EfhEngine::handleCharacterJoining() { return 2; } -void EfhEngine::drawMapWindow() { - drawColoredRect(128, 8, 303, 135, 0); -} - -void EfhEngine::copyString(char *srcStr, char *destStr) { - char lastChar = 1; - int16 idx = 0; - - while (lastChar != 0) { - lastChar = destStr[idx] = srcStr[idx]; - ++idx; - } -} - int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, int maxY, int argC) { bool doneFlag = false; int16 var_F2 = -1; @@ -1853,7 +1606,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, case 0x07: if (argC != 0) { totalPartyKill(); - emptyFunction(2); + // emptyFunction(2); } break; case 0x08: @@ -2163,15 +1916,6 @@ void EfhEngine::sub133E5(uint8 *srcPtr, int posX, int posY, int maxX, int maxY, script_parse(_messageToBePrinted, posX, posY, maxX, maxY, argC); } -void EfhEngine::displayGameScreen() { - clearScreen(0); - drawUpperLeftBorders(); - drawUpperRightBorders(); - drawBottomBorders(); - displayAnimFrame(); - displayLowStatusScreen(false); -} - void EfhEngine::sub221FA(uint8 *impArray, bool flag) { for (uint8 counter = 0; counter < 2; ++counter) { if (counter == 0 || flag) { @@ -2185,24 +1929,6 @@ void EfhEngine::sub221FA(uint8 *impArray, bool flag) { } } -void EfhEngine::drawUpperLeftBorders() { - displayRawDataAtPos(_circleImageSubFileArray[0], 0, 0); - displayRawDataAtPos(_circleImageSubFileArray[1], 112, 0); - displayRawDataAtPos(_circleImageSubFileArray[3], 16, 0); -} - -void EfhEngine::drawUpperRightBorders() { - displayRawDataAtPos(_circleImageSubFileArray[2], 304, 0); - displayRawDataAtPos(_circleImageSubFileArray[4], 128, 0); -} - -void EfhEngine::drawBottomBorders() { - displayRawDataAtPos(_circleImageSubFileArray[7], 16, 136); - displayRawDataAtPos(_circleImageSubFileArray[8], 16, 192); - displayRawDataAtPos(_circleImageSubFileArray[5], 0, 136); - displayRawDataAtPos(_circleImageSubFileArray[6], 304, 136); -} - void EfhEngine::sub15A28(int16 arg0, int16 arg2) { warning("STUB: sub15A28"); } @@ -2310,44 +2036,6 @@ int16 EfhEngine::sub151FD(int16 posX, int16 posY) { return -1; } -void EfhEngine::drawChar(uint8 curChar, int16 posX, int posY) { - // Quick hacked display, may require rework - uint8 *destPtr = (uint8 *)_mainSurface->getBasePtr(posX, posY); - - int16 charId = curChar - 0x20; - uint8 width = _fontDescr._widthArray[charId]; - - for (int16 line = 0; line < 8; ++line) { - int16 x = 0; - for (int i = 7; i >= 7 - width; --i) { - if (_fontDescr._fontData[charId]._lines[line] & (1 << i)) - destPtr[320 * line + x] = _textColor; - ++x; - } - } -} - -void EfhEngine::setTextColorWhite() { - if (_videoMode == 8) // CGA - _textColor = 0x3; - else - _textColor = 0xF; -} - -void EfhEngine::setTextColorRed() { - if (_videoMode == 8) // CGA - _textColor = 0x2; - else - _textColor = 0xC; -} - -void EfhEngine::setTextColorGrey() { - if (_videoMode == 8) // CGA - _textColor = 0x1; - else - _textColor = 0x8; -} - bool EfhEngine::isPosOutOfMap(int16 mapPosX, int16 mapPosY) { int16 maxMapBlocks = _largeMapFlag ? 63 : 23; @@ -2512,10 +2200,6 @@ bool EfhEngine::handleDeathMenu() { return false; } -void EfhEngine::setNumLock() { - // No implementation in ScummVM -} - void EfhEngine::computeMapAnimation() { const int16 maxMapBlocks = _largeMapFlag ? 63 : 23; @@ -2579,27 +2263,6 @@ void EfhEngine::unkFct_anim() { computeMapAnimation(); } -void EfhEngine::setNextCharacterPos() { - if (_textPosX <= 311) - return; - - _textPosX = 0; - _textPosY += 8; - - if (_textPosY > 191) - _textPosY = 0; -} - -void EfhEngine::displayStringAtTextPos(const char *message) { - drawString(message, _textPosX, _textPosY, _textColor); - _textPosX += getStringWidth(message) + 1; - setNextCharacterPos(); -} - -void EfhEngine::unkFct_displayMenuBox_2(int16 color) { - drawColoredRect(16, 152, 302, 189, color); -} - int8 EfhEngine::sub16B08(int16 monsterId) { // Simplified version compared to the original int16 maxSize = _largeMapFlag ? 63 : 23; @@ -3189,29 +2852,6 @@ void EfhEngine::sub221D2(int16 monsterId) { } } -Common::KeyCode EfhEngine::getInputBlocking() { - // The original checks for the joystick input - Common::Event event; - _system->getEventManager()->pollEvent(event); - Common::KeyCode retVal = Common::KEYCODE_INVALID; - - uint32 lastMs = _system->getMillis(); - while (retVal == Common::KEYCODE_INVALID) { - if (event.type == Common::EVENT_KEYUP) { - retVal = event.kbd.keycode; - } - - _system->delayMillis(20); - uint32 newMs = _system->getMillis(); - - if (newMs - lastMs >= 220) { - lastMs = newMs; - unkFct_anim(); - } - } - return retVal; -} - void EfhEngine::sub22AA8(int16 arg0) { int16 var8, varA, varC, varE; var8 = varA = varC = varE = 0; @@ -3541,16 +3181,6 @@ int16 EfhEngine::getXPLevel(int32 xp) { return level; } -void EfhEngine::displayChar(char character) { - char buffer[2]; - buffer[0] = character; - buffer[1] = 0; - - drawString(buffer, _textPosX, _textPosY, _textColor); - _textPosX += getStringWidth(buffer) + 1; - setNextCharacterPos(); -} - void EfhEngine::displayCharacterSummary(int16 curMenuLine, int16 npcId) { char buffer1[40]; char buffer2[40]; @@ -3743,19 +3373,6 @@ void EfhEngine::unk_StatusMenu(int16 windowId, int16 menuId, int16 curMenuLine, displayFctFullScreen(); } -void EfhEngine::displayWindow(uint8 *buffer, int16 posX, int16 posY, uint8 *dest) { - if (buffer == nullptr) { - warning("Target Buffer Not Defined...DCImage!"); // That's the original message... And yes, it's wrong: it's checking the source buffer :) - return; - } - - // Only MCGA handled, the rest is skipped - uncompressBuffer(buffer, dest); - displayRawDataAtPos(dest, posX, posY); - displayFctFullScreen(); - displayRawDataAtPos(dest, posX, posY); -} - void EfhEngine::sub18E80(int16 charId, int16 windowId, int16 menuId, int16 curMenuLine) { for (int counter = 0; counter < 2; ++counter) { displayWindow(_menuBuf, 0, 0, _hiResImageBuf); @@ -3832,20 +3449,616 @@ void EfhEngine::sub191FF(int16 charId, int16 objectId, int16 windowId, int16 men } } -int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine, int16 argA) { - warning("STUB: sub19E2E"); +void EfhEngine::sub1E028(int16 id, uint8 mask, int16 groupFl) { + int16 monsterId; + if (groupFl) { + monsterId = _teamMonsterIdArray[id]; + } else { + monsterId = id; + } - return -1; + _mapMonsters[monsterId]._field_8 &= 0xF0; + _mapMonsters[monsterId]._field_8 |= mask; } -bool EfhEngine::getValidationFromUser() { - Common::KeyCode input = handleAndMapInput(true); - if (input == Common::KEYCODE_y) // or if joystick button 1 +bool EfhEngine::sub1BA9B(int16 groupId, int16 id) { + if (_mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[id] > 0 && _stru32686[groupId]._field0[id] == 0) return true; - return false; } +int16 EfhEngine::sub15538(int16 mapPosX, int16 mapPosY) { + int16 mapTileInfo = getMapTileInfo(mapPosX, mapPosY); + int16 imageSetId = mapTileInfo / 72; + + return (_currentTileBankImageSetId[imageSetId] * 72) + (mapTileInfo % 72); +} + +void EfhEngine::setCharacterObjectToBroken(int16 charId, int16 objectId) { + _npcBuf[charId]._inventory[objectId]._ref = 0x7FFF; +} + +Common::KeyCode EfhEngine::selectOtherCharFromTeam() { + Common::KeyCode maxVal = (Common::KeyCode) (Common::KEYCODE_0 + _teamSize); + Common::KeyCode input = Common::KEYCODE_INVALID; + for (;;) { + input = waitForKey(); + if (input == Common::KEYCODE_ESCAPE || (input >= Common::KEYCODE_0 && input <= maxVal)) + break; + } + + return input; +} + +int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine, int16 argA) { + char buffer1[80]; + char buffer2[80]; + + int16 varA6 = 0; + int16 varA4 = 0; + + int16 itemId = _npcBuf[charId]._inventory[objectId]._ref; + switch (_items[itemId].field_16 - 1) { + case 0: + if (argA == 2) { + displayString_3("The item emits a low droning hum...", false, charId, windowId, menuId, curMenuLine); + } else { + int16 varAE = 0; + strcat((char *)_messageToBePrinted, " The item emits a low droning hum..."); + if (getRandom(100) < 50) { + for (int16 varA8 = 0; varA8 < 9; ++varA8) { + if (sub1BA9B(windowId, varA8)) { + ++varAE; + _stru32686[windowId]._field0[varA8] = 1; + _stru32686[windowId]._field2[varA8] = getRandom(8); + } + } + } else { + int16 varAC = getRandom(9); + for (int16 varA8 = 0; varA8 < 9; ++varA8) { + if (varAC == 0) + break; + + if (sub1BA9B(windowId, varA8)) { + ++varAE; + --varAC; + _stru32686[windowId]._field0[varA8] = 1; + _stru32686[windowId]._field2[varA8] = getRandom(8); + } + } + } + // The original was duplicating this code in each branch of the previous random check. + if (varAE > 1) { + sprintf(buffer1, "%d %ss fall asleep!", varAE, kEncounters[_mapMonsters[_teamMonsterIdArray[windowId]]._MonsterRef]._name); + } else { + sprintf(buffer1, "%d %s falls asleep!", varAE, kEncounters[_mapMonsters[_teamMonsterIdArray[windowId]]._MonsterRef]._name); + } + strcat((char *)_messageToBePrinted, buffer1); + } + + varA6 = -1; + break; + case 1: + if (argA == 2) { + displayString_3("The item grows very cold for a moment...", false, charId, windowId, menuId, curMenuLine); + } else { + strcat((char *)_messageToBePrinted, " The item emits a blue beam..."); + int16 varAE = 0; + if (getRandom(100) < 50) { + for (int16 varA8 = 0; varA8 < 9; ++varA8) { + if (sub1BA9B(windowId, varA8)) { + ++varAE; + _stru32686[windowId]._field0[varA8] = 2; + _stru32686[windowId]._field2[varA8] = getRandom(8); + } + } + } else { + int16 varAC = getRandom(9); + for (int16 varA8 = 0; varA8 < 9; ++varA8) { + if (varAC == 0) + break; + + if (sub1BA9B(windowId, varA8)) { + ++varAE; + --varAC; + _stru32686[windowId]._field0[varA8] = 2; + _stru32686[windowId]._field2[varA8] = getRandom(8); + } + } + } + // : This part is only present in the original in the case < 50, but for me + // it's missing in the other case as there's an effect (frozen enemies) but no feedback to the player + if (varAE > 1) { + sprintf(buffer1, "%d %ss are frozen in place!", varAE, kEncounters[_mapMonsters[_teamMonsterIdArray[windowId]]._MonsterRef]._name); + } else { + sprintf(buffer1, "%d %s is frozen in place!", varAE, kEncounters[_mapMonsters[_teamMonsterIdArray[windowId]]._MonsterRef]._name); + } + strcat((char *)_messageToBePrinted, buffer1); + // + } + + varA6 = -1; + break; + case 2: + if (argA == 2) { + displayString_3("A serene feeling passes through the air...", false, charId, windowId, menuId, curMenuLine); + } else { + strcat((char *)_messageToBePrinted, " The combat pauses...as there is a moment of forgiveness..."); + _unkArray2C8AA[0] = 0; + } + + varA6 = -1; + break; + case 4: + if (argA == 2) { + displayString_3("A dark sense fills your soul...then fades!", false, charId, windowId, menuId, curMenuLine); + } else { + strcat((char *)_messageToBePrinted, " A dark gray fiery whirlwind surrounds the poor victim...the power fades and death abounds!"); + if (getRandom(100) < 50) { + for (int16 varA8 = 0; varA8 < 9; ++varA8) { + if (getRandom(100) < 50) { + _mapMonsters[_teamMonsterIdArray[windowId]]._pictureRef[varA8] = 0; + } + } + } else { + for (int16 varA8 = 0; varA8 < 9; ++varA8) { + if (sub1BA9B(windowId, varA8)) { + if (getRandom(100) < 50) { + _mapMonsters[_teamMonsterIdArray[windowId]]._pictureRef[varA8] = 0; + } + break; + } + } + } + } + varA6 = -1; + break; + case 5: + if (argA == 2) { + displayString_3("A dark sense fills your soul...then fades!", false, charId, windowId, menuId, curMenuLine); + } else { + if (getRandom(100) < 50) { + strcat((char *)_messageToBePrinted, " A dark fiery whirlwind surrounds the poor victim...the power fades and all targeted die!"); + for (int16 varA8 = 0; varA8 < 9; ++varA8) { + _mapMonsters[_teamMonsterIdArray[windowId]]._pictureRef[varA8] = 0; + } + } else { + strcat((char *)_messageToBePrinted, " A dark fiery whirlwind surrounds the poor victim...the power fades and one victim dies!"); + for (int16 varA8 = 0; varA8 < 9; ++varA8) { + if (sub1BA9B(windowId, varA8)) { + _mapMonsters[_teamMonsterIdArray[windowId]]._pictureRef[varA8] = 0; + } + } + } + } + + varA6 = -1; + break; + case 12: + if (argA == 2) { + displayString_3("There is no apparent affect!", false, charId, windowId, menuId, curMenuLine); + } else { + strcat((char *)_messageToBePrinted, " The magic sparkles brilliant hues in the air!"); + sub1E028(windowId, _items[itemId].field17_attackTypeDefense, true); + } + varA6 = -1; + break; + case 14: { + int16 varAA; + if (argA == 2) { + displayString_3("Who will use the item?", false, charId, windowId, menuId, curMenuLine); + varAA = selectOtherCharFromTeam(); + } else { + varAA = windowId; + } + + if (varAA != 0x1B) { + strcpy(buffer1, " The magic makes the user as quick and agile as a bird!"); + if (argA == 2) { + displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + } else { + strcat((char *)_messageToBePrinted, buffer1); + } + _word32482[varAA] -= 50; + if (_word32482[varAA] < 0) + _word32482[varAA] = 0; + } + + varA6 = -1; + } + break; + case 15: { + int16 varAA; + if (argA == 2) { + displayString_3("Who will use the item?", false, charId, windowId, menuId, curMenuLine); + varAA = selectOtherCharFromTeam(); + } else { + varAA = windowId; + } + + if (varAA != 0x1B) { + strcpy(buffer1, " The magic makes the user invisible!"); + if (argA == 2) { + displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + } else { + strcat((char *)_messageToBePrinted, buffer1); + } + + _word32680[varAA] -= 50; + if (_word32680[varAA] < 0) + _word32680[varAA] = 0; + } + + varA6 = -1; + } + break; + case 16: { + int16 varAC = _mapPosX; + int16 varAA = _mapPosY; + _mapPosX = getRandom(_largeMapFlag ? 63 : 23); + _mapPosY = getRandom(_largeMapFlag ? 63 : 23); + int16 varAE = sub15538(_mapPosX, _mapPosY); + + if (_tileFact[2 * varAE] == 0) { + totalPartyKill(); + strcpy(buffer1, "The entire party vanishes in a flash... only to appear in stone !"); + if (argA == 2) { + displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + } else { + strcat((char *)_messageToBePrinted, buffer1); + varA4 = -1; + } + // emptyFunction(2); + } else { + if (varAE == 0 || varAE == 0x48) { + strcpy(buffer1, "The entire party vanishes in a flash...but re-appears, as if nothing happened!"); + if (argA == 2) { + displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + } else { + strcat((char *)_messageToBePrinted, buffer1); + varA4 = -1; + } + } else { + strcpy(buffer1, "The entire party vanishes in a flash...only to appear elsewhere!"); + if (argA == 2) { + displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + } else { + strcat((char *)_messageToBePrinted, buffer1); + varA4 = -1; + } + } + } + + varA6 = -1; + } + break; + case 17: { + _mapPosX = _items[itemId].field_19; + _mapPosY = _items[itemId].field_1A; + int16 varAE = sub15538(_mapPosX, _mapPosY); + if (_tileFact[2 * varAE] == 0) { + totalPartyKill(); + strcpy(buffer1, "The entire party vanishes in a flash... only to appear in stone !"); + if (argA == 2) { + displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + } else { + strcat((char *)_messageToBePrinted, buffer1); + varA4 = -1; + } + // emptyFunction(2); + } else { + if (varAE == 0 || varAE == 0x48) { + strcpy(buffer1, "The entire party vanishes in a flash...but re-appears, as if nothing happened!"); + if (argA == 2) { + displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + } else { + strcat((char *)_messageToBePrinted, buffer1); + varA4 = -1; + } + } else { + strcpy(buffer1, "The entire party vanishes in a flash...only to appear elsewhere!"); + if (argA == 2) { + displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + } else { + strcat((char *)_messageToBePrinted, buffer1); + varA4 = -1; + } + } + } + + varA6 = -1; + } + break; + case 18: + if (argA == 2) { + displayString_3("The item makes a loud noise!", false, charId, windowId, menuId, curMenuLine); + } else { + int16 varAA = windowId; + if (varAA != 0x1B) { + if (_teamCharStatus[varAA]._status == 2) { // frozen + strcat((char *)_messageToBePrinted, " The item makes a loud noise, awakening the character!"); + _teamCharStatus[varAA]._status = 0; + _teamCharStatus[varAA]._duration = 0; + } else { + strcat((char *)_messageToBePrinted, " The item makes a loud noise, but has no effect!"); + } + } + } + + varA6 = -1; + break; + case 19: + strcpy(buffer1, " * The item breaks!"); + if (argA == 2) { + displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + } else { + strcat((char *)_messageToBePrinted, buffer1); + } + setCharacterObjectToBroken(charId, objectId); + varA6 = -1; + break; + case 23: + copyString(_items[itemId]._name, buffer2); + sprintf(buffer1, "The %s says, '", buffer2); + if (_items[itemId].field_19 < _mapPosX) { + if (_items[itemId].field_1A < _mapPosY) { + strcat(buffer1, "North West!"); + } else if (_items[itemId].field_1A > _mapPosY) { + strcat(buffer1, "South West!"); + } else { + strcat(buffer1, "West!"); + } + } else if (_items[itemId].field_19 > _mapPosX) { + if (_items[itemId].field_1A < _mapPosY) { + strcat(buffer1, "North East!"); + } else if (_items[itemId].field_1A > _mapPosY) { + strcat(buffer1, "South East!"); + } else { + strcat(buffer1, "East!"); + } + } else { // equals _mapPosX + if (_items[itemId].field_1A < _mapPosY) { + strcat(buffer1, "North!"); + } else if (_items[itemId].field_1A > _mapPosY) { + strcat(buffer1, "South!"); + } else { + strcat(buffer1, "Here!!!"); + } + } + strcat(buffer1, "'"); + if (argA == 2) { + displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + } else { + strcat((char *)_messageToBePrinted, buffer1); + varA4 = -1; + } + + varA6 = -1; + break; + case 24: { + int16 varAA; + if (argA == 2) { + displayString_3("Who will use this item?", false, charId, windowId, menuId, curMenuLine); + varAA = selectOtherCharFromTeam(); + } else + varAA = windowId; + + if (varAA != 0x1B) { + uint8 varAE = _items[itemId].field17_attackTypeDefense; + uint8 varAC = getRandom(_items[itemId].field_19); + _npcBuf[_teamCharId[varAA]]._activeScore[varAE] += varAC; + if (_npcBuf[_teamCharId[varAA]]._activeScore[varAE] > 20) { + _npcBuf[_teamCharId[varAA]]._activeScore[varAE] = 20; + } + if (varAC > 1) + sprintf(buffer1, "%s increased %d points!", kSkillArray[varAE], varAC); + else + sprintf(buffer1, "%s increased 1 point!", kSkillArray[varAE]); + + if (argA == 2) { + displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + } else { + strcat((char *)_messageToBePrinted, buffer1); + varA4 = -1; + } + } + + varA6 = -1; + } + break; + case 25: { + int16 varAA; + if (argA == 2) { + displayString_3("Who will use this item?", false, charId, windowId, menuId, curMenuLine); + varAA = selectOtherCharFromTeam(); + } else + varAA = windowId; + + if (varAA != 0x1B) { + uint8 varAE = _items[itemId].field17_attackTypeDefense; + uint8 varAC = getRandom(_items[itemId].field_19); + _npcBuf[_teamCharId[varAA]]._activeScore[varAE] -= varAC; + if (_npcBuf[_teamCharId[varAA]]._activeScore[varAE] > 20 || _npcBuf[_teamCharId[varAA]]._activeScore[varAE] < 0) { + _npcBuf[_teamCharId[varAA]]._activeScore[varAE] = 1; + } + if (varAC > 1) + sprintf(buffer1, "%s lowered %d points!", kSkillArray[varAE], varAC); + else + sprintf(buffer1, "%s lowered 1 point!", kSkillArray[varAE]); + + if (argA == 2) { + displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + } else { + strcat((char *)_messageToBePrinted, buffer1); + varA4 = -1; + } + } + + varA6 = -1; + } + break; + case 26: + strcpy(buffer1, "The entire party collapses, dead!!!"); + if (argA == 2) { + displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + } else { + strcat((char *)_messageToBePrinted, buffer1); + varA4 = -1; + } + totalPartyKill(); + // emptyFunction(2); + varA6 = -1; + break; + case 27: { + int16 varAA; + if (argA == 2) { + displayString_3("Who will use the item?", false, charId, windowId, menuId, curMenuLine); + varAA = selectOtherCharFromTeam(); + } else { + varAA = windowId; + } + + if (varAA != 0x1B) { + _npcBuf[_teamCharId[varAA]]._hitPoints = 0; + copyString(_npcBuf[_teamCharId[varAA]]._name, buffer2); + sprintf(buffer1, "%s collapses, dead!!!", buffer2); + if (argA == 2) { + displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + } else { + strcat((char *)_messageToBePrinted, buffer1); + varA4 = -1; + } + // emptyFunction(2); + } + + varA6 = -1; + } + break; + case 28: + if (argA == 2) { + displayString_3("The item makes a loud noise!", false, charId, windowId, menuId, curMenuLine); + } else { + int16 varAA = windowId; + if (varAA != 0x1B) { + if (_teamCharStatus[varAA]._status == 0) { + strcat((char *)_messageToBePrinted, " The item makes a loud noise, awakening the character!"); + _teamCharStatus[varAA]._status = 0; + _teamCharStatus[varAA]._duration = 0; + } else { + strcat((char *)_messageToBePrinted, " The item makes a loud noise, but has no effect!"); + } + } + } + + varA6 = -1; + break; + case 29: { + int16 varAA; + if (argA == 2) { + displayString_3("Who will use the item?", false, charId, windowId, menuId, curMenuLine); + varAA = selectOtherCharFromTeam(); + } else { + varAA = windowId; + } + + if (varAA != 0x1B) { + int16 varAE = getRandom(_items[itemId].field17_attackTypeDefense); + _npcBuf[_teamCharId[varA4]]._hitPoints += varAE; + if (_npcBuf[_teamCharId[varA4]]._hitPoints > _npcBuf[_teamCharId[varA4]]._maxHP) + _npcBuf[_teamCharId[varA4]]._hitPoints = _npcBuf[_teamCharId[varA4]]._maxHP; + + copyString(_npcBuf[_teamCharId[varAA]]._name, buffer2); + if (varAE > 1) + sprintf(buffer1, "%s is healed %d points!", buffer2, varAE); + else + sprintf(buffer1, "%s is healed 1 point!", buffer2); + } + + if (argA == 2) { + displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + } else { + strcat((char *)_messageToBePrinted, buffer1); + varA4 = -1; + } + + varA6 = -1; + } + break; + case 30: { + int16 varAA; + if (argA == 2) { + displayString_3("Who will use the item?", false, charId, windowId, menuId, curMenuLine); + varAA = selectOtherCharFromTeam(); + } else { + varAA = windowId; + } + + if (varAA != 0x1B) { + int16 varAE = getRandom(_items[itemId].field17_attackTypeDefense); + _npcBuf[_teamCharId[varA4]]._hitPoints -= varAE; + if (_npcBuf[_teamCharId[varA4]]._hitPoints < 0) + _npcBuf[_teamCharId[varA4]]._hitPoints = 0; + + copyString(_npcBuf[_teamCharId[varAA]]._name, buffer2); + if (varAE > 1) + sprintf(buffer1, "%s is harmed for %d points!", buffer2, varAE); + else + sprintf(buffer1, "%s is harmed for 1 point!", buffer2); + } + + if (argA == 2) { + displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + } else { + strcat((char *)_messageToBePrinted, buffer1); + varA4 = -1; + } + + varA6 = -1; + + } + break; + case 3: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 13: + case 20: + case 21: + case 22: + default: + break; + } + + if (varA6 != 0) { + if ((_npcBuf[charId]._inventory[objectId]._stat1 & 0x7F) != 0x7F) { + int8 varA1 = (_npcBuf[charId]._inventory[objectId]._stat1 & 0x7F) - 1; + if (varA1 <= 0) { + strcpy(buffer1, " * The item breaks!"); + if (argA == 2) { + Common::KeyCode varAE = getLastCharAfterAnimCount(_guessAnimationAmount); + displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + } else { + strcat((char *)_messageToBePrinted, buffer1); + } + setCharacterObjectToBroken(charId, objectId); + } else { + _npcBuf[charId]._inventory[objectId]._stat1 &= 0x80; + _npcBuf[charId]._inventory[objectId]._stat1 |= 0xA1; + } + } + + if (argA == 2) { + Common::KeyCode varAE = getLastCharAfterAnimCount(_guessAnimationAmount); + sub18E80(charId, windowId, menuId, curMenuLine); + } + } + + return varA4; +} + int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { int16 menuId = 9; int16 var16 = -1; @@ -4403,204 +4616,12 @@ void EfhEngine::loadGame() { loadPlacesFile(_fullPlaceId, true); } -uint32 EfhEngine::uncompressBuffer(uint8 *compressedBuf, uint8 *destBuf) { - if (compressedBuf == nullptr || destBuf == nullptr) - error("uncompressBuffer - Invalid pointer used in parameter list"); - - uint8 *curPtrDest = destBuf; - - uint16 compSize = READ_LE_UINT16(compressedBuf) + 1; - uint8 *curPtrCompressed = compressedBuf + 2; - - // Not in the original. This has been added for debug purposes (the original function doesn't return a value) - uint32 decompSize = 0; - - for (;;) { - uint8 next = *curPtrCompressed++; - if (--compSize <= 0) - break; - - if (next != 0xC3) { - *curPtrDest++ = next; - ++decompSize; - continue; - } - - next = *curPtrCompressed++; - if (--compSize <= 0) - break; - - if (next == 0) { - *curPtrDest++ = 0xC3; - ++decompSize; - continue; - } - - uint8 loopVal = next; - next = *curPtrCompressed++; - - for (int i = 0; i < loopVal; ++i) { - *curPtrDest++ = next; - ++decompSize; - } - - --compSize; - if (compSize == 0) - break; - } - - curPtrDest[0] = curPtrDest[1] = 0; - decompSize += 2; - - return decompSize; -} - uint8 EfhEngine::getMapTileInfo(int16 mapPosX, int16 mapPosY) { - int size = _largeMapFlag ? 32 : 24; + int size = _largeMapFlag ? 64 : 24; return _mapGameMapPtr[mapPosX * size + mapPosY]; } -void EfhEngine::drawRect(int minX, int minY, int maxX, int maxY) { - if (minY > maxY) - SWAP(minY, maxY); - - if (minX > maxX) - SWAP(minX, maxX); - - // warning("drawRect - _graphicsStruct x %d -> %d, y %d -> %d", _graphicsStruct->_area.left, _graphicsStruct->_area.right, _graphicsStruct->_area.top, _graphicsStruct->_area.bottom); - - minX = CLIP(minX, 0, 319); - maxX = CLIP(maxX, 0, 319); - minY = CLIP(minY, 0, 199); - maxY = CLIP(maxY, 0, 199); - - int deltaY = 1 + maxY - minY; - int deltaX = 1 + maxX - minX; - - uint8 color = _defaultBoxColor & 0xF; - bool xorColor = (_defaultBoxColor & 0x40) != 0; - uint8 *destPtr = (uint8 *)_mainSurface->getBasePtr(minX, minY); - - for (int line = 0; line < deltaY; ++line) { - for (int col = 0; col < deltaX; ++col) { - if (xorColor) - destPtr[320 * line + col] ^= color; - else - destPtr[320 * line + col] = color; - } - } - -} - -void EfhEngine::drawColoredRect(int minX, int minY, int maxX, int maxY, int color) { - uint8 oldValue = _defaultBoxColor; - _defaultBoxColor = color; - drawRect(minX, minY, maxX, maxY); - _defaultBoxColor = oldValue; -} - -void EfhEngine::clearScreen(int color) { - drawColoredRect(0, 0, 320, 200, color); -} - -Common::KeyCode EfhEngine::handleAndMapInput(bool animFl) { - // The original checks for the joystick input - Common::Event event; - _system->getEventManager()->pollEvent(event); - Common::KeyCode retVal = Common::KEYCODE_INVALID; - if (event.type == Common::EVENT_KEYUP) { - retVal = event.kbd.keycode; - } - - if (animFl) { - warning("STUB - handleAndMapInput - animFl"); - } - return retVal; -} - -Common::KeyCode EfhEngine::waitForKey() { - Common::KeyCode retVal = Common::KEYCODE_INVALID; - Common::Event event; - - uint32 lastMs = _system->getMillis(); - while (retVal == Common::KEYCODE_INVALID) { // TODO: Check shouldquit() - _system->delayMillis(20); - uint32 newMs = _system->getMillis(); - - if (newMs - lastMs >= 200) { - lastMs = newMs; - unkFct_anim(); - } - - _system->getEventManager()->pollEvent(event); - if (event.type == Common::EVENT_KEYUP) { - retVal = event.kbd.keycode; - } - } - - return retVal; -} - -Common::KeyCode EfhEngine::mapInputCode(Common::KeyCode input) { - // Original is doing: - // if input < a or > z : return input - // else return (input + 0xE0) - // ex: 'a' = 0x61 + 0xE0 = 0x0141, but it's a uint8 so it's 0x41 which is 'A'. - // So basically the original works with uppercase letters and do not alter the other inputs. - // => no implementation needed. - return input; -} - -Common::KeyCode EfhEngine::getLastCharAfterAnimCount(int16 delay) { - if (delay == 0) - return Common::KEYCODE_INVALID; - - Common::KeyCode lastChar = Common::KEYCODE_INVALID; - - uint32 lastMs = _system->getMillis(); - while (delay > 0 && lastChar == Common::KEYCODE_INVALID) { - _system->delayMillis(20); - uint32 newMs = _system->getMillis(); - - if (newMs - lastMs >= 200) { - lastMs = newMs; - --delay; - unkFct_anim(); - } - - lastChar = handleAndMapInput(false); - } - - return lastChar; -} - -Common::KeyCode EfhEngine::getInput(int16 delay) { - if (delay == 0) - return Common::KEYCODE_INVALID; - - Common::KeyCode lastChar = Common::KEYCODE_INVALID; - Common::KeyCode retVal = Common::KEYCODE_INVALID; - - uint32 lastMs = _system->getMillis(); - while (delay > 0) { - _system->delayMillis(20); - uint32 newMs = _system->getMillis(); - - if (newMs - lastMs >= 200) { - lastMs = newMs; - --delay; - unkFct_anim(); - } - - lastChar = handleAndMapInput(false); - if (lastChar != Common::KEYCODE_INVALID) - retVal = lastChar; - } - - return retVal; -} - void EfhEngine::displayNextAnimFrame() { if (++_unkAnimRelatedIndex >= 15) _unkAnimRelatedIndex = 0; @@ -4643,17 +4664,4 @@ void EfhEngine::copyCurrentPlaceToBuffer(int id) { memcpy(_curPlace, placesPtr, 24 * 24); } -void EfhEngine::displayRawDataAtPos(uint8 *imagePtr, int16 posX, int16 posY) { - uint16 height = READ_LE_INT16(imagePtr); - uint16 width = READ_LE_INT16(imagePtr + 2); - uint8 *imageData = imagePtr + 4; - - _imageDataPtr._lineDataSize = width; - _imageDataPtr._dataPtr = imageData; - _imageDataPtr._height = height; - _imageDataPtr._width = width * 2; // 2 pixels per byte - _imageDataPtr._startX = _imageDataPtr._startY = 0; - - displayBufferBmAtPos(&_imageDataPtr, posX, posY); -} } // End of namespace Efh diff --git a/engines/efh/efh.h b/engines/efh/efh.h index cb33cdc8cf45..60a4407ea2ba 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -214,6 +214,13 @@ struct MapMonster { int16 _pictureRef[9]; }; +struct Stru32686 { + int16 _field0[9]; + int16 _field2[9]; + + void init(); +}; + class EfhEngine : public Engine { public: EfhEngine(OSystem *syst, const EfhGameDescription *gd); @@ -252,9 +259,7 @@ class EfhEngine : public Engine { GameType _gameType; Common::Platform _platform; - void initPalette(); void initialize(); - int32 readFileToBuffer(Common::String &filename, uint8 *destBuffer); void readAnimInfo(); void findMapFile(int16 mapId); void loadNewPortrait(); @@ -262,17 +267,11 @@ class EfhEngine : public Engine { void loadHistory(); void loadTechMapImp(int16 fileId); void loadPlacesFile(uint16 fullPlaceId, bool forceReloadFl); - void drawLeftCenterBox(); - void displayAnimFrame(); - void displayAnimFrames(int16 animId, bool displayMenuBoxFl); void readTileFact(); void readItems(); void loadNPCS(); - void setDefaultNoteDuration(); Common::KeyCode playSong(uint8 *buffer); - void decryptImpFile(bool techMapFl); void readImpFile(int16 id, bool techMapFl); - Common::KeyCode getLastCharAfterAnimCount(int16 delay); void playIntro(); void initEngine(); void initMapMonsters(); @@ -281,68 +280,40 @@ class EfhEngine : public Engine { int16 getEquipmentDefense(int16 charId, bool flag); uint16 sub1C80A(int16 charId, int field18, bool flag); void displayLowStatusScreen(bool flag); - void loadImageSet(int imageSetId, uint8 *buffer, uint8 **subFilesArray, uint8 *destBuffer); - void rImageFile(Common::String filename, uint8 *targetBuffer, uint8 **subFilesArray, uint8 *packedBuffer); - void displayFctFullScreen(); - void copyDirtyRect(int16 minX, int16 minY, int16 maxX, int16 maxY); - void copyGraphicBufferFromTo(EfhGraphicsStruct *efh_graphics_struct, EfhGraphicsStruct *efh_graphics_struct1, const Common::Rect &rect, int16 min_x, int16 min_y); void loadImageSetToTileBank(int16 tileBankId, int16 imageSetId); void restoreAnimImageSetId(); void checkProtection(); void loadGame(); - uint32 uncompressBuffer(uint8 *compressedBuf, uint8 *destBuf); void copyCurrentPlaceToBuffer(int id); uint8 getMapTileInfo(int16 mapPosX, int16 mapPosY); - void drawRect(int minX, int minY, int maxX, int maxY); - void drawColoredRect(int minX, int minY, int maxX, int maxY, int color); - void clearScreen(int color); - Common::KeyCode handleAndMapInput(bool animFl); void displayNextAnimFrame(); void writeTechAndMapFiles(); uint16 getStringWidth(const char *buffer); void setTextPos(int16 textPosX, int16 textPosY); - void sub15150(bool flag); void drawMap(bool largeMapFl, int16 mapPosX, int16 mapPosY, int mapSize, bool drawHeroFl, bool drawMonstersFl); void displaySmallMap(int16 posX, int16 posY); void displayLargeMap(int16 posX, int16 posY); void redrawScreen(); - void displayRawDataAtPos(uint8 *imagePtr, int16 posX, int16 posY); - void displayBufferBmAtPos(BufferBM *bufferBM, int16 posX, int16 posY); uint8 *script_readNumberArray(uint8 *buffer, int16 destArraySize, int16 *destArray); uint8 *script_getNumber(uint8 *srcBuffer, int16 *retval); void removeObject(int16 charId, int16 objectId); void totalPartyKill(); - int16 getRandom(int16 maxVal); void removeCharacterFromTeam(int16 teamMemberId); - void emptyFunction(int i); void refreshTeamSize(); bool isCharacterATeamMember(int16 id); bool isTPK(); - Common::KeyCode getInput(int16 delay); void handleWinSequence(); bool giveItemTo(int16 charId, int16 objectId, int altCharId); - void drawString(const char *str, int16 startX, int16 startY, uint16 unkFl); - void displayCenteredString(const char *str, int16 minX, int16 maxX, int16 posY); int16 chooseCharacterToReplace(); int16 handleCharacterJoining(); - void drawMapWindow(); - void copyString(char *srcStr, char *destStr); int16 script_parse(uint8 *str, int posX, int posY, int maxX, int maxY, int argC); void sub133E5(uint8 *impPtr, int posX, int posY, int maxX, int maxY, int argC); - void displayGameScreen(); void sub221FA(uint8 *impArray, bool flag); - void drawUpperLeftBorders(); - void drawUpperRightBorders(); - void drawBottomBorders(); void sub15A28(int16 arg0, int16 arg2); void sub2455E(int16 arg0, int16 arg1, int16 arg2); int16 sub1C219(uint8 *str, int menuType, int arg4, bool displayTeamWindowFl); int16 sub151FD(int16 posX, int16 posY); - void drawChar(uint8 curChar, int16 posX, int posY); - void setTextColorWhite(); - void setTextColorRed(); - void setTextColorGrey(); bool isPosOutOfMap(int16 mapPosX, int16 mapPosY); void goSouth(); void goNorth(); @@ -354,13 +325,8 @@ class EfhEngine : public Engine { void goSouthWest(); void handleNewRoundEffects(); bool handleDeathMenu(); - - void setNumLock(); void computeMapAnimation(); void unkFct_anim(); - void setNextCharacterPos(); - void displayStringAtTextPos(const char *message); - void unkFct_displayMenuBox_2(int16 color); int8 sub16B08(int16 monsterId); bool moveMonsterAwayFromTeam(int16 monsterId); bool moveMonsterTowardsTeam(int16 monsterId); @@ -379,7 +345,6 @@ class EfhEngine : public Engine { bool checkMonsterGroupDistance1OrLess(int16 monsterId); bool sub21820(int16 monsterId, int16 arg2, int16 itemId); void sub221D2(int16 monsterId); - Common::KeyCode getInputBlocking(); void sub22AA8(int16 arg0); bool sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemId, int16 arg8, int16 imageSetId); int8 sub15581(int16 mapPosX, int16 mapPosY, int16 arg4); @@ -388,24 +353,73 @@ class EfhEngine : public Engine { void displayStatusMenu(int16 windowId); void countRightWindowItems(int16 menuId, int16 charId); int16 getXPLevel(int32 xp); - void displayChar(char character); void displayCharacterSummary(int16 curMenuLine, int16 npcId); void displayCharacterInformationOrSkills(int16 curMenuLine, int16 npcId); void displayStatusMenuActions(int16 menuId, int16 curMenuLine, int16 npcId); void unk_StatusMenu(int16 windowId, int16 menuId, int16 curMenuLine, int16 charId, bool unusedFl, bool refreshFl); - void displayWindow(uint8 *buffer, int16 posX, int16 posY, uint8 *dest); void sub18E80(int16 charId, int16 windowId, int16 menuId, int16 curMenuLine); - int16 displayString_3(const char * str, bool animFl, int16 charId, int16 windowId, int16 menuId, int16 curMenuLine); + int16 displayString_3(const char *str, bool animFl, int16 charId, int16 windowId, int16 menuId, int16 curMenuLine); bool isItemCursed(int16 itemId); bool hasObjectEquipped(int16 charId, int16 _objectId); void equipCursedItem(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine); void sub191FF(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine); + void sub1E028(int16 id, uint8 mask, int16 groupFl); + bool sub1BA9B(int16 groupId, int16 id); + int16 sub15538(int16 mapPosX, int16 mapPosY); + void setCharacterObjectToBroken(int16 charId, int16 objectId); + Common::KeyCode selectOtherCharFromTeam(); int16 sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine, int16 argA); - bool getValidationFromUser(); int16 handleStatusMenu(int16 gameMode, int16 charId); + bool sub16E14(); + + // Graphics + void initPalette(); + void drawLeftCenterBox(); + void displayAnimFrame(); + void displayAnimFrames(int16 animId, bool displayMenuBoxFl); + void displayFctFullScreen(); + void copyDirtyRect(int16 minX, int16 minY, int16 maxX, int16 maxY); + void copyGraphicBufferFromTo(EfhGraphicsStruct *efh_graphics_struct, EfhGraphicsStruct *efh_graphics_struct1, const Common::Rect &rect, int16 min_x, int16 min_y); + void displayBufferBmAtPos(BufferBM *bufferBM, int16 posX, int16 posY); + void drawRect(int minX, int minY, int maxX, int maxY); + void drawColoredRect(int minX, int minY, int maxX, int maxY, int color); + void clearScreen(int color); + void displayRawDataAtPos(uint8 *imagePtr, int16 posX, int16 posY); + void drawString(const char *str, int16 startX, int16 startY, uint16 unkFl); + void displayCenteredString(const char *str, int16 minX, int16 maxX, int16 posY); + void drawMapWindow(); + void displayGameScreen(); + void drawUpperLeftBorders(); + void drawUpperRightBorders(); + void drawBottomBorders(); + void drawChar(uint8 curChar, int16 posX, int posY); + void setTextColorWhite(); + void setTextColorRed(); + void setTextColorGrey(); + void displayStringAtTextPos(const char *message); + void unkFct_displayMenuBox_2(int16 color); + void setNextCharacterPos(); + void displayChar(char character); + void displayWindow(uint8 *buffer, int16 posX, int16 posY, uint8 *dest); + + // Utils + int32 readFileToBuffer(Common::String &filename, uint8 *destBuffer); + void setDefaultNoteDuration(); + void decryptImpFile(bool techMapFl); + void loadImageSet(int imageSetId, uint8 *buffer, uint8 **subFilesArray, uint8 *destBuffer); + void rImageFile(Common::String filename, uint8 *targetBuffer, uint8 **subFilesArray, uint8 *packedBuffer); + uint32 uncompressBuffer(uint8 *compressedBuf, uint8 *destBuf); + int16 getRandom(int16 maxVal); + Common::KeyCode getLastCharAfterAnimCount(int16 delay); + Common::KeyCode getInput(int16 delay); Common::KeyCode waitForKey(); Common::KeyCode mapInputCode(Common::KeyCode input); - bool sub16E14(); + Common::KeyCode handleAndMapInput(bool animFl); + Common::KeyCode getInputBlocking(); + void setNumLock(); + void copyString(char *srcStr, char *destStr); + bool getValidationFromUser(); + uint8 _videoMode; uint8 _bufferCharBM[128]; @@ -502,8 +516,11 @@ class EfhEngine : public Engine { bool _word2C8D2; int16 _menuDepth; int16 _word2D0BA; + int16 _word32680[3]; + int16 _word32482[3]; int16 _word3273A[15]; + Stru32686 _stru32686[5]; }; } // End of namespace Efh diff --git a/engines/efh/graphics.cpp b/engines/efh/graphics.cpp new file mode 100644 index 000000000000..47a81e7c0194 --- /dev/null +++ b/engines/efh/graphics.cpp @@ -0,0 +1,346 @@ +/* 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "efh/efh.h" +#include "graphics/palette.h" +#include "common/system.h" + +namespace Efh { + +void EfhEngine::initPalette() { + // Strangerke - values from a tool I wrote in 2008. I can't remember if it's guess work or not. + const uint8 pal[3 * 16] = { + 0, 0, 0, + 0, 0, 170, + 0, 170, 0, + 0, 170, 170, + 170, 0, 0, + 170, 0, 170, + 170, 85, 0, + 170, 170, 170, + 85, 85, 85, + 85, 85, 255, + 1, 1, 1, + 85, 255, 255, + 255, 85, 85, + 255, 85, 255, + 255, 255, 85, + 255, 255, 255 + }; + + _system->getPaletteManager()->setPalette(pal, 0, 16); + _system->updateScreen(); +} + +void EfhEngine::drawLeftCenterBox() { + drawColoredRect(16, 8, 111, 135, 0); +} + +void EfhEngine::displayAnimFrame() { + // The original had a parameter. As it was always equal to zero, it was removed in ScummVM + + if (_animImageSetId == 0xFF) + return; + + if (_animImageSetId == 0xFE) { + displayRawDataAtPos(_portraitSubFilesArray[0], 16, 8); + return; + } + + displayRawDataAtPos(_portraitSubFilesArray[0], 16, 8); + for (int i = 0; i < 4; ++i) { + int16 var2 = _animInfo[_animImageSetId]._unkAnimArray[_unkAnimRelatedIndex].field0; + if (var2 == 0xFF) + continue; + displayRawDataAtPos(_portraitSubFilesArray[var2 + 1], _animInfo[_animImageSetId]._field46_startX[var2] + 16, _animInfo[_animImageSetId]._field3C_startY[var2] + 8); + } +} + +void EfhEngine::displayAnimFrames(int16 animId, bool displayMenuBoxFl) { + if (animId == 0xFF) + return; + + _animImageSetId = animId; + if (_animImageSetId == 0xFE) + loadNewPortrait(); + else + loadAnimImageSet(); + + if (!displayMenuBoxFl) + return; + + for (int i = 0; i < 2; ++i) { + drawLeftCenterBox(); + displayAnimFrame(); + + if (i == 0) + displayFctFullScreen(); + } +} + +void EfhEngine::displayFctFullScreen() { + // CHECKME: 319 is in the original but looks suspicious. + // copyDirtyRect(0, 0, 319, 200); + + _system->copyRectToScreen((uint8 *)_mainSurface->getPixels(), 320, 0, 0, 320, 200); + _system->updateScreen(); +} + +void EfhEngine::copyDirtyRect(int16 minX, int16 minY, int16 maxX, int16 maxY) { + _graphicsStruct->copy(_vgaGraphicsStruct2); + _initRect = Common::Rect(minX, minY, maxX, maxY); + copyGraphicBufferFromTo(_vgaGraphicsStruct2, _vgaGraphicsStruct1, _initRect, minX, minY); +} + +void EfhEngine::copyGraphicBufferFromTo(EfhGraphicsStruct *efh_graphics_struct, EfhGraphicsStruct *efh_graphics_struct1, const Common::Rect &rect, int16 min_x, int16 min_y) { + warning("STUB - copyGraphicBufferFromTo"); +} + +void EfhEngine::displayBufferBmAtPos(BufferBM *bufferBM, int16 posX, int16 posY) { + // TODO: Quick code to display stuff, may require to really reverse the actual function + uint8 *destPtr = (uint8 *)_mainSurface->getBasePtr(posX, posY); + // warning("%d %d - startX %d startY %d width %d height %d lineDataSize %d fieldD %d", posX, posY, bufferBM->_startX, bufferBM->_startY, bufferBM->_width, bufferBM->_height, bufferBM->_lineDataSize, bufferBM->_fieldD); + int counter = 0; + for (int line = 0; line < bufferBM->_height; ++line) { + for (int col = 0; col < bufferBM->_lineDataSize; ++col) { // _lineDataSize = _width / 2 + destPtr[320 * line + 2 * col] = bufferBM->_dataPtr[counter] >> 4; + destPtr[320 * line + 2 * col + 1] = bufferBM->_dataPtr[counter] & 0xF; + ++counter; + } + } + + // _system->copyRectToScreen((uint8 *)_mainSurface->getPixels(), 320, 0, 0, 320, 200); + // _system->updateScreen(); +} + +void EfhEngine::drawRect(int minX, int minY, int maxX, int maxY) { + if (minY > maxY) + SWAP(minY, maxY); + + if (minX > maxX) + SWAP(minX, maxX); + + // warning("drawRect - _graphicsStruct x %d -> %d, y %d -> %d", _graphicsStruct->_area.left, _graphicsStruct->_area.right, _graphicsStruct->_area.top, _graphicsStruct->_area.bottom); + + minX = CLIP(minX, 0, 319); + maxX = CLIP(maxX, 0, 319); + minY = CLIP(minY, 0, 199); + maxY = CLIP(maxY, 0, 199); + + int deltaY = 1 + maxY - minY; + int deltaX = 1 + maxX - minX; + + uint8 color = _defaultBoxColor & 0xF; + bool xorColor = (_defaultBoxColor & 0x40) != 0; + uint8 *destPtr = (uint8 *)_mainSurface->getBasePtr(minX, minY); + + for (int line = 0; line < deltaY; ++line) { + for (int col = 0; col < deltaX; ++col) { + if (xorColor) + destPtr[320 * line + col] ^= color; + else + destPtr[320 * line + col] = color; + } + } +} + +void EfhEngine::drawColoredRect(int minX, int minY, int maxX, int maxY, int color) { + uint8 oldValue = _defaultBoxColor; + _defaultBoxColor = color; + drawRect(minX, minY, maxX, maxY); + _defaultBoxColor = oldValue; +} + +void EfhEngine::clearScreen(int color) { + drawColoredRect(0, 0, 320, 200, color); +} + +void EfhEngine::displayRawDataAtPos(uint8 *imagePtr, int16 posX, int16 posY) { + uint16 height = READ_LE_INT16(imagePtr); + uint16 width = READ_LE_INT16(imagePtr + 2); + uint8 *imageData = imagePtr + 4; + + _imageDataPtr._lineDataSize = width; + _imageDataPtr._dataPtr = imageData; + _imageDataPtr._height = height; + _imageDataPtr._width = width * 2; // 2 pixels per byte + _imageDataPtr._startX = _imageDataPtr._startY = 0; + + displayBufferBmAtPos(&_imageDataPtr, posX, posY); +} + +void EfhEngine::drawString(const char *str, int16 startX, int16 startY, uint16 unkFl) { + uint8 *curPtr = (uint8 *)str; + uint16 lineHeight = _fontDescr._charHeight + _fontDescr._extraVerticalSpace; + _unk_sub26437_flag = unkFl & 0x3FFF; + int16 minX = startX; + int16 minY = startY; // Used in case 0x8000 + int16 var6 = _fontDescr._extraLines[0] + startY - 1; // Used in case 0x8000 + + if (unkFl & 0x8000) { + warning("STUB - drawString - 0x8000"); + } + + for (uint8 curChar = *curPtr++; curChar != 0; curChar = *curPtr++) { + if (curChar == 0x0A) { + startX = minX; + startY += lineHeight; + continue; + } + + if (curChar < 0x20) + continue; + + uint16 characterId = (curChar + 0xE0) & 0xFF; + uint8 charWidth = _fontDescr._widthArray[characterId]; + + if (startX + charWidth >= 319) { + startX = minX; + startY += lineHeight; + } + + uint8 varC = _fontDescr._extraLines[characterId]; + drawChar(curChar, startX, startY + varC); + startX += charWidth + _fontDescr._extraHorizontalSpace; + } +} + +void EfhEngine::displayCenteredString(const char *str, int16 minX, int16 maxX, int16 posY) { + uint16 length = getStringWidth(str); + int16 startCenteredDisplayX = minX + (maxX - minX - length) / 2; + drawString(str, startCenteredDisplayX, posY, _textColor); +} + +void EfhEngine::drawMapWindow() { + drawColoredRect(128, 8, 303, 135, 0); +} + +void EfhEngine::displayGameScreen() { + clearScreen(0); + drawUpperLeftBorders(); + drawUpperRightBorders(); + drawBottomBorders(); + displayAnimFrame(); + displayLowStatusScreen(false); +} + +void EfhEngine::drawUpperLeftBorders() { + displayRawDataAtPos(_circleImageSubFileArray[0], 0, 0); + displayRawDataAtPos(_circleImageSubFileArray[1], 112, 0); + displayRawDataAtPos(_circleImageSubFileArray[3], 16, 0); +} + +void EfhEngine::drawUpperRightBorders() { + displayRawDataAtPos(_circleImageSubFileArray[2], 304, 0); + displayRawDataAtPos(_circleImageSubFileArray[4], 128, 0); +} + +void EfhEngine::drawBottomBorders() { + displayRawDataAtPos(_circleImageSubFileArray[7], 16, 136); + displayRawDataAtPos(_circleImageSubFileArray[8], 16, 192); + displayRawDataAtPos(_circleImageSubFileArray[5], 0, 136); + displayRawDataAtPos(_circleImageSubFileArray[6], 304, 136); +} + +void EfhEngine::drawChar(uint8 curChar, int16 posX, int posY) { + // Quick hacked display, may require rework + uint8 *destPtr = (uint8 *)_mainSurface->getBasePtr(posX, posY); + + int16 charId = curChar - 0x20; + uint8 width = _fontDescr._widthArray[charId]; + + for (int16 line = 0; line < 8; ++line) { + int16 x = 0; + for (int i = 7; i >= 7 - width; --i) { + if (_fontDescr._fontData[charId]._lines[line] & (1 << i)) + destPtr[320 * line + x] = _textColor; + ++x; + } + } +} + +void EfhEngine::setTextColorWhite() { + if (_videoMode == 8) // CGA + _textColor = 0x3; + else + _textColor = 0xF; +} + +void EfhEngine::setTextColorRed() { + if (_videoMode == 8) // CGA + _textColor = 0x2; + else + _textColor = 0xC; +} + +void EfhEngine::setTextColorGrey() { + if (_videoMode == 8) // CGA + _textColor = 0x1; + else + _textColor = 0x8; +} + +void EfhEngine::displayStringAtTextPos(const char *message) { + drawString(message, _textPosX, _textPosY, _textColor); + _textPosX += getStringWidth(message) + 1; + setNextCharacterPos(); +} + +void EfhEngine::unkFct_displayMenuBox_2(int16 color) { + drawColoredRect(16, 152, 302, 189, color); +} + +void EfhEngine::setNextCharacterPos() { + if (_textPosX <= 311) + return; + + _textPosX = 0; + _textPosY += 8; + + if (_textPosY > 191) + _textPosY = 0; +} + +void EfhEngine::displayChar(char character) { + char buffer[2]; + buffer[0] = character; + buffer[1] = 0; + + drawString(buffer, _textPosX, _textPosY, _textColor); + _textPosX += getStringWidth(buffer) + 1; + setNextCharacterPos(); +} + +void EfhEngine::displayWindow(uint8 *buffer, int16 posX, int16 posY, uint8 *dest) { + if (buffer == nullptr) { + warning("Target Buffer Not Defined...DCImage!"); // That's the original message... And yes, it's wrong: it's checking the source buffer :) + return; + } + + // Only MCGA handled, the rest is skipped + uncompressBuffer(buffer, dest); + displayRawDataAtPos(dest, posX, posY); + displayFctFullScreen(); + displayRawDataAtPos(dest, posX, posY); +} + +} // End of namespace Efh diff --git a/engines/efh/module.mk b/engines/efh/module.mk index cd1d0983a97d..158d389f1c3b 100644 --- a/engines/efh/module.mk +++ b/engines/efh/module.mk @@ -3,6 +3,8 @@ MODULE := engines/efh MODULE_OBJS = \ constants.o \ efh.o \ + graphics.o \ + utils.o \ metaengine.o MODULE_DIRS += \ diff --git a/engines/efh/utils.cpp b/engines/efh/utils.cpp new file mode 100644 index 000000000000..e8b99457842d --- /dev/null +++ b/engines/efh/utils.cpp @@ -0,0 +1,318 @@ +/* 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "efh/efh.h" +#include "common/system.h" +#include "common/random.h" + +namespace Efh { + +int32 EfhEngine::readFileToBuffer(Common::String &filename, uint8 *destBuffer) { + Common::File f; + if (!f.open(filename)) + error("Unable to find file %s", filename.c_str()); + + int size = f.size(); + + return f.read(destBuffer, size); +} + +void EfhEngine::setDefaultNoteDuration() { + // Original implementation is based on the int1C, which is triggered at 18.2065Hz. + // Every 4 times, it sets a flag (thus, approx every 220ms) + // The function was checking the keyboard in a loop, incrementing a counter and setting the last character read + // The "_defaultNoteDuration" was then set to 7 times this counter + // + // No implementation required in ScummVM +} + +void EfhEngine::decryptImpFile(bool techMapFl) { + uint16 counter = 0; + uint16 target; + uint8 *curPtr; + + if (!techMapFl) { + _imp2PtrArray[counter++] = curPtr = _imp2; + target = 431; + } else { + _imp2PtrArray[counter++] = curPtr = _imp1; + target = 99; + } + + do { + *curPtr = (*curPtr - 3) ^ 0xD7; + if (*curPtr == 0x40) { + curPtr += 3; + if (!techMapFl) + _imp2PtrArray[counter++] = curPtr; + else + _imp1PtrArray[counter++] = curPtr; + } else + ++curPtr; + } while (*curPtr != 0x60 && counter <= target); + +// TODO: remove the dump part + Common::DumpFile dump; + if (!techMapFl) { + dump.open("imp2_unc.dump"); + dump.write(_imp2, curPtr - _imp2); + } else { + dump.open("imp1_unc.dump"); + dump.write(_imp1, curPtr - _imp1); + } + dump.flush(); + dump.close(); +} + +void EfhEngine::loadImageSet(int imageSetId, uint8 *buffer, uint8 **subFilesArray, uint8 *destBuffer) { + Common::String fileName = Common::String::format("imageset.%d", imageSetId); + rImageFile(fileName, buffer, subFilesArray, destBuffer); +} + +void EfhEngine::rImageFile(Common::String filename, uint8 *targetBuffer, uint8 **subFilesArray, uint8 *packedBuffer) { + readFileToBuffer(filename, packedBuffer); + uint32 size = uncompressBuffer(packedBuffer, targetBuffer); + // TODO: Keep this dump for debug purposes only + Common::DumpFile dump; + dump.open(filename + ".dump"); + dump.write(targetBuffer, size); + dump.flush(); + dump.close(); + // End of dump + + // TODO: Refactoring: once uncompressed, the container contains for each image its width, its height, and raw data (4 Bpp) + // => Write a class to handle that more properly + uint8 *ptr = targetBuffer; + uint16 counter = 0; + while (READ_LE_INT16(ptr) != 0) { + subFilesArray[counter] = ptr; + ++counter; + int16 imageWidth = READ_LE_INT16(ptr); + ptr += 2; + int16 imageHeight = READ_LE_INT16(ptr); + ptr += 2; + ptr += (imageWidth * imageHeight); + } +} + +uint32 EfhEngine::uncompressBuffer(uint8 *compressedBuf, uint8 *destBuf) { + if (compressedBuf == nullptr || destBuf == nullptr) + error("uncompressBuffer - Invalid pointer used in parameter list"); + + uint8 *curPtrDest = destBuf; + + uint16 compSize = READ_LE_UINT16(compressedBuf) + 1; + uint8 *curPtrCompressed = compressedBuf + 2; + + // Not in the original. This has been added for debug purposes (the original function doesn't return a value) + uint32 decompSize = 0; + + for (;;) { + uint8 next = *curPtrCompressed++; + if (--compSize <= 0) + break; + + if (next != 0xC3) { + *curPtrDest++ = next; + ++decompSize; + continue; + } + + next = *curPtrCompressed++; + if (--compSize <= 0) + break; + + if (next == 0) { + *curPtrDest++ = 0xC3; + ++decompSize; + continue; + } + + uint8 loopVal = next; + next = *curPtrCompressed++; + + for (int i = 0; i < loopVal; ++i) { + *curPtrDest++ = next; + ++decompSize; + } + + --compSize; + if (compSize == 0) + break; + } + + curPtrDest[0] = curPtrDest[1] = 0; + decompSize += 2; + + return decompSize; +} + +int16 EfhEngine::getRandom(int16 maxVal) { + if (maxVal == 0) + return 0; + + return 1 + _rnd->getRandomNumber(maxVal - 1); +} + +Common::KeyCode EfhEngine::getLastCharAfterAnimCount(int16 delay) { + if (delay == 0) + return Common::KEYCODE_INVALID; + + Common::KeyCode lastChar = Common::KEYCODE_INVALID; + + uint32 lastMs = _system->getMillis(); + while (delay > 0 && lastChar == Common::KEYCODE_INVALID) { + _system->delayMillis(20); + uint32 newMs = _system->getMillis(); + + if (newMs - lastMs >= 200) { + lastMs = newMs; + --delay; + unkFct_anim(); + } + + lastChar = handleAndMapInput(false); + } + + return lastChar; +} + +Common::KeyCode EfhEngine::getInput(int16 delay) { + if (delay == 0) + return Common::KEYCODE_INVALID; + + Common::KeyCode lastChar = Common::KEYCODE_INVALID; + Common::KeyCode retVal = Common::KEYCODE_INVALID; + + uint32 lastMs = _system->getMillis(); + while (delay > 0) { + _system->delayMillis(20); + uint32 newMs = _system->getMillis(); + + if (newMs - lastMs >= 200) { + lastMs = newMs; + --delay; + unkFct_anim(); + } + + lastChar = handleAndMapInput(false); + if (lastChar != Common::KEYCODE_INVALID) + retVal = lastChar; + } + + return retVal; +} + +Common::KeyCode EfhEngine::waitForKey() { + Common::KeyCode retVal = Common::KEYCODE_INVALID; + Common::Event event; + + uint32 lastMs = _system->getMillis(); + while (retVal == Common::KEYCODE_INVALID) { // TODO: Check shouldquit() + _system->delayMillis(20); + uint32 newMs = _system->getMillis(); + + if (newMs - lastMs >= 200) { + lastMs = newMs; + unkFct_anim(); + } + + _system->getEventManager()->pollEvent(event); + if (event.type == Common::EVENT_KEYUP) { + retVal = event.kbd.keycode; + } + } + + return retVal; +} + +Common::KeyCode EfhEngine::mapInputCode(Common::KeyCode input) { + // Original is doing: + // if input < a or > z : return input + // else return (input + 0xE0) + // ex: 'a' = 0x61 + 0xE0 = 0x0141, but it's a uint8 so it's 0x41 which is 'A'. + // So basically the original works with uppercase letters and do not alter the other inputs. + // => no implementation needed. + return input; +} + +Common::KeyCode EfhEngine::handleAndMapInput(bool animFl) { + // The original checks for the joystick input + Common::Event event; + _system->getEventManager()->pollEvent(event); + Common::KeyCode retVal = Common::KEYCODE_INVALID; + if (event.type == Common::EVENT_KEYUP) { + retVal = event.kbd.keycode; + } + + if (animFl) { + warning("STUB - handleAndMapInput - animFl"); + } + return retVal; +} + +Common::KeyCode EfhEngine::getInputBlocking() { + // The original checks for the joystick input + Common::Event event; + _system->getEventManager()->pollEvent(event); + Common::KeyCode retVal = Common::KEYCODE_INVALID; + + uint32 lastMs = _system->getMillis(); + while (retVal == Common::KEYCODE_INVALID) { + if (event.type == Common::EVENT_KEYUP) { + retVal = event.kbd.keycode; + } + + _system->delayMillis(20); + uint32 newMs = _system->getMillis(); + + if (newMs - lastMs >= 220) { + lastMs = newMs; + unkFct_anim(); + } + } + return retVal; +} + +void EfhEngine::setNumLock() { + // No implementation in ScummVM +} + +void EfhEngine::copyString(char *srcStr, char *destStr) { + char lastChar = 1; + int16 idx = 0; + + while (lastChar != 0) { + lastChar = destStr[idx] = srcStr[idx]; + ++idx; + } +} + +bool EfhEngine::getValidationFromUser() { + Common::KeyCode input = handleAndMapInput(true); + if (input == Common::KEYCODE_y) // or if joystick button 1 + return true; + + return false; +} + +} // End of namespace Efh From 6cc1cc1a25ba79de6fb59653fa648515a3968f87 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sun, 12 Dec 2021 19:51:27 +0100 Subject: [PATCH 088/412] Fix selectOtherCharFromTeam() --- engines/efh/efh.cpp | 7 +++++-- engines/efh/efh.h | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 2dde75fa0b35..ac758755e415 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -3478,7 +3478,7 @@ void EfhEngine::setCharacterObjectToBroken(int16 charId, int16 objectId) { _npcBuf[charId]._inventory[objectId]._ref = 0x7FFF; } -Common::KeyCode EfhEngine::selectOtherCharFromTeam() { +int16 EfhEngine::selectOtherCharFromTeam() { Common::KeyCode maxVal = (Common::KeyCode) (Common::KEYCODE_0 + _teamSize); Common::KeyCode input = Common::KEYCODE_INVALID; for (;;) { @@ -3487,7 +3487,10 @@ Common::KeyCode EfhEngine::selectOtherCharFromTeam() { break; } - return input; + if (input == Common::KEYCODE_ESCAPE) + return 0x1B; + + return (int16)input - (int16)Common::KEYCODE_0; } int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine, int16 argA) { diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 60a4407ea2ba..89844c5566bf 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -367,7 +367,7 @@ class EfhEngine : public Engine { bool sub1BA9B(int16 groupId, int16 id); int16 sub15538(int16 mapPosX, int16 mapPosY); void setCharacterObjectToBroken(int16 charId, int16 objectId); - Common::KeyCode selectOtherCharFromTeam(); + int16 selectOtherCharFromTeam(); int16 sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine, int16 argA); int16 handleStatusMenu(int16 gameMode, int16 charId); bool sub16E14(); From 36744e2dd3d88e147de93baad26752122d3b5ad6 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sun, 12 Dec 2021 23:18:23 +0100 Subject: [PATCH 089/412] EFH: Some renaming, fix a couple of issues --- engines/efh/efh.cpp | 296 ++++++++++++++++++++++---------------------- 1 file changed, 150 insertions(+), 146 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index ac758755e415..b3ff1f702ad1 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -3384,7 +3384,7 @@ void EfhEngine::sub18E80(int16 charId, int16 windowId, int16 menuId, int16 curMe } int16 EfhEngine::displayString_3(const char *str, bool animFl, int16 charId, int16 windowId, int16 menuId, int16 curMenuLine) { - int16 var2 = 0; + int16 retVal = 0; for (int16 counter = 0; counter < 2; ++counter) { unk_StatusMenu(windowId, menuId, curMenuLine, charId, true, false); @@ -3394,7 +3394,7 @@ int16 EfhEngine::displayString_3(const char *str, bool animFl, int16 charId, int script_parse((uint8 *)str, 28, 122, 105, 166, 0); displayFctFullScreen(); } else { - var2 = script_parse((uint8 *)str, 28, 122, 105, 166, -1); + retVal = script_parse((uint8 *)str, 28, 122, 105, 166, -1); } } @@ -3403,7 +3403,7 @@ int16 EfhEngine::displayString_3(const char *str, bool animFl, int16 charId, int sub18E80(charId, windowId, menuId, curMenuLine); } - return var2; + return retVal; } bool EfhEngine::isItemCursed(int16 itemId) { @@ -3497,8 +3497,8 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me char buffer1[80]; char buffer2[80]; - int16 varA6 = 0; - int16 varA4 = 0; + bool varA6 = false; + bool retVal = false; int16 itemId = _npcBuf[charId]._inventory[objectId]._ref; switch (_items[itemId].field_16 - 1) { @@ -3506,51 +3506,51 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me if (argA == 2) { displayString_3("The item emits a low droning hum...", false, charId, windowId, menuId, curMenuLine); } else { - int16 varAE = 0; + int16 victims = 0; strcat((char *)_messageToBePrinted, " The item emits a low droning hum..."); if (getRandom(100) < 50) { - for (int16 varA8 = 0; varA8 < 9; ++varA8) { - if (sub1BA9B(windowId, varA8)) { - ++varAE; - _stru32686[windowId]._field0[varA8] = 1; - _stru32686[windowId]._field2[varA8] = getRandom(8); + for (int16 counter = 0; counter < 9; ++counter) { + if (sub1BA9B(windowId, counter)) { + ++victims; + _stru32686[windowId]._field0[counter] = 1; + _stru32686[windowId]._field2[counter] = getRandom(8); } } } else { - int16 varAC = getRandom(9); - for (int16 varA8 = 0; varA8 < 9; ++varA8) { - if (varAC == 0) + int16 NumberOfTargets = getRandom(9); + for (int16 counter = 0; counter < 9; ++counter) { + if (NumberOfTargets == 0) break; - if (sub1BA9B(windowId, varA8)) { - ++varAE; - --varAC; - _stru32686[windowId]._field0[varA8] = 1; - _stru32686[windowId]._field2[varA8] = getRandom(8); + if (sub1BA9B(windowId, counter)) { + ++victims; + --NumberOfTargets; + _stru32686[windowId]._field0[counter] = 1; + _stru32686[windowId]._field2[counter] = getRandom(8); } } } // The original was duplicating this code in each branch of the previous random check. - if (varAE > 1) { - sprintf(buffer1, "%d %ss fall asleep!", varAE, kEncounters[_mapMonsters[_teamMonsterIdArray[windowId]]._MonsterRef]._name); + if (victims > 1) { + sprintf(buffer1, "%d %ss fall asleep!", victims, kEncounters[_mapMonsters[_teamMonsterIdArray[windowId]]._MonsterRef]._name); } else { - sprintf(buffer1, "%d %s falls asleep!", varAE, kEncounters[_mapMonsters[_teamMonsterIdArray[windowId]]._MonsterRef]._name); + sprintf(buffer1, "%d %s falls asleep!", victims, kEncounters[_mapMonsters[_teamMonsterIdArray[windowId]]._MonsterRef]._name); } strcat((char *)_messageToBePrinted, buffer1); } - varA6 = -1; + varA6 = true; break; case 1: if (argA == 2) { displayString_3("The item grows very cold for a moment...", false, charId, windowId, menuId, curMenuLine); } else { strcat((char *)_messageToBePrinted, " The item emits a blue beam..."); - int16 varAE = 0; + int16 victim = 0; if (getRandom(100) < 50) { for (int16 varA8 = 0; varA8 < 9; ++varA8) { if (sub1BA9B(windowId, varA8)) { - ++varAE; + ++victim; _stru32686[windowId]._field0[varA8] = 2; _stru32686[windowId]._field2[varA8] = getRandom(8); } @@ -3562,7 +3562,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me break; if (sub1BA9B(windowId, varA8)) { - ++varAE; + ++victim; --varAC; _stru32686[windowId]._field0[varA8] = 2; _stru32686[windowId]._field2[varA8] = getRandom(8); @@ -3571,16 +3571,16 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me } // : This part is only present in the original in the case < 50, but for me // it's missing in the other case as there's an effect (frozen enemies) but no feedback to the player - if (varAE > 1) { - sprintf(buffer1, "%d %ss are frozen in place!", varAE, kEncounters[_mapMonsters[_teamMonsterIdArray[windowId]]._MonsterRef]._name); + if (victim > 1) { + sprintf(buffer1, "%d %ss are frozen in place!", victim, kEncounters[_mapMonsters[_teamMonsterIdArray[windowId]]._MonsterRef]._name); } else { - sprintf(buffer1, "%d %s is frozen in place!", varAE, kEncounters[_mapMonsters[_teamMonsterIdArray[windowId]]._MonsterRef]._name); + sprintf(buffer1, "%d %s is frozen in place!", victim, kEncounters[_mapMonsters[_teamMonsterIdArray[windowId]]._MonsterRef]._name); } strcat((char *)_messageToBePrinted, buffer1); // } - varA6 = -1; + varA6 = true; break; case 2: if (argA == 2) { @@ -3590,7 +3590,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me _unkArray2C8AA[0] = 0; } - varA6 = -1; + varA6 = true; break; case 4: if (argA == 2) { @@ -3598,23 +3598,23 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me } else { strcat((char *)_messageToBePrinted, " A dark gray fiery whirlwind surrounds the poor victim...the power fades and death abounds!"); if (getRandom(100) < 50) { - for (int16 varA8 = 0; varA8 < 9; ++varA8) { + for (int16 counter = 0; counter < 9; ++counter) { if (getRandom(100) < 50) { - _mapMonsters[_teamMonsterIdArray[windowId]]._pictureRef[varA8] = 0; + _mapMonsters[_teamMonsterIdArray[windowId]]._pictureRef[counter] = 0; } } } else { - for (int16 varA8 = 0; varA8 < 9; ++varA8) { - if (sub1BA9B(windowId, varA8)) { + for (int16 counter = 0; counter < 9; ++counter) { + if (sub1BA9B(windowId, counter)) { if (getRandom(100) < 50) { - _mapMonsters[_teamMonsterIdArray[windowId]]._pictureRef[varA8] = 0; + _mapMonsters[_teamMonsterIdArray[windowId]]._pictureRef[counter] = 0; } break; } } } } - varA6 = -1; + varA6 = true; break; case 5: if (argA == 2) { @@ -3622,20 +3622,20 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me } else { if (getRandom(100) < 50) { strcat((char *)_messageToBePrinted, " A dark fiery whirlwind surrounds the poor victim...the power fades and all targeted die!"); - for (int16 varA8 = 0; varA8 < 9; ++varA8) { - _mapMonsters[_teamMonsterIdArray[windowId]]._pictureRef[varA8] = 0; + for (int16 counter = 0; counter < 9; ++counter) { + _mapMonsters[_teamMonsterIdArray[windowId]]._pictureRef[counter] = 0; } } else { strcat((char *)_messageToBePrinted, " A dark fiery whirlwind surrounds the poor victim...the power fades and one victim dies!"); - for (int16 varA8 = 0; varA8 < 9; ++varA8) { - if (sub1BA9B(windowId, varA8)) { - _mapMonsters[_teamMonsterIdArray[windowId]]._pictureRef[varA8] = 0; + for (int16 counter = 0; counter < 9; ++counter) { + if (sub1BA9B(windowId, counter)) { + _mapMonsters[_teamMonsterIdArray[windowId]]._pictureRef[counter] = 0; } } } } - varA6 = -1; + varA6 = true; break; case 12: if (argA == 2) { @@ -3644,7 +3644,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me strcat((char *)_messageToBePrinted, " The magic sparkles brilliant hues in the air!"); sub1E028(windowId, _items[itemId].field17_attackTypeDefense, true); } - varA6 = -1; + varA6 = true; break; case 14: { int16 varAA; @@ -3667,19 +3667,19 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me _word32482[varAA] = 0; } - varA6 = -1; + varA6 = true; } break; case 15: { - int16 varAA; + int16 teamCharId; if (argA == 2) { displayString_3("Who will use the item?", false, charId, windowId, menuId, curMenuLine); - varAA = selectOtherCharFromTeam(); + teamCharId = selectOtherCharFromTeam(); } else { - varAA = windowId; + teamCharId = windowId; } - if (varAA != 0x1B) { + if (teamCharId != 0x1B) { strcpy(buffer1, " The magic makes the user invisible!"); if (argA == 2) { displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); @@ -3687,12 +3687,12 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me strcat((char *)_messageToBePrinted, buffer1); } - _word32680[varAA] -= 50; - if (_word32680[varAA] < 0) - _word32680[varAA] = 0; + _word32680[teamCharId] -= 50; + if (_word32680[teamCharId] < 0) + _word32680[teamCharId] = 0; } - varA6 = -1; + varA6 = true; } break; case 16: { @@ -3709,7 +3709,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); } else { strcat((char *)_messageToBePrinted, buffer1); - varA4 = -1; + retVal = true; } // emptyFunction(2); } else { @@ -3719,7 +3719,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); } else { strcat((char *)_messageToBePrinted, buffer1); - varA4 = -1; + retVal = true; } } else { strcpy(buffer1, "The entire party vanishes in a flash...only to appear elsewhere!"); @@ -3727,12 +3727,12 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); } else { strcat((char *)_messageToBePrinted, buffer1); - varA4 = -1; + retVal = true; } } } - varA6 = -1; + varA6 = true; } break; case 17: { @@ -3746,7 +3746,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); } else { strcat((char *)_messageToBePrinted, buffer1); - varA4 = -1; + retVal = true; } // emptyFunction(2); } else { @@ -3756,7 +3756,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); } else { strcat((char *)_messageToBePrinted, buffer1); - varA4 = -1; + retVal = true; } } else { strcpy(buffer1, "The entire party vanishes in a flash...only to appear elsewhere!"); @@ -3764,31 +3764,31 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); } else { strcat((char *)_messageToBePrinted, buffer1); - varA4 = -1; + retVal = true; } } } - varA6 = -1; + varA6 = true; } break; case 18: if (argA == 2) { displayString_3("The item makes a loud noise!", false, charId, windowId, menuId, curMenuLine); } else { - int16 varAA = windowId; - if (varAA != 0x1B) { - if (_teamCharStatus[varAA]._status == 2) { // frozen + int16 teamCharId = windowId; + if (teamCharId != 0x1B) { + if (_teamCharStatus[teamCharId]._status == 2) { // frozen strcat((char *)_messageToBePrinted, " The item makes a loud noise, awakening the character!"); - _teamCharStatus[varAA]._status = 0; - _teamCharStatus[varAA]._duration = 0; + _teamCharStatus[teamCharId]._status = 0; + _teamCharStatus[teamCharId]._duration = 0; } else { strcat((char *)_messageToBePrinted, " The item makes a loud noise, but has no effect!"); } } } - varA6 = -1; + varA6 = true; break; case 19: strcpy(buffer1, " * The item breaks!"); @@ -3798,7 +3798,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me strcat((char *)_messageToBePrinted, buffer1); } setCharacterObjectToBroken(charId, objectId); - varA6 = -1; + varA6 = true; break; case 23: copyString(_items[itemId]._name, buffer2); @@ -3833,28 +3833,28 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); } else { strcat((char *)_messageToBePrinted, buffer1); - varA4 = -1; + retVal = true; } - varA6 = -1; + varA6 = true; break; case 24: { - int16 varAA; + int16 teamCharId; if (argA == 2) { displayString_3("Who will use this item?", false, charId, windowId, menuId, curMenuLine); - varAA = selectOtherCharFromTeam(); + teamCharId = selectOtherCharFromTeam(); } else - varAA = windowId; + teamCharId = windowId; - if (varAA != 0x1B) { + if (teamCharId != 0x1B) { uint8 varAE = _items[itemId].field17_attackTypeDefense; - uint8 varAC = getRandom(_items[itemId].field_19); - _npcBuf[_teamCharId[varAA]]._activeScore[varAE] += varAC; - if (_npcBuf[_teamCharId[varAA]]._activeScore[varAE] > 20) { - _npcBuf[_teamCharId[varAA]]._activeScore[varAE] = 20; + uint8 effectPoints = getRandom(_items[itemId].field_19); + _npcBuf[_teamCharId[teamCharId]]._activeScore[varAE] += effectPoints; + if (_npcBuf[_teamCharId[teamCharId]]._activeScore[varAE] > 20) { + _npcBuf[_teamCharId[teamCharId]]._activeScore[varAE] = 20; } - if (varAC > 1) - sprintf(buffer1, "%s increased %d points!", kSkillArray[varAE], varAC); + if (effectPoints > 1) + sprintf(buffer1, "%s increased %d points!", kSkillArray[varAE], effectPoints); else sprintf(buffer1, "%s increased 1 point!", kSkillArray[varAE]); @@ -3862,30 +3862,30 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); } else { strcat((char *)_messageToBePrinted, buffer1); - varA4 = -1; + retVal = true; } } - varA6 = -1; + varA6 = true; } break; case 25: { - int16 varAA; + int16 teamCharId; if (argA == 2) { displayString_3("Who will use this item?", false, charId, windowId, menuId, curMenuLine); - varAA = selectOtherCharFromTeam(); + teamCharId = selectOtherCharFromTeam(); } else - varAA = windowId; + teamCharId = windowId; - if (varAA != 0x1B) { + if (teamCharId != 0x1B) { uint8 varAE = _items[itemId].field17_attackTypeDefense; - uint8 varAC = getRandom(_items[itemId].field_19); - _npcBuf[_teamCharId[varAA]]._activeScore[varAE] -= varAC; - if (_npcBuf[_teamCharId[varAA]]._activeScore[varAE] > 20 || _npcBuf[_teamCharId[varAA]]._activeScore[varAE] < 0) { - _npcBuf[_teamCharId[varAA]]._activeScore[varAE] = 1; + uint8 effectPoints = getRandom(_items[itemId].field_19); + _npcBuf[_teamCharId[teamCharId]]._activeScore[varAE] -= effectPoints; + if (_npcBuf[_teamCharId[teamCharId]]._activeScore[varAE] > 20 || _npcBuf[_teamCharId[teamCharId]]._activeScore[varAE] < 0) { + _npcBuf[_teamCharId[teamCharId]]._activeScore[varAE] = 1; } - if (varAC > 1) - sprintf(buffer1, "%s lowered %d points!", kSkillArray[varAE], varAC); + if (effectPoints > 1) + sprintf(buffer1, "%s lowered %d points!", kSkillArray[varAE], effectPoints); else sprintf(buffer1, "%s lowered 1 point!", kSkillArray[varAE]); @@ -3893,11 +3893,11 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); } else { strcat((char *)_messageToBePrinted, buffer1); - varA4 = -1; + retVal = true; } } - varA6 = -1; + varA6 = true; } break; case 26: @@ -3906,71 +3906,71 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); } else { strcat((char *)_messageToBePrinted, buffer1); - varA4 = -1; + retVal = true; } totalPartyKill(); // emptyFunction(2); - varA6 = -1; + varA6 = true; break; case 27: { - int16 varAA; + int16 teamCharId; if (argA == 2) { displayString_3("Who will use the item?", false, charId, windowId, menuId, curMenuLine); - varAA = selectOtherCharFromTeam(); + teamCharId = selectOtherCharFromTeam(); } else { - varAA = windowId; + teamCharId = windowId; } - if (varAA != 0x1B) { - _npcBuf[_teamCharId[varAA]]._hitPoints = 0; - copyString(_npcBuf[_teamCharId[varAA]]._name, buffer2); + if (teamCharId != 0x1B) { + _npcBuf[_teamCharId[teamCharId]]._hitPoints = 0; + copyString(_npcBuf[_teamCharId[teamCharId]]._name, buffer2); sprintf(buffer1, "%s collapses, dead!!!", buffer2); if (argA == 2) { displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); } else { strcat((char *)_messageToBePrinted, buffer1); - varA4 = -1; + retVal = true; } // emptyFunction(2); } - varA6 = -1; + varA6 = true; } break; case 28: if (argA == 2) { displayString_3("The item makes a loud noise!", false, charId, windowId, menuId, curMenuLine); } else { - int16 varAA = windowId; - if (varAA != 0x1B) { - if (_teamCharStatus[varAA]._status == 0) { + int16 teamCharId = windowId; + if (teamCharId != 0x1B) { + if (_teamCharStatus[teamCharId]._status == 0) { strcat((char *)_messageToBePrinted, " The item makes a loud noise, awakening the character!"); - _teamCharStatus[varAA]._status = 0; - _teamCharStatus[varAA]._duration = 0; + _teamCharStatus[teamCharId]._status = 0; + _teamCharStatus[teamCharId]._duration = 0; } else { strcat((char *)_messageToBePrinted, " The item makes a loud noise, but has no effect!"); } } } - varA6 = -1; + varA6 = true; break; case 29: { - int16 varAA; + int16 teamCharId; if (argA == 2) { displayString_3("Who will use the item?", false, charId, windowId, menuId, curMenuLine); - varAA = selectOtherCharFromTeam(); + teamCharId = selectOtherCharFromTeam(); } else { - varAA = windowId; + teamCharId = windowId; } - if (varAA != 0x1B) { + if (teamCharId != 0x1B) { int16 varAE = getRandom(_items[itemId].field17_attackTypeDefense); - _npcBuf[_teamCharId[varA4]]._hitPoints += varAE; - if (_npcBuf[_teamCharId[varA4]]._hitPoints > _npcBuf[_teamCharId[varA4]]._maxHP) - _npcBuf[_teamCharId[varA4]]._hitPoints = _npcBuf[_teamCharId[varA4]]._maxHP; + _npcBuf[_teamCharId[teamCharId]]._hitPoints += varAE; + if (_npcBuf[_teamCharId[teamCharId]]._hitPoints > _npcBuf[_teamCharId[teamCharId]]._maxHP) + _npcBuf[_teamCharId[teamCharId]]._hitPoints = _npcBuf[_teamCharId[teamCharId]]._maxHP; - copyString(_npcBuf[_teamCharId[varAA]]._name, buffer2); + copyString(_npcBuf[_teamCharId[teamCharId]]._name, buffer2); if (varAE > 1) sprintf(buffer1, "%s is healed %d points!", buffer2, varAE); else @@ -3981,28 +3981,28 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); } else { strcat((char *)_messageToBePrinted, buffer1); - varA4 = -1; + retVal = true; } - varA6 = -1; + varA6 = true; } break; case 30: { - int16 varAA; + int16 teamCharId; if (argA == 2) { displayString_3("Who will use the item?", false, charId, windowId, menuId, curMenuLine); - varAA = selectOtherCharFromTeam(); + teamCharId = selectOtherCharFromTeam(); } else { - varAA = windowId; + teamCharId = windowId; } - if (varAA != 0x1B) { + if (teamCharId != 0x1B) { int16 varAE = getRandom(_items[itemId].field17_attackTypeDefense); - _npcBuf[_teamCharId[varA4]]._hitPoints -= varAE; - if (_npcBuf[_teamCharId[varA4]]._hitPoints < 0) - _npcBuf[_teamCharId[varA4]]._hitPoints = 0; + _npcBuf[_teamCharId[teamCharId]]._hitPoints -= varAE; + if (_npcBuf[_teamCharId[teamCharId]]._hitPoints < 0) + _npcBuf[_teamCharId[teamCharId]]._hitPoints = 0; - copyString(_npcBuf[_teamCharId[varAA]]._name, buffer2); + copyString(_npcBuf[_teamCharId[teamCharId]]._name, buffer2); if (varAE > 1) sprintf(buffer1, "%s is harmed for %d points!", buffer2, varAE); else @@ -4013,10 +4013,10 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); } else { strcat((char *)_messageToBePrinted, buffer1); - varA4 = -1; + retVal = true; } - varA6 = -1; + varA6 = true; } break; @@ -4035,7 +4035,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me break; } - if (varA6 != 0) { + if (varA6) { if ((_npcBuf[charId]._inventory[objectId]._stat1 & 0x7F) != 0x7F) { int8 varA1 = (_npcBuf[charId]._inventory[objectId]._stat1 & 0x7F) - 1; if (varA1 <= 0) { @@ -4059,7 +4059,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me } } - return varA4; + return retVal; } int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { @@ -4067,8 +4067,8 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { int16 var16 = -1; int16 windowId = -1; int16 curMenuLine = -1; - int16 var10 = 0; - int16 var2 = 0; + bool var10 = false; + bool var2 = false; saveAnimImageSetId(); @@ -4151,7 +4151,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { if (_menuDepth == 0) { menuId = windowId; if (menuId > 7) - var10 = -1; + var10 = true; else { _menuDepth = 1; curMenuLine = 0; @@ -4164,7 +4164,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { unk_StatusMenu(windowId, menuId, curMenuLine, charId, true, true); } else { var16 = curMenuLine; - var10 = -1; + var10 = true; } } break; @@ -4212,6 +4212,8 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { } } break; + default: + break; } if (curMenuLine == -1) @@ -4219,7 +4221,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { else unk_StatusMenu(windowId, menuId, curMenuLine, charId, true, true); - } while (var10 == 0); + } while (!var10); bool validationFl = true; @@ -4290,17 +4292,17 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { sub18E80(charId, windowId, menuId, curMenuLine); if (validationFl) { - int16 var6; + bool var6; int16 var8; do { if (_teamCharId[2] != -1) { var8 = displayString_3("Who will you give the item to?", false, charId, windowId, menuId, curMenuLine); - var2 = 0; + var2 = false; } else if (_teamCharId[1]) { var8 = 0x1A; - var2 = 0; + var2 = false; } else { - var2 = -1; + var2 = true; if (_teamCharId[0] == charId) var8 = 1; else @@ -4309,7 +4311,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { if (var8 != 0x1A && var8 != 0x1B) { var6 = giveItemTo(_teamCharId[var8], objectId, charId); - if (var6 == 0) { + if (!var6) { displayString_3("That character cannot carry anymore!", false, charId, windowId, menuId, curMenuLine); getLastCharAfterAnimCount(_guessAnimationAmount); } @@ -4319,9 +4321,9 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { getLastCharAfterAnimCount(_guessAnimationAmount); var8 = 0x1B; } - var6 = 0; + var6 = false; } - } while (var6 == 0 && var2 == 0 && var8 != 0x1B); + } while (!var6 && !var2 && var8 != 0x1B); if (var6) { removeObject(charId, objectId); @@ -4399,10 +4401,12 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { } } break; + default: + break; } if (menuId != 8) { - var10 = 0; + var10 = false; _menuDepth = 0; menuId = 9; var16 = -1; @@ -4465,7 +4469,7 @@ bool EfhEngine::sub16E14() { sprintf(buffer, "with %d %s", var6A, dest); } else if (var1 == 0x3E) { strcpy(buffer, "(NOT DEFINED)"); - } else if (var1 == 0x3F) { // Useless if, it's the last possible value + } else if (var1 == 0x3F) { // Useless check, it's the last possible value copyString(_npcBuf[_mapMonsters[monsterId]._MonsterRef]._name, dest); sprintf(buffer, "with %s", dest); } From 232e260453a3f858080cce3d67ec1874ad027c97 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Mon, 13 Dec 2021 01:02:18 +0100 Subject: [PATCH 090/412] EFH: Fix handleCharacterJoining, add chooseCharacterToReplace --- engines/efh/efh.cpp | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index b3ff1f702ad1..a0526edecf62 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -611,6 +611,8 @@ void EfhEngine::readItems() { _items[i].field_18 = *curPtr++; _items[i].field_19 = *curPtr++; _items[i].field_1A = *curPtr++; + + warning("%s\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x", _items[i]._name, _items[i]._damage, _items[i]._defense, _items[i]._attacks, _items[i]._uses, _items[i].field_13, _items[i]._range, _items[i]._attackType, _items[i].field_16, _items[i].field17_attackTypeDefense, _items[i].field_18, _items[i].field_19, _items[i].field_1A); } } @@ -1422,8 +1424,18 @@ bool EfhEngine::giveItemTo(int16 charId, int16 objectId, int altCharId) { } int16 EfhEngine::chooseCharacterToReplace() { - warning("STUB - chooseCharacterToReplace"); - return 0x1B; + Common::KeyCode maxVal = (Common::KeyCode)(Common::KEYCODE_0 + _teamSize); + Common::KeyCode input = Common::KEYCODE_INVALID; + for (;;) { + input = waitForKey(); + if (input == Common::KEYCODE_ESCAPE || input == Common::KEYCODE_0 || (input > Common::KEYCODE_1 && input <= maxVal)) + break; + } + + if (input == Common::KEYCODE_ESCAPE || input == Common::KEYCODE_0) + return 0x1B; + + return (int16)input - (int16)Common::KEYCODE_1; } int16 EfhEngine::handleCharacterJoining() { @@ -3487,10 +3499,10 @@ int16 EfhEngine::selectOtherCharFromTeam() { break; } - if (input == Common::KEYCODE_ESCAPE) + if (input == Common::KEYCODE_ESCAPE || input == Common::KEYCODE_0) return 0x1B; - return (int16)input - (int16)Common::KEYCODE_0; + return (int16)input - (int16)Common::KEYCODE_1; } int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine, int16 argA) { From 5f3c36217e09925953fc7c64ba07ef22533f3acb Mon Sep 17 00:00:00 2001 From: Strangerke Date: Mon, 13 Dec 2021 22:04:18 +0100 Subject: [PATCH 091/412] EFH: Implement some more stubs --- engines/efh/efh.cpp | 95 +++++++++++++++++++++++++++++++++++++--- engines/efh/efh.h | 2 +- engines/efh/graphics.cpp | 2 +- 3 files changed, 92 insertions(+), 7 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index a0526edecf62..d294bdad7ca4 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -1942,7 +1942,35 @@ void EfhEngine::sub221FA(uint8 *impArray, bool flag) { } void EfhEngine::sub15A28(int16 arg0, int16 arg2) { - warning("STUB: sub15A28"); + _drawHeroOnMapFl = false; + int16 varE = arg0 - 11; + int16 varC = arg2 - 11; + + if (varE < 0) + varE = 0; + if (varC < 0) + varC = 0; + + for (int16 counter = 0; counter <= 23; counter += 2) { + for (int16 var8 = 0; var8 <= 23; ++var8) { + int16 var4 = counter + varE; + int16 var2 = var8 + varC; + _mapGameMapPtr[var2 + 64 * var4] = _curPlace[var8 + counter * 24]; + } + redrawScreen(); + } + + for (int16 counter = 1; counter <= 23; counter += 2) { + for (int16 var8 = 0; var8 <= 23; ++var8) { + int16 var4 = counter + varE; + int16 var2 = var8 + varC; + _mapGameMapPtr[var2 + 64 * var4] = _curPlace[var8 + counter * 24]; + } + redrawScreen(); + } + + getLastCharAfterAnimCount(3); + _drawHeroOnMapFl = true; } void EfhEngine::sub2455E(int16 arg0, int16 arg2, int16 arg4) { @@ -2208,7 +2236,63 @@ void EfhEngine::handleNewRoundEffects() { } bool EfhEngine::handleDeathMenu() { - warning("STUB: handleDeathMenu"); + displayAnimFrames(20, true); + _imageSetSubFilesIdx = 213; + redrawScreen(); + + for (int16 counter = 0; counter < 2; ++counter) { + unkFct_displayMenuBox_2(0); + displayCenteredString("Darkness Prevails...Death Has Taken You!", 24, 296, 153); + setTextPos(100, 162); + setTextColorWhite(); + displayCharAtTextPos('L'); + setTextColorRed(); + displayStringAtTextPos("oad last saved game"); + setTextPos(100, 171); + setTextColorWhite(); + displayCharAtTextPos('R'); + setTextColorRed(); + displayStringAtTextPos("estart from beginning"); + setTextPos(100, 180); + setTextColorWhite(); + displayCharAtTextPos('Q'); + setTextColorRed(); + displayStringAtTextPos("uit for now"); + if (counter == 0) + displayFctFullScreen(); + } + + bool found; + for (found = false; !found;) { + Common::KeyCode input = waitForKey(); + switch (input) { + case Common::KEYCODE_l: + loadGame(); + found = true; + break; + case Common::KEYCODE_q: + return true; + break; + case Common::KEYCODE_r: + loadGame(); + loadTechMapImp(0); + _largeMapFlag = true; + _oldMapPosX = _mapPosX = 31; + _oldMapPosY = _mapPosY = 31; + _unkRelatedToAnimImageSetId = 0; + *_unkArray2C8AA = 0; + found = true; + break; + case Common::KEYCODE_x: + if (!_word2C8D7) + found = true; + break; + default: + break; + } + } + + displayAnimFrames(0xFE, true); return false; } @@ -3245,7 +3329,7 @@ void EfhEngine::displayCharacterSummary(int16 curMenuLine, int16 npcId) { if (itemId != 0x7FFF) { if (_npcBuf[npcId]._inventory[_word3273A[counter]]._stat1 & 0x80) { setTextPos(146, textPosY); - displayChar('E'); + displayCharAtTextPos('E'); } } @@ -4636,9 +4720,10 @@ void EfhEngine::loadGame() { } uint8 EfhEngine::getMapTileInfo(int16 mapPosX, int16 mapPosY) { - int size = _largeMapFlag ? 64 : 24; + if (_largeMapFlag) + return _mapGameMapPtr[mapPosX * 64 + mapPosY]; - return _mapGameMapPtr[mapPosX * size + mapPosY]; + return _curPlace[mapPosX * 24 + mapPosY]; } void EfhEngine::displayNextAnimFrame() { diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 89844c5566bf..898569f33ede 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -399,7 +399,7 @@ class EfhEngine : public Engine { void displayStringAtTextPos(const char *message); void unkFct_displayMenuBox_2(int16 color); void setNextCharacterPos(); - void displayChar(char character); + void displayCharAtTextPos(char character); void displayWindow(uint8 *buffer, int16 posX, int16 posY, uint8 *dest); // Utils diff --git a/engines/efh/graphics.cpp b/engines/efh/graphics.cpp index 47a81e7c0194..1ba345425339 100644 --- a/engines/efh/graphics.cpp +++ b/engines/efh/graphics.cpp @@ -320,7 +320,7 @@ void EfhEngine::setNextCharacterPos() { _textPosY = 0; } -void EfhEngine::displayChar(char character) { +void EfhEngine::displayCharAtTextPos(char character) { char buffer[2]; buffer[0] = character; buffer[1] = 0; From c8ee5e07dd8ed98cd5e611ceecfe4e64328fdc57 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Mon, 13 Dec 2021 22:26:36 +0100 Subject: [PATCH 092/412] EFH: Fix issue in sub221FA() --- engines/efh/efh.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index d294bdad7ca4..5ef6cd2fbe68 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -1937,6 +1937,8 @@ void EfhEngine::sub221FA(uint8 *impArray, bool flag) { _dword2C856 = impArray; sub133E5(impArray, 17, 115, 110, 133, 0); } + if (counter == 0 && flag) + displayFctFullScreen(); } } } From 468aeeaa272a69f91c5cb8b1d1e33e8a7c7da5f2 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Tue, 14 Dec 2021 00:01:49 +0100 Subject: [PATCH 093/412] EFH: Add 3 missing key mapped in main loop (some more are still missing) --- engines/efh/efh.cpp | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 5ef6cd2fbe68..6256376fbe59 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -400,7 +400,30 @@ Common::Error EfhEngine::run() { goNorthWest(); _imageSetSubFilesIdx = 147; break; - + case Common::KEYCODE_F1: + if (_teamCharId[0] != -1) { + handleStatusMenu(1, _teamCharId[0]); + _dword2C856 = nullptr; + sub15150(true); + _redrawNeededFl = true; + } + break; + case Common::KEYCODE_F2: + if (_teamCharId[1] != -1) { + handleStatusMenu(1, _teamCharId[1]); + _dword2C856 = nullptr; + sub15150(true); + _redrawNeededFl = true; + } + break; + case Common::KEYCODE_F3: + if (_teamCharId[2] != -1) { + handleStatusMenu(1, _teamCharId[2]); + _dword2C856 = nullptr; + sub15150(true); + _redrawNeededFl = true; + } + break; default: if (retVal != Common::KEYCODE_INVALID) warning("Main Loop: Unhandled input %d", retVal); From 2cf05c04326ff7d5de2ce1f28fbcfafe96e3180e Mon Sep 17 00:00:00 2001 From: Strangerke Date: Tue, 14 Dec 2021 08:34:17 +0100 Subject: [PATCH 094/412] EFH: Add keyboard mapping for save and load game --- engines/efh/efh.cpp | 59 ++++++++++++++++++++++++++++++++++++---- engines/efh/efh.h | 7 ++++- engines/efh/graphics.cpp | 16 +++++++++++ 3 files changed, 76 insertions(+), 6 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 6256376fbe59..c36a7c8975a2 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -424,6 +424,51 @@ Common::Error EfhEngine::run() { _redrawNeededFl = true; } break; + case Common::KEYCODE_F5: { // Original is using CTRL-S + for (int16 counter = 0; counter < 2; ++counter) { + unkFct_displayMenuBox_2(0); + displayCenteredString("Are You Sure You Want To Save?", 24, 296, 160); + if (counter == 0) + displayFctFullScreen(); + } + Common::KeyCode input = waitForKey(); + if (input = Common::KEYCODE_y) { + displayMenuAnswerString("-> Yes <-", 24, 296, 169); + getInput(2); + saveEfhGame(); + unkFct_displayBox(0); + displayLowStatusScreen(true); + } else { + displayMenuAnswerString("-> No!!! <-", 24, 296, 169); + getInput(2); + unkFct_displayBox(0); + displayLowStatusScreen(true); + } + + } + break; + case Common::KEYCODE_F7: { // Original is using CTRL-S + for (int16 counter = 0; counter < 2; ++counter) { + unkFct_displayMenuBox_2(0); + displayCenteredString("Are You Sure You Want To Load?", 24, 296, 160); + if (counter == 0) + displayFctFullScreen(); + } + Common::KeyCode input = waitForKey(); + if (input = Common::KEYCODE_y) { + displayMenuAnswerString("-> Yes <-", 24, 296, 169); + getInput(2); + loadEfhGame(); + unkFct_displayBox(0); + displayLowStatusScreen(true); + } else { + displayMenuAnswerString("-> No!!! <-", 24, 296, 169); + getInput(2); + unkFct_displayBox(0); + displayLowStatusScreen(true); + } + + } break; default: if (retVal != Common::KEYCODE_INVALID) warning("Main Loop: Unhandled input %d", retVal); @@ -588,7 +633,6 @@ void EfhEngine::loadTechMapImp(int16 fileId) { } void EfhEngine::loadPlacesFile(uint16 fullPlaceId, bool forceReloadFl) { - //TODO : Remove unused parameter when all the calls are implemented if (fullPlaceId == 0xFF) return; @@ -930,7 +974,7 @@ void EfhEngine::initEngine() { // Note: The original at this point saves int 24h and sets a new int24 to handle fatal failure checkProtection(); - loadGame(); + loadEfhGame(); _engineInitPending = false; } @@ -2292,14 +2336,14 @@ bool EfhEngine::handleDeathMenu() { Common::KeyCode input = waitForKey(); switch (input) { case Common::KEYCODE_l: - loadGame(); + loadEfhGame(); found = true; break; case Common::KEYCODE_q: return true; break; case Common::KEYCODE_r: - loadGame(); + loadEfhGame(); loadTechMapImp(0); _largeMapFlag = true; _oldMapPosX = _mapPosX = 31; @@ -3189,6 +3233,7 @@ int8 EfhEngine::sub15581(int16 mapPosX, int16 mapPosY, int16 arg4) { bool EfhEngine::handleFight(int16 monsterId) { warning("STUB - handleFight"); + return false; } @@ -4691,7 +4736,7 @@ void EfhEngine::checkProtection() { sub15150(true); } -void EfhEngine::loadGame() { +void EfhEngine::loadEfhGame() { // The original used a loop to check for the presence of the savegame on the current floppy. // When the savegame wasn't found, it was displaying a screen asking for Disk 1 and was setting a flag used // to call a function after loading right before returning. @@ -4744,6 +4789,10 @@ void EfhEngine::loadGame() { loadPlacesFile(_fullPlaceId, true); } +void EfhEngine::saveEfhGame() { + warning("STUB - saveEfhGame"); +} + uint8 EfhEngine::getMapTileInfo(int16 mapPosX, int16 mapPosY) { if (_largeMapFlag) return _mapGameMapPtr[mapPosX * 64 + mapPosY]; diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 898569f33ede..ab5338cc6bc9 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -249,6 +249,7 @@ class EfhEngine : public Engine { protected: Common::EventManager *_eventMan; int _lastTime; + void saveGame(); // Engine APIs Common::Error run() override; void handleMenu(); @@ -283,7 +284,8 @@ class EfhEngine : public Engine { void loadImageSetToTileBank(int16 tileBankId, int16 imageSetId); void restoreAnimImageSetId(); void checkProtection(); - void loadGame(); + void loadEfhGame(); + void saveEfhGame(); void copyCurrentPlaceToBuffer(int id); uint8 getMapTileInfo(int16 mapPosX, int16 mapPosY); void displayNextAnimFrame(); @@ -387,6 +389,7 @@ class EfhEngine : public Engine { void displayRawDataAtPos(uint8 *imagePtr, int16 posX, int16 posY); void drawString(const char *str, int16 startX, int16 startY, uint16 unkFl); void displayCenteredString(const char *str, int16 minX, int16 maxX, int16 posY); + void displayMenuAnswerString(const char *str, int16 minX, int16 maxX, int posY); void drawMapWindow(); void displayGameScreen(); void drawUpperLeftBorders(); @@ -401,6 +404,8 @@ class EfhEngine : public Engine { void setNextCharacterPos(); void displayCharAtTextPos(char character); void displayWindow(uint8 *buffer, int16 posX, int16 posY, uint8 *dest); + void displayColoredMenuBox(int16 minX, int16 minY, int16 maxX, int16 maxY, int16 color); + void unkFct_displayBox(int16 color); // Utils int32 readFileToBuffer(Common::String &filename, uint8 *destBuffer); diff --git a/engines/efh/graphics.cpp b/engines/efh/graphics.cpp index 1ba345425339..2ef7f03015e8 100644 --- a/engines/efh/graphics.cpp +++ b/engines/efh/graphics.cpp @@ -230,6 +230,12 @@ void EfhEngine::displayCenteredString(const char *str, int16 minX, int16 maxX, i drawString(str, startCenteredDisplayX, posY, _textColor); } +void EfhEngine::displayMenuAnswerString(const char *str, int16 minX, int16 maxX, int posY) { + displayCenteredString(str, minX, maxX, posY); + displayFctFullScreen(); + displayCenteredString(str, minX, maxX, posY); +} + void EfhEngine::drawMapWindow() { drawColoredRect(128, 8, 303, 135, 0); } @@ -343,4 +349,14 @@ void EfhEngine::displayWindow(uint8 *buffer, int16 posX, int16 posY, uint8 *dest displayRawDataAtPos(dest, posX, posY); } +void EfhEngine::displayColoredMenuBox(int16 minX, int16 minY, int16 maxX, int16 maxY, int16 color) { + drawColoredRect(minX, minY, maxX, maxY, color); + displayFctFullScreen(); + drawColoredRect(minX, minY, maxX, maxY, color); +} + +void EfhEngine::unkFct_displayBox(int16 color) { + displayColoredMenuBox(16, 152, 302, 189, color); +} + } // End of namespace Efh From 13e6100ec77b79e3948b3e21705ba4cd7ce8f5aa Mon Sep 17 00:00:00 2001 From: Strangerke Date: Fri, 17 Dec 2021 09:14:09 +0100 Subject: [PATCH 095/412] EFH: Start working on handleFight --- engines/efh/constants.cpp | 2 + engines/efh/constants.h | 1 + engines/efh/efh.cpp | 463 +++++++++++++++++++++++++++++++++++++- engines/efh/efh.h | 34 ++- 4 files changed, 490 insertions(+), 10 deletions(-) diff --git a/engines/efh/constants.cpp b/engines/efh/constants.cpp index 0e94b67c90f6..6bc0bf44f5cf 100644 --- a/engines/efh/constants.cpp +++ b/engines/efh/constants.cpp @@ -393,4 +393,6 @@ const uint8 kByte2C7D0[60] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +const char kPossessive[3][4] = { 'his', 'her', 'its'}; + } // End of namespace Efh diff --git a/engines/efh/constants.h b/engines/efh/constants.h index 4112f4ee4242..6aa94ee2af56 100644 --- a/engines/efh/constants.h +++ b/engines/efh/constants.h @@ -46,6 +46,7 @@ extern const Font kFontData[96]; extern const Encounter kEncounters[]; extern const char kSkillArray[37][20]; extern const uint8 kByte2C7D0[60]; +extern const char kPossessive[3][4]; } // End of namespace Efh diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index c36a7c8975a2..803283504204 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -165,6 +165,11 @@ void Stru32686::init() { } } +void Stru3244C::init() { + _field0 = 0; + _field2 = 0; +} + EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst), _gameDescription(gd) { const Common::FSNode gameDataDir(ConfMan.get("path")); @@ -224,11 +229,15 @@ EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst) for (int i = 0; i < 20; ++i) { _portraitSubFilesArray[i] = nullptr; - _ennemyNamePt2[i] = 0; - _characterNamePt2[i] = 0; - _nameBuffer[i] = 0; } + memset(_characterNamePt1, 0, 5); + memset(_characterNamePt2, 0, 20); + memset(_enemyNamePt1, 0, 5); + memset(_enemyNamePt2, 0, 20); + memset(_nameBuffer, 0, 20); + memset(_attackBuffer, 0, 20); + for (int i = 0; i < 100; ++i) { _imp1PtrArray[i] = nullptr; _mapUnknown[i].init(); @@ -255,6 +264,8 @@ EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst) _unkArray2C8AA[i] = 0; _word32680[i] = 0; _word32482[i] = 0; + _word3267A[i] = -1; + _teamLastAction[i] = 0; } for (int i = 0; i < 5; ++i) { @@ -298,6 +309,8 @@ EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst) } memset(_messageToBePrinted, 0, 400); + for (int i = 0; i < 8; ++i) + _stru3244C[i].init(); } EfhEngine::~EfhEngine() { @@ -1871,9 +1884,9 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, var110 = sub1C219((uint8 *)"Nothing...", 1, 2, true); displayFctFullScreen(); } else { - copyString(_npcBuf[_teamCharId[counter]]._name, _ennemyNamePt2); + copyString(_npcBuf[_teamCharId[counter]]._name, _enemyNamePt2); copyString(_items[var110]._name, _nameBuffer); - sprintf(dest, "%s finds a %s!", _ennemyNamePt2, _nameBuffer); + sprintf(dest, "%s finds a %s!", _enemyNamePt2, _nameBuffer); drawMapWindow(); displayFctFullScreen(); drawMapWindow(); @@ -2959,9 +2972,9 @@ bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { for (int16 counter = 0; counter < _teamSize; ++counter) { if (_npcBuf[var58].field_11 == _teamCharId[counter]) { displayMonsterAnim(monsterId); - copyString(_npcBuf[var58]._name, _ennemyNamePt2); + copyString(_npcBuf[var58]._name, _enemyNamePt2); copyString(_npcBuf[_teamCharId[counter]]._name, _characterNamePt2); - sprintf(buffer, "%s asks that %s leave your party.", _ennemyNamePt2, _characterNamePt2); + sprintf(buffer, "%s asks that %s leave your party.", _enemyNamePt2, _characterNamePt2); for (int16 i = 0; i < 2; ++i) { unkFct_displayMenuBox_2(0); _textColor = 0xE; @@ -3231,10 +3244,442 @@ int8 EfhEngine::sub15581(int16 mapPosX, int16 mapPosY, int16 arg4) { return _tileFact[imageSetId * 2]; } +void EfhEngine::sub1BCA7(int16 monsterId) { + warning("STUB: sub1BE89"); +} + +void EfhEngine::reset_stru32686() { + for (int16 counter1 = 0; counter1 < 5; ++counter1) { + for (int16 counter2 = 0; counter2 < 9; ++counter2) { + _stru32686[counter1]._field0[counter2] = 0; + _stru32686[counter1]._field2[counter2] = 0; + } + } +} + +void EfhEngine::sub1BE89(int16 monsterId) { + sub1BCA7(monsterId); + reset_stru32686(); +} + +void EfhEngine::resetTeamMonsterIdArray() { + for (int i = 0; i < 5; ++i) { + _teamMonsterIdArray[i] = -1; + } +} + +bool EfhEngine::isTeamMemberStatusNormal(int16 teamMemberId) { + if (_npcBuf[_teamCharId[teamMemberId]]._hitPoints > 0 && _teamCharStatus[teamMemberId]._status == 0) + return true; + + return false; +} + +void EfhEngine::sub1CDFA() { + warning("STUB: sub1CDFA"); +} + +bool EfhEngine::sub1CB27() { + warning("STUB: sub1CB27"); + + return false; +} + +void EfhEngine::sub1BE9A(int16 monsterId) { + warning("STUB sub1BE9A"); +} + +int16 EfhEngine::getTeamMonsterAnimId() { + int16 retVal = 0xFF; + for (int16 counter = 0; counter < 5; ++counter) { + int16 monsterGroupId = _teamMonsterIdArray[counter]; + if (monsterGroupId == -1) + continue; + + if (!unkFct_checkMonsterField8(monsterGroupId, false)) + continue; + + retVal = kEncounters[_mapMonsters[monsterGroupId]._MonsterRef]._animId; + break; + } + + if (retVal == 0xFF) + retVal = kEncounters[_mapMonsters[_teamMonsterIdArray[0]]._MonsterRef]._animId; + + return retVal; +} + +void EfhEngine::sub1C4CA(bool WhiteFl) { + warning("STUB: sub1C4CA"); +} + +void EfhEngine::displayCombatMenu(int16 charId) { + char buffer[80]; + copyString(_npcBuf[charId]._name, buffer); + strcat(buffer, ":"); + setTextColorWhite(); + setTextPos(144, 7); + displayStringAtTextPos(buffer); + setTextPos(152, 79); + displayStringAtTextPos("A"); + setTextColorRed(); + displayStringAtTextPos("ttack"); + setTextPos(195, 79); + setTextColorWhite(); + displayStringAtTextPos("H"); + setTextColorRed(); + displayStringAtTextPos("ide"); + setTextPos(152, 88); + setTextColorWhite(); + displayStringAtTextPos("D"); + setTextColorRed(); + displayStringAtTextPos("efend"); + setTextPos(195, 88); + setTextColorWhite(); + displayStringAtTextPos("R"); + setTextColorRed(); + displayStringAtTextPos("un"); + setTextPos(152, 97); + setTextColorWhite(); + displayStringAtTextPos("S"); + setTextColorRed(); + displayStringAtTextPos("tatus"); +} + +void EfhEngine::drawCombatScreen(int16 charId, bool whiteFl, bool forceDrawFl) { + for (int16 counter = 0; counter < 2; ++counter) { + if (counter == 0 || forceDrawFl) { + drawMapWindow(); + displayCenteredString("Combat", 128, 303, 9); + drawColoredRect(200, 112, 278, 132, 0); + displayCenteredString("'T' for Terrain", 128, 303, 117); + sub1C219(nullptr, 1, 0, false); + sub1C4CA(whiteFl); + displayCombatMenu(charId); + displayLowStatusScreen(false); + } + + if (counter == 0 && forceDrawFl) + displayFctFullScreen(); + } +} + +void EfhEngine::handleFight_checkEndEffect(int16 charId) { + // In the original, this function is part of handleFight. + // It has been split for readability purposes. + if (_teamCharStatus[charId]._status == 0) + return; + if (--_teamCharStatus[charId]._duration != 0) + return; + + // At this point : The status is different to 0 (normal) and the effect duration is finally 0 (end of effect) + copyString(_npcBuf[_teamCharId[charId]]._name, _enemyNamePt2); + if ((_npcBuf[_teamCharId[charId]]._possessivePronounSHL6 >> 6) == 2) { + strcpy(_enemyNamePt1, "The "); + } else { + _enemyNamePt1[0] = 0; + } + + // End of effect message depends on the type of effect + switch (_teamCharStatus[charId]._status) { + case 1: + sprintf((char *)_messageToBePrinted, "%s%s wakes up!", _enemyNamePt1, _enemyNamePt2); + break; + case 2: + sprintf((char *)_messageToBePrinted, "%s%s thaws out!", _enemyNamePt1, _enemyNamePt2); + break; + default: + sprintf((char *)_messageToBePrinted, "%s%s recovers!", _enemyNamePt1, _enemyNamePt2); + break; + } + + // The character status is back to normal + _teamCharStatus[charId]._status = 0; + + // Finally, display the message + sub1C219(_messageToBePrinted, 1, 2, true); +} + +int16 EfhEngine::sub1DEC8(int16 groupNumber) { + warning("STUB: sub1DEC8"); + return -1; +} + +int16 EfhEngine::getCharacterScore(int16 charId, int16 itemId) { + warning("STUB - getCharacterScore"); + return 90; +} + +bool EfhEngine::checkSpecialItemsOnCurrentPlace(int16 itemId) { + switch(_techData[_techDataId_MapPosX * 64 + _techDataId_MapPosY]) { + case 1: + if ((itemId < 0x58 || itemId > 0x68) && (itemId < 0x86 || itemId > 0x89) && (itemId < 0x74 || itemId > 0x76) && (itemId != 0x8C)) + return true; + return false; + case 2: + if ((itemId < 0x61 || itemId > 0x63) && (itemId < 0x74 || itemId > 0x76) && (itemId < 0x86 || itemId > 0x89) && (itemId < 0x5B || itemId > 0x5E) && (itemId < 0x66 || itemId > 0x68) && (itemId != 0x8C)) + return true; + return false; + default: + return true; + } +} + +void EfhEngine::generateSound(int16 soundType) { + warning("STUB: generateSound"); +} + +void EfhEngine::genericGenerateSound(int16 soundType, int16 repeatCount) { + if (repeatCount <= 0) + return; + + switch (soundType) { + case 0: + case 1: + case 2: + generateSound(5); + break; + case 3: + case 4: + case 6: + generateSound(9); + break; + case 5: + case 7: + generateSound(13); + break; + case 8: + case 9: + case 10: + generateSound(10); + generateSound(9); + break; + case 14: + generateSound(14); + break; + case 11: + case 12: + case 13: + for (int16 counter = 0; counter < repeatCount; ++counter) { + generateSound(17); + } + break; + case 15: + generateSound(16); + default: + break; + } +} + +void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { + // In the original, this function is part of handleFight. + // It has been split for readability purposes. + + int16 unk_monsterField5_itemId = sub1C80A(_teamCharId[teamCharId], 9, true); + if (unk_monsterField5_itemId == 0x7FFF) + unk_monsterField5_itemId = 0x3F; + int16 monsterGroupNumber = _word3267A[teamCharId]; + if (monsterGroupNumber == 0x64) + monsterGroupNumber = 0; + + if (monsterGroupNumber == -1) + return; + int16 var58; + if (_items[unk_monsterField5_itemId]._range == 4) + var58 = 5; + else + var58 = monsterGroupNumber + 1; + + int16 var54; + int16 teamMemberId; + if (_items[unk_monsterField5_itemId]._range < 3) { + teamMemberId = sub1DEC8(monsterGroupNumber); + var54 = teamMemberId + 1; + } else { + teamMemberId = 0; + var54 = 9; + } + + if (teamMemberId != -1) { + bool var6E = true; + for (int16 groupId = monsterGroupNumber; groupId < var58; ++groupId) { + if (_teamMonsterIdArray[groupId] == -1) + continue; + + for (int16 var7E = teamMemberId; var7E < var54; ++var7E) { + if (sub1BA9B(groupId, var7E) && var6E) { + int16 var5C; + if (unkFct_checkMonsterField8(groupId, true)) { + sub1E028(groupId, 9, true); + *_unkArray2C8AA += 500; + var5C = -1; + } else + var5C = 0; + + int16 var76 = getRandom(_mapMonsters[_teamMonsterIdArray[groupId]]._field_6); + int16 varInt = _teamCharId[teamCharId]; + int16 var51 = _npcBuf[varInt]._possessivePronounSHL6; + var51 >>= 6; + int16 var70 = var51; + varInt = _teamMonsterIdArray[groupId]; + int16 var5E = kEncounters[_mapMonsters[varInt]._MonsterRef]._nameArticle; + int16 charScore = getCharacterScore(_teamCharId[teamCharId], unk_monsterField5_itemId); + int16 var80 = _mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E]; + int16 var62 = 0; + int16 hitPoints = 0; + int16 originalDamage = 0; + int16 damagePointsAbsorbed = 0; + int16 var64 = _items[unk_monsterField5_itemId]._attacks *_npcBuf[_teamCharId[teamCharId]]._speed; + + warning("STUB: handleFight - Action A - Loop var84"); + + if (originalDamage < 0) + originalDamage = 0; + + hitPoints = originalDamage + damagePointsAbsorbed; + + if (checkSpecialItemsOnCurrentPlace(unk_monsterField5_itemId)) + var62 = 0; + + if (var62 > 0) { + _mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] -= originalDamage; + if (var62 > 1) { + sprintf(_attackBuffer, "%d times ", var62); + } else { + *_attackBuffer = 0; + } + } + int16 var68 = _items[unk_monsterField5_itemId]._attackType + 1; + int16 var6A = getRandom(3) - 1; + if (var5E == 2) { + strcpy(_characterNamePt1, "The "); + } else { + *_characterNamePt1 = 0; + } + + if (var70 == 2) { + strcpy(_enemyNamePt1, "The "); + } else { + *_enemyNamePt1 = 0; + } + + strcpy(_characterNamePt2, kEncounters[_mapMonsters[_teamMonsterIdArray[groupId]]._MonsterRef]._name); + copyString(_npcBuf[_teamCharId[teamCharId]]._name, _enemyNamePt2); + copyString(_items[unk_monsterField5_itemId]._name, _nameBuffer); + if (checkSpecialItemsOnCurrentPlace(unk_monsterField5_itemId)) { + warning("STUB: handleFight - Action A - Check degats"); + warning("STUB: handleFight - Action A - Shitload of checks in cascade"); + warning("STUB: handleFight - Action A - Second Shitload of checks in cascade"); + if (var5C) + strcat((char *)_messageToBePrinted, " Your actions do not go un-noticed..."); + + warning("STUB: handleFight - Action A - Check if item broke"); + warning("STUB: handleFight - Action A - Check effect"); + } else { + sprintf((char *)_messageToBePrinted, "%s%s tries to use %s %s, but it doesn',27h,'t work!", _enemyNamePt1, _enemyNamePt2, kPossessive[var70], _nameBuffer); + } + + genericGenerateSound(_items[unk_monsterField5_itemId]._attackType, var62); + sub1C219(_messageToBePrinted, 1, 2, true); + } + } + } + } +} + bool EfhEngine::handleFight(int16 monsterId) { warning("STUB - handleFight"); - - return false; + + int16 var8C = 0; + + sub1BE89(monsterId); + + if (_teamMonsterIdArray[0] == -1) { + resetTeamMonsterIdArray(); + _word2D0BC = false; + displayAnimFrames(0xFE, true); + return true; + } + + drawCombatScreen(0, false, true); + + for (bool mainLoopCond = false; !mainLoopCond;) { + if (isTPK()) { + resetTeamMonsterIdArray(); + _word2D0BC = false; + displayAnimFrames(0xFE, true); + return false; + } + + if (_teamMonsterIdArray[0] == -1) { + resetTeamMonsterIdArray(); + _word2D0BC = false; + displayAnimFrames(0xFE, true); + return true; + } + + int16 varInt = getTeamMonsterAnimId(); + displayAnimFrames(varInt, true); + for (int16 counter = 0; counter < _teamSize; ++counter) { + _word32680[counter] = 100; + _word32482[counter] = 65; + } + + if (!sub1CB27()) { + resetTeamMonsterIdArray(); + _word2D0BC = false; + totalPartyKill(); + displayAnimFrames(0xFE, true); + return false; + } + + for (int16 counter = 0; counter < _teamSize; ++counter) { + if (_teamLastAction[counter] == 0x52) + mainLoopCond = true; + } + + sub1CDFA(); + sub1C219(nullptr, 2, 1, false); + + for (int16 counter = 0; counter < 8; ++counter) { + int16 monsterGroupIdOrMonsterId = _stru3244C[counter]._field0; + if (monsterGroupIdOrMonsterId == -1) + continue; + if (monsterGroupIdOrMonsterId > 999) { + monsterGroupIdOrMonsterId -= 1000; + if (!isTeamMemberStatusNormal(monsterGroupIdOrMonsterId)) { + handleFight_checkEndEffect(monsterGroupIdOrMonsterId); + } else { + switch (_teamLastAction[monsterGroupIdOrMonsterId]) { + case 0x41:// 'A'ttack + handleFight_lastAction_A(monsterGroupIdOrMonsterId); + break; + case 0x44: // 'D'efend + warning("STUB: handlefight - last action == 44h"); + break; + case 0x48: // 'H'ide + warning("STUB: handlefight - last action == 48h"); + break; + case 0x55: // 'U' + warning("STUB: handlefight - last action == 55h"); + break; + default: + break; + } + } + } else if (unkFct_checkMonsterField8(monsterGroupIdOrMonsterId, true)) { + warning("STUB - handleFight - loop var86"); + } + } + + sub174A0(); + sub1BE9A(monsterId); + } + + resetTeamMonsterIdArray(); + _word2D0BC = false; + displayAnimFrames(0xFE, true); + return true; } void EfhEngine::displayMenuItemString(int16 menuBoxId, int thisBoxId, int minX, int maxX, int minY, const char *str) { diff --git a/engines/efh/efh.h b/engines/efh/efh.h index ab5338cc6bc9..89b42d961277 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -221,6 +221,13 @@ struct Stru32686 { void init(); }; +struct Stru3244C { + int16 _field0; + int16 _field2; + + void init(); +}; + class EfhEngine : public Engine { public: EfhEngine(OSystem *syst, const EfhGameDescription *gd); @@ -350,6 +357,25 @@ class EfhEngine : public Engine { void sub22AA8(int16 arg0); bool sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemId, int16 arg8, int16 imageSetId); int8 sub15581(int16 mapPosX, int16 mapPosY, int16 arg4); + void sub1BCA7(int16 monsterId); + void reset_stru32686(); + void sub1BE89(int16 monsterId); + void resetTeamMonsterIdArray(); + bool isTeamMemberStatusNormal(int16 id); + void sub1CDFA(); + bool sub1CB27(); + void sub1BE9A(int16 monsterId); + int16 getTeamMonsterAnimId(); + void sub1C4CA(bool WhiteFl); + void displayCombatMenu(int16 charId); + void drawCombatScreen(int16 charId, bool whiteFl, bool forceDrawFl); + void handleFight_checkEndEffect(int16 charId); + int16 sub1DEC8(int16 groupNumber); + int16 getCharacterScore(int16 charId, int16 itemId); + bool checkSpecialItemsOnCurrentPlace(int16 itemId); + void generateSound(int16 soundType); + void genericGenerateSound(int16 soundType, int16 repeatCount); + void handleFight_lastAction_A(int16 teamCharId); bool handleFight(int16 monsterId); void displayMenuItemString(int16 menuBoxId, int thisBoxId, int minX, int maxX, int minY, const char *str); void displayStatusMenu(int16 windowId); @@ -451,9 +477,12 @@ class EfhEngine : public Engine { AnimInfo _animInfo[100]; uint8 _history[256]; uint8 _techData[4096]; - char _ennemyNamePt2[20]; + char _enemyNamePt1[5]; + char _enemyNamePt2[20]; + char _characterNamePt1[5]; char _characterNamePt2[20]; char _nameBuffer[20]; + char _attackBuffer[20]; uint8 _messageToBePrinted[400]; uint8 *_mapBitmapRef; @@ -495,6 +524,7 @@ class EfhEngine : public Engine { int16 _teamMonsterIdArray[5]; CharStatus _teamCharStatus[3]; int16 _unkArray2C8AA[3]; + int16 _teamLastAction[3]; int16 _teamSize; int16 _word2C872; bool _word2C880; @@ -523,9 +553,11 @@ class EfhEngine : public Engine { int16 _word2D0BA; int16 _word32680[3]; int16 _word32482[3]; + int16 _word3267A[3]; int16 _word3273A[15]; Stru32686 _stru32686[5]; + Stru3244C _stru3244C[8]; }; } // End of namespace Efh From c164d4854e66a222c6a96b00c962848466754d90 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sat, 18 Dec 2021 00:06:17 +0100 Subject: [PATCH 096/412] EFH: More work on handleFight / Action A --- engines/efh/constants.cpp | 55 +++++++++++++++++++++++++++++++++- engines/efh/constants.h | 1 + engines/efh/efh.cpp | 62 +++++++++++++++++++++++++++++++++++++-- engines/efh/efh.h | 3 ++ 4 files changed, 117 insertions(+), 4 deletions(-) diff --git a/engines/efh/constants.cpp b/engines/efh/constants.cpp index 6bc0bf44f5cf..3416107495b1 100644 --- a/engines/efh/constants.cpp +++ b/engines/efh/constants.cpp @@ -393,6 +393,59 @@ const uint8 kByte2C7D0[60] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; -const char kPossessive[3][4] = { 'his', 'her', 'its'}; +const char kPossessive[3][4] = { "his", "her", "its"}; +const char kAttackVerbs[51][20] = { + "hits", + "strikes", + "hits", + "slashes", + "hacks", + "slashes", + "stabs", + "sticks", + "pokes", + "pounds", + "bashes", + "hammers", + "blasts", + "blasts", + "roasts", + "blasts", + "chills", + "zaps", + "zaps", + "zaps", + "zaps", + "shoots", + "hits", + "strikes", + "zaps", + "zaps", + "zaps", + "blasts", + "blasts", + "blasts", + "blasts", + "blasts", + "blasts", + "blasts", + "blasts", + "blasts", + "blasts", + "shoots", + "shoots", + "blasts", + "shoots", + "shoots", + "blasts", + "shoots", + "shoots", + "gases", + "sprays", + "fumigates", + "shoots", + "shoots", + "shoots" +}; } // End of namespace Efh diff --git a/engines/efh/constants.h b/engines/efh/constants.h index 6aa94ee2af56..a9d65f4c9fb1 100644 --- a/engines/efh/constants.h +++ b/engines/efh/constants.h @@ -47,6 +47,7 @@ extern const Encounter kEncounters[]; extern const char kSkillArray[37][20]; extern const uint8 kByte2C7D0[60]; extern const char kPossessive[3][4]; +extern const char kAttackVerbs[51][20]; } // End of namespace Efh diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 803283504204..a0c45a1ff091 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -3471,6 +3471,23 @@ void EfhEngine::genericGenerateSound(int16 soundType, int16 repeatCount) { } } +bool EfhEngine::hasAdequateDefense(int16 monsterId, uint8 attackType) { + int16 itemId = _mapMonsters[monsterId]._itemId_Weapon; + + if (_items[itemId].field_16 != 0) + return false; + + return _items[itemId].field17_attackTypeDefense == attackType; +} + +void EfhEngine::getDeathTypeDescription(int16 attackerId, int16 victimId) { + warning("STUB - getDeathTypeDescription"); +} + +void EfhEngine::getXPAndSearchCorpse(int16 charId, char *namePt1, char *namePt2, int16 monsterId) { + warning("STUB - getXPAndSearchCorpse"); +} + void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { // In the original, this function is part of handleFight. // It has been split for readability purposes. @@ -3532,7 +3549,24 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { int16 var64 = _items[unk_monsterField5_itemId]._attacks *_npcBuf[_teamCharId[teamCharId]]._speed; warning("STUB: handleFight - Action A - Loop var84"); - + // Action A - Loop var84 - Start + for (int16 var84 = 0; var84 < var64; ++var84) { + if (getRandom(100) < charScore) { + ++var62; + if (!hasAdequateDefense(_teamMonsterIdArray[groupId], _items[unk_monsterField5_itemId]._attackType)) { + int16 var7C = getRandom(_items[unk_monsterField5_itemId]._damage); + varInt = var7C - var76; + if (varInt > 0) { + originalDamage += varInt; + damagePointsAbsorbed += var76; + } else { + damagePointsAbsorbed += var7C; + } + } + } + } + // Action A - Loop var84 - End + if (originalDamage < 0) originalDamage = 0; @@ -3567,7 +3601,29 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { copyString(_npcBuf[_teamCharId[teamCharId]]._name, _enemyNamePt2); copyString(_items[unk_monsterField5_itemId]._name, _nameBuffer); if (checkSpecialItemsOnCurrentPlace(unk_monsterField5_itemId)) { - warning("STUB: handleFight - Action A - Check degats"); + // Action A - Check damages - Start + if (var62 == 0) { + sprintf((char *)_messageToBePrinted, "%s%s %s at %s%s with %s %s, but misses!", _enemyNamePt1, _enemyNamePt2, kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2, kPossessive[var70], _nameBuffer); + } else if (hitPoints <= 0){ + sprintf((char *)_messageToBePrinted, "%s%s %s %s%s %swith %s %s, but does no damage!", _enemyNamePt1, _enemyNamePt2, kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2, _attackBuffer, kPossessive[var70], _nameBuffer); + } else if (hitPoints == 1) { + sprintf((char *)_messageToBePrinted, "%s%s %s %s%s %swith %s %s for 1 point", _enemyNamePt1, _enemyNamePt2, kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2, _attackBuffer, kPossessive[var70], _nameBuffer); + if (_mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] <= 0) { + getDeathTypeDescription(groupId, teamCharId + 1000); + getXPAndSearchCorpse(_teamCharId[teamCharId], _enemyNamePt1, _enemyNamePt2, _teamMonsterIdArray[groupId]); + } else { + strcat((char *)_messageToBePrinted, "!"); + } + } else { + sprintf((char *)_messageToBePrinted, "%s%s %s %s%s %swith %s %s for %d points", _enemyNamePt1, _enemyNamePt2, kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2, _attackBuffer, kPossessive[var70], _nameBuffer, hitPoints); + if (_mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] <= 0) { + getDeathTypeDescription(groupId, teamCharId + 1000); + getXPAndSearchCorpse(_teamCharId[teamCharId], _enemyNamePt1, _enemyNamePt2, _teamMonsterIdArray[groupId]); + } else { + strcat((char *)_messageToBePrinted, "!"); + } + } + // Action A - Check damages - End warning("STUB: handleFight - Action A - Shitload of checks in cascade"); warning("STUB: handleFight - Action A - Second Shitload of checks in cascade"); if (var5C) @@ -3576,7 +3632,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { warning("STUB: handleFight - Action A - Check if item broke"); warning("STUB: handleFight - Action A - Check effect"); } else { - sprintf((char *)_messageToBePrinted, "%s%s tries to use %s %s, but it doesn',27h,'t work!", _enemyNamePt1, _enemyNamePt2, kPossessive[var70], _nameBuffer); + sprintf((char *)_messageToBePrinted, "%s%s tries to use %s %s, but it doesn't work!", _enemyNamePt1, _enemyNamePt2, kPossessive[var70], _nameBuffer); } genericGenerateSound(_items[unk_monsterField5_itemId]._attackType, var62); diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 89b42d961277..9b59535c7f47 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -375,6 +375,9 @@ class EfhEngine : public Engine { bool checkSpecialItemsOnCurrentPlace(int16 itemId); void generateSound(int16 soundType); void genericGenerateSound(int16 soundType, int16 repeatCount); + bool hasAdequateDefense(int16 monsterId, uint8 attackType); + void getDeathTypeDescription(int16 attackerId, int16 victimId); + void getXPAndSearchCorpse(int16 charId, char* namePt1, char* namePt2, int16 monsterId); void handleFight_lastAction_A(int16 teamCharId); bool handleFight(int16 monsterId); void displayMenuItemString(int16 menuBoxId, int thisBoxId, int minX, int maxX, int minY, const char *str); From f3c3f6307610ac4ab51e00440b1dc2d38dc77d3d Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sat, 18 Dec 2021 09:56:29 +0100 Subject: [PATCH 097/412] EFH: More work on handleFight / Action A (2) --- engines/efh/efh.cpp | 155 +++++++++++++++++++++++++++++++++++++++++++- engines/efh/efh.h | 1 + 2 files changed, 154 insertions(+), 2 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index a0c45a1ff091..2ccfd67cc55a 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -3488,6 +3488,124 @@ void EfhEngine::getXPAndSearchCorpse(int16 charId, char *namePt1, char *namePt2, warning("STUB - getXPAndSearchCorpse"); } +void EfhEngine::addReactionText(int16 id) { + int16 rand3 = getRandom(3); + char buffer[80]; + memset(buffer, 0, 80); + + switch (id) { + case 0: + switch (rand3) { + case 1: + sprintf(buffer, " %s%s reels from the blow!", _characterNamePt1, _characterNamePt2); + break; + case 2: + sprintf(buffer, " %s%s sways from the attack!", _characterNamePt1, _characterNamePt2); + break; + case 3: + sprintf(buffer, " %s%s looks dazed!", _characterNamePt1, _characterNamePt2); + break; + default: + break; + } + break; + case 1: + switch (rand3) { + case 1: + sprintf(buffer, " %s%s cries out in agony!", _characterNamePt1, _characterNamePt2); + break; + case 2: + sprintf(buffer, " %s%s screams from the abuse!", _characterNamePt1, _characterNamePt2); + break; + case 3: + sprintf(buffer, " %s%s wails terribly!", _characterNamePt1, _characterNamePt2); + break; + default: + break; + } + break; + case 2: + switch (rand3) { + case 1: + sprintf(buffer, " %s%s is staggering!", _characterNamePt1, _characterNamePt2); + break; + case 2: + sprintf(buffer, " %s%s falters for a moment!", _characterNamePt1, _characterNamePt2); + break; + case 3: + sprintf(buffer, " %s%s is stumbling about!", _characterNamePt1, _characterNamePt2); + break; + default: + break; + } + break; + case 3: + switch (rand3) { + case 1: + sprintf(buffer, " %s%s winces from the pain!", _characterNamePt1, _characterNamePt2); + break; + case 2: + sprintf(buffer, " %s%s cringes from the damage!", _characterNamePt1, _characterNamePt2); + break; + case 3: + sprintf(buffer, " %s%s shrinks from the wound!", _characterNamePt1, _characterNamePt2); + break; + default: + break; + } + break; + case 4: + switch (rand3) { + case 1: + sprintf(buffer, " %s%s screams!", _characterNamePt1, _characterNamePt2); + break; + case 2: + sprintf(buffer, " %s%s bellows!", _characterNamePt1, _characterNamePt2); + break; + case 3: + sprintf(buffer, " %s%s shrills!", _characterNamePt1, _characterNamePt2); + break; + default: + break; + } + break; + case 5: + switch (rand3) { + case 1: + sprintf(buffer, " %s%s chortles!", _characterNamePt1, _characterNamePt2); + break; + case 2: + sprintf(buffer, " %s%s seems amused!", _characterNamePt1, _characterNamePt2); + break; + case 3: + sprintf(buffer, " %s%s looks concerned!", _characterNamePt1, _characterNamePt2); + break; + default: + break; + } + break; + case 6: + switch (rand3) { + case 1: + sprintf(buffer, " %s%s laughs at the feeble attack!", _characterNamePt1, _characterNamePt2); + break; + case 2: + sprintf(buffer, " %s%s smiles at the pathetic attack!", _characterNamePt1, _characterNamePt2); + break; + case 3: + sprintf(buffer, " %s%s laughs at the ineffective assault!", _characterNamePt1, _characterNamePt2); + break; + default: + break; + } + break; + default: + break; + } + + strcat((char *)_messageToBePrinted, buffer); +} + void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { // In the original, this function is part of handleFight. // It has been split for readability purposes. @@ -3624,8 +3742,41 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { } } // Action A - Check damages - End - warning("STUB: handleFight - Action A - Shitload of checks in cascade"); - warning("STUB: handleFight - Action A - Second Shitload of checks in cascade"); + + // Action A - Add reaction text - Start + if (var62 != 0 && originalDamage > 0 && getRandom(100) <= 35 && _mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] > 0) { + if (_mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] - 5 <= originalDamage) { + addReactionText(0); + } else if (_mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] < var80 / 8) { + addReactionText(1); + } else if (_mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] < var80 / 4) { + addReactionText(2); + } else if (_mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] < var80 / 2) { + addReactionText(3); + } else if (_mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] < var80 / 3) { + // CHECKME: Doesn't make any sense to check /3 after /2... I don't get it + addReactionText(4); + } else if (var80 / 8 >= originalDamage) { + addReactionText(5); + } else if (originalDamage == 0 && getRandom(100) < 35) { + addReactionText(6); + } + } + // Action A - Add reaction text - End + + // Action A - Add armor absorb text - Start + if (var76 && var62 && _mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] > 0) { + char buffer[80]; + memset(buffer, 0, 80); + if (damagePointsAbsorbed <= 1) + sprintf(buffer, " %s%s's armor absorbs 1 point!", _characterNamePt1, _characterNamePt2); + else + sprintf(buffer, " %s%s',27h,'s armor absorbs %d points!", _characterNamePt1, _characterNamePt2, damagePointsAbsorbed); + + strcat((char *)_messageToBePrinted, buffer); + } + // Action A - Add armor absorb text - End + if (var5C) strcat((char *)_messageToBePrinted, " Your actions do not go un-noticed..."); diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 9b59535c7f47..ba7ac6d9a876 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -378,6 +378,7 @@ class EfhEngine : public Engine { bool hasAdequateDefense(int16 monsterId, uint8 attackType); void getDeathTypeDescription(int16 attackerId, int16 victimId); void getXPAndSearchCorpse(int16 charId, char* namePt1, char* namePt2, int16 monsterId); + void addReactionText(int16 id); void handleFight_lastAction_A(int16 teamCharId); bool handleFight(int16 monsterId); void displayMenuItemString(int16 menuBoxId, int thisBoxId, int minX, int maxX, int minY, const char *str); From 790f00cb9db6947876ec2110d5a3d02006651d25 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sat, 18 Dec 2021 10:24:13 +0100 Subject: [PATCH 098/412] EFH: Finish the implementation of handleFight / Action A --- engines/efh/efh.cpp | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 2ccfd67cc55a..43b8fc9e7cc3 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -3780,8 +3780,44 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { if (var5C) strcat((char *)_messageToBePrinted, " Your actions do not go un-noticed..."); - warning("STUB: handleFight - Action A - Check if item broke"); - warning("STUB: handleFight - Action A - Check effect"); + // Action A - Check item durability - Start + varInt = _teamCharId[teamCharId]; + var64 = sub1C80A(varInt, 9, false); + if (var64 != 0x7FFF && (_npcBuf[varInt]._inventory[var64]._stat1 & 0x7F) != 0x7F) { + var51 = _npcBuf[varInt]._inventory[var64]._stat1 & 0x7F; + --var51; + if (var51 <= 0) { + char buffer[80]; + memset(buffer, 0, 80); + sprintf(buffer, " * %s%s's %s breaks!", _enemyNamePt1, _enemyNamePt2, _nameBuffer); + strcat((char *)_messageToBePrinted, buffer); + setCharacterObjectToBroken(varInt, var64); + var6E = false; + } else { + _npcBuf[varInt]._inventory[var64]._stat1 = (_npcBuf[varInt]._inventory[var64]._stat1 & 80) + var51; + } + } + // Action A - Check item durability - End + + // Action A - Check effect - Start + if (_items[unk_monsterField5_itemId].field_16 == 1 && _mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] > 0) { + if (getRandom(100) < 35) { + _stru32686[var7E]._field0[groupId] = 1; + _stru32686[var7E]._field2[groupId] = getRandom(10); + char buffer[80]; + memset(buffer, 0, 80); + sprintf(buffer, " %s%s falls asleep!", _characterNamePt1, _characterNamePt2); + strcat((char *)_messageToBePrinted, buffer); + } + } else if (_items[unk_monsterField5_itemId].field_16 == 2 && _mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] > 0) { + _stru32686[var7E]._field0[groupId] = 2; + _stru32686[var7E]._field2[groupId] = getRandom(10); + char buffer[80]; + memset(buffer, 0, 80); + sprintf(buffer, " %s%s is frozen!", _characterNamePt1, _characterNamePt2); + strcat((char *)_messageToBePrinted, buffer); + } + // Action A - Check effect - End } else { sprintf((char *)_messageToBePrinted, "%s%s tries to use %s %s, but it doesn't work!", _enemyNamePt1, _enemyNamePt2, kPossessive[var70], _nameBuffer); } From f63a39055d729c85906b67a91f2fbaf29cc93f6e Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sat, 18 Dec 2021 20:56:40 +0100 Subject: [PATCH 099/412] EFH: Implement handlefight - lastAction D, H and U --- engines/efh/constants.cpp | 1 + engines/efh/constants.h | 1 + engines/efh/efh.cpp | 56 +++++++++++++++++++++++++++++++++++---- engines/efh/efh.h | 4 +++ 4 files changed, 57 insertions(+), 5 deletions(-) diff --git a/engines/efh/constants.cpp b/engines/efh/constants.cpp index 3416107495b1..2deb3ec07829 100644 --- a/engines/efh/constants.cpp +++ b/engines/efh/constants.cpp @@ -394,6 +394,7 @@ const uint8 kByte2C7D0[60] = { }; const char kPossessive[3][4] = { "his", "her", "its"}; +const char kPersonal[3][4] = {"him", "her", "it"}; const char kAttackVerbs[51][20] = { "hits", diff --git a/engines/efh/constants.h b/engines/efh/constants.h index a9d65f4c9fb1..0fced1a00fae 100644 --- a/engines/efh/constants.h +++ b/engines/efh/constants.h @@ -47,6 +47,7 @@ extern const Encounter kEncounters[]; extern const char kSkillArray[37][20]; extern const uint8 kByte2C7D0[60]; extern const char kPossessive[3][4]; +extern const char kPersonal[3][4]; extern const char kAttackVerbs[51][20]; } // End of namespace Efh diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 43b8fc9e7cc3..a37927929791 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -265,6 +265,7 @@ EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst) _word32680[i] = 0; _word32482[i] = 0; _word3267A[i] = -1; + _word31780[i] = 0; _teamLastAction[i] = 0; } @@ -3830,6 +3831,51 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { } } +void EfhEngine::handleFight_lastAction_D(int16 teamCharId) { + _word32482[teamCharId] -= 40; + copyString(_npcBuf[_teamCharId[teamCharId]]._name, _enemyNamePt2); + int16 var70 = _npcBuf[_teamCharId[teamCharId]]._possessivePronounSHL6 >> 6; + + if (var70 == 2) + strcpy(_enemyNamePt1, "The "); + else + *_enemyNamePt1 = 0; + + sprintf((char *)_messageToBePrinted, "%s%s prepares to defend %sself!", _enemyNamePt1, _enemyNamePt2, kPersonal[var70]); + sub1C219(_messageToBePrinted, 1, 2, true); +} + +void EfhEngine::handleFight_lastAction_H(int16 teamCharId) { + // In the original, this function is part of handleFight. + // It has been split for readability purposes. + + _word32680[teamCharId] -= 50; + copyString(_npcBuf[_teamCharId[teamCharId]]._name, _enemyNamePt2); + int16 var70 = _npcBuf[_teamCharId[teamCharId]]._possessivePronounSHL6 >> 6; + + if (var70 == 2) + strcpy(_enemyNamePt1, "The "); + else + *_enemyNamePt1 = 0; + + sprintf((char *)_messageToBePrinted, "%s%s attempts to hide %sself!", _enemyNamePt1, _enemyNamePt2, kPersonal[var70]); + sub1C219(_messageToBePrinted, 1, 2, true); +} + +void EfhEngine::handleFight_lastAction_U(int16 teamCharId) { + int16 unk_monsterField5_itemId = _npcBuf[_teamCharId[teamCharId]]._inventory[_word31780[teamCharId]]._ref; + copyString(_npcBuf[_teamCharId[teamCharId]]._name, _enemyNamePt2); + copyString(_items[unk_monsterField5_itemId]._name, _nameBuffer); + int16 var70 = _npcBuf[_teamCharId[teamCharId]]._possessivePronounSHL6 >> 6; + if (var70 == 2) + strcpy(_enemyNamePt1, "The "); + else + *_enemyNamePt1 = 0; + + sprintf((char *)_messageToBePrinted, "%s%s uses %s %s! ", _enemyNamePt1, _enemyNamePt2, kPossessive[var70], _nameBuffer); + sub1C219(_messageToBePrinted, 1, 2, true); +} + bool EfhEngine::handleFight(int16 monsterId) { warning("STUB - handleFight"); @@ -3877,7 +3923,7 @@ bool EfhEngine::handleFight(int16 monsterId) { } for (int16 counter = 0; counter < _teamSize; ++counter) { - if (_teamLastAction[counter] == 0x52) + if (_teamLastAction[counter] == 0x52) // 'R' mainLoopCond = true; } @@ -3898,13 +3944,13 @@ bool EfhEngine::handleFight(int16 monsterId) { handleFight_lastAction_A(monsterGroupIdOrMonsterId); break; case 0x44: // 'D'efend - warning("STUB: handlefight - last action == 44h"); + handleFight_lastAction_D(monsterGroupIdOrMonsterId); break; case 0x48: // 'H'ide - warning("STUB: handlefight - last action == 48h"); + handleFight_lastAction_H(monsterGroupIdOrMonsterId); break; - case 0x55: // 'U' - warning("STUB: handlefight - last action == 55h"); + case 0x55: // 'U'se + handleFight_lastAction_U(monsterGroupIdOrMonsterId); break; default: break; diff --git a/engines/efh/efh.h b/engines/efh/efh.h index ba7ac6d9a876..e6ce39afb150 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -380,6 +380,9 @@ class EfhEngine : public Engine { void getXPAndSearchCorpse(int16 charId, char* namePt1, char* namePt2, int16 monsterId); void addReactionText(int16 id); void handleFight_lastAction_A(int16 teamCharId); + void handleFight_lastAction_D(int16 teamCharId); + void handleFight_lastAction_H(int16 teamCharId); + void handleFight_lastAction_U(int16 teamCharId); bool handleFight(int16 monsterId); void displayMenuItemString(int16 menuBoxId, int thisBoxId, int minX, int maxX, int minY, const char *str); void displayStatusMenu(int16 windowId); @@ -558,6 +561,7 @@ class EfhEngine : public Engine { int16 _word32680[3]; int16 _word32482[3]; int16 _word3267A[3]; + int16 _word31780[3]; int16 _word3273A[15]; Stru32686 _stru32686[5]; From 4b7e91feade3378bb5af9cd21b76fe12c62c840c Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sun, 19 Dec 2021 15:16:40 +0100 Subject: [PATCH 100/412] EFH: More work on handleFight --- engines/efh/efh.cpp | 116 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 113 insertions(+), 3 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index a37927929791..fd8de7242a5c 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -3863,6 +3863,8 @@ void EfhEngine::handleFight_lastAction_H(int16 teamCharId) { } void EfhEngine::handleFight_lastAction_U(int16 teamCharId) { + // In the original, this function is part of handleFight. + // It has been split for readability purposes. int16 unk_monsterField5_itemId = _npcBuf[_teamCharId[teamCharId]]._inventory[_word31780[teamCharId]]._ref; copyString(_npcBuf[_teamCharId[teamCharId]]._name, _enemyNamePt2); copyString(_items[unk_monsterField5_itemId]._name, _nameBuffer); @@ -3877,8 +3879,6 @@ void EfhEngine::handleFight_lastAction_U(int16 teamCharId) { } bool EfhEngine::handleFight(int16 monsterId) { - warning("STUB - handleFight"); - int16 var8C = 0; sub1BE89(monsterId); @@ -3957,7 +3957,117 @@ bool EfhEngine::handleFight(int16 monsterId) { } } } else if (unkFct_checkMonsterField8(monsterGroupIdOrMonsterId, true)) { - warning("STUB - handleFight - loop var86"); + // handleFight - Loop on var86 - Start + for (int16 var86 = 0; var86 < 9; ++var86) { + if (sub1BA9B(monsterGroupIdOrMonsterId, var86)) { + int16 unk_monsterField5_itemId = _mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._itemId_Weapon; + if (unk_monsterField5_itemId == 0xFF) + unk_monsterField5_itemId = 0x3F; + int16 teamMemberId = -1; + int16 var54; + if (_items[unk_monsterField5_itemId]._range < 3) { + for (int16 var84 = 0; var84 < 10; ++var84) { + teamMemberId = getRandom(_teamSize) - 1; + if (checkWeaponRange(_teamMonsterIdArray[monsterGroupIdOrMonsterId], unk_monsterField5_itemId) && isTeamMemberStatusNormal(teamMemberId) && getRandom(100) < _word32680[teamMemberId]) { + break; + } + teamMemberId = -1; + } + var54 = teamMemberId + 1; + } else { + teamMemberId = 0; + var54 = _teamSize; + } + if (teamMemberId != -1) { + // handleFight - Loop on var7E - Start + for (int16 var7E = teamMemberId; var7E < var54; ++var7E) { + if (_teamCharId[var7E] == -1 || !isTeamMemberStatusNormal(var7E)) + continue; + + int16 var76 = getRandom(getEquipmentDefense(_teamCharId[var7E], false)); + varInt = _teamMonsterIdArray[monsterGroupIdOrMonsterId]; + int16 var70 = kEncounters[_mapMonsters[varInt]._MonsterRef]._nameArticle; + int16 var5E = _npcBuf[_teamCharId[var7E]]._possessivePronounSHL6 >> 6; + varInt = _items[unk_monsterField5_itemId].field_13; + _word32482[var7E] += (varInt * 5); + int16 var62 = 0; + int16 hitPoints = 0; + int16 originalDamage = 0; + int16 damagePointsAbsorbed = 0; + int16 var64 = _mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._field_1 * _items[unk_monsterField5_itemId]._attacks; + for (int16 var84 = 0; var84 < var64; ++var84) + warning("STUB: handleFight - Loop on var64"); + + if (originalDamage < 0) + originalDamage = 0; + + hitPoints = originalDamage + damagePointsAbsorbed; + if (!checkSpecialItemsOnCurrentPlace(unk_monsterField5_itemId)) + var62 = 0; + + if (var62 > 0) { + _npcBuf[_teamCharId[var7E]]._hitPoints -= originalDamage; + if (var62 > 1) + sprintf(_attackBuffer, "%d times ", var62); + else + *_attackBuffer = 0; + } + + int16 var68 = _items[unk_monsterField5_itemId]._attackType + 1; + int16 var6A = getRandom(3); + if (var5E == 2) + sprintf(_characterNamePt1, "The "); + else + *_characterNamePt1 = 0; + + if (var7E == 2) + sprintf(_enemyNamePt1, "The "); + else + *_enemyNamePt1 = 0; + + strcpy(_enemyNamePt2, kEncounters[_mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._MonsterRef]._name); + copyString(_npcBuf[_teamCharId[var7E]]._name, _characterNamePt2); + copyString(_items[unk_monsterField5_itemId]._name, _nameBuffer); + if (checkSpecialItemsOnCurrentPlace(unk_monsterField5_itemId)) { + warning("STUB: handleFight - check Damages"); + warning("STUB: handleFight - Cascade of checks"); + warning("STUB: handleFight - check armor"); + warning("STUB: handleFight - check effect"); + } else { + sprintf((char *)_messageToBePrinted, "%s%s tries to use %s %s, but it doesn't work!", _enemyNamePt1, _enemyNamePt2, kPossessive[var70], _nameBuffer); + } + genericGenerateSound(_items[unk_monsterField5_itemId]._attackType, var62); + sub1C219(_messageToBePrinted, 1, 2, true); + } + // handleFight - Loop on var7E - End + } + } else if (_mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._pictureRef[var86] > 0 && _stru32686[monsterGroupIdOrMonsterId]._field0[var86]) { + --_stru32686[monsterGroupIdOrMonsterId]._field2[var86]; + if (_stru32686[monsterGroupIdOrMonsterId]._field2[var86] <= 0) { + strcpy(_enemyNamePt2, kEncounters[_mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._MonsterRef]._name); + int16 var70 = kEncounters[_mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._MonsterRef]._nameArticle; + if (var70 == 2) + strcpy(_enemyNamePt1, "The "); + else + *_enemyNamePt1 = 0; + + switch (_stru32686[monsterGroupIdOrMonsterId]._field0[var86]) { + case 1: + sprintf((char *)_messageToBePrinted, "%s%s wakes up!", _enemyNamePt1, _enemyNamePt2); + break; + case 2: + sprintf((char *)_messageToBePrinted, "%s%s thaws out!", _enemyNamePt1, _enemyNamePt2); + break; + default: + sprintf((char *)_messageToBePrinted, "%s%s recovers!", _enemyNamePt1, _enemyNamePt2); + break; + } + _stru32686[monsterGroupIdOrMonsterId]._field0[var86] = 0; + sub1C219(_messageToBePrinted, 1, 2, true); + } + } + } + // handleFight - Loop on var86 - End } } From 706496f1bd246a95abbe22bb70b02a47fa182111 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sun, 19 Dec 2021 19:49:59 +0100 Subject: [PATCH 101/412] EFH: Implement 3 more stubs in handleFight --- engines/efh/efh.cpp | 83 ++++++++++++++++++++++++++++++++++++++++++--- engines/efh/efh.h | 1 + 2 files changed, 80 insertions(+), 4 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index fd8de7242a5c..d40df381fe0c 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -3481,6 +3481,23 @@ bool EfhEngine::hasAdequateDefense(int16 monsterId, uint8 attackType) { return _items[itemId].field17_attackTypeDefense == attackType; } +bool EfhEngine::hasAdequateDefense_2(int16 charId, uint8 attackType) { + int16 itemId = _npcBuf[charId]._unkItemId; + + if (_items[itemId].field_16 == 0 && _items[itemId].field17_attackTypeDefense == attackType) + return true; + + for (int16 counter = 0; counter < 10; ++counter) { + if (_npcBuf[charId]._inventory[counter]._ref == 0x7FFF || _npcBuf[charId]._inventory[counter]._stat1 == 0x80) + continue; + + itemId = _npcBuf[charId]._inventory[counter]._ref; + if (_items[itemId].field_16 == 0 && _items[itemId].field17_attackTypeDefense == attackType) + return true; + } + return false; +} + void EfhEngine::getDeathTypeDescription(int16 attackerId, int16 victimId) { warning("STUB - getDeathTypeDescription"); } @@ -3995,8 +4012,27 @@ bool EfhEngine::handleFight(int16 monsterId) { int16 originalDamage = 0; int16 damagePointsAbsorbed = 0; int16 var64 = _mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._field_1 * _items[unk_monsterField5_itemId]._attacks; - for (int16 var84 = 0; var84 < var64; ++var84) - warning("STUB: handleFight - Loop on var64"); + for (int16 var84 = 0; var84 < var64; ++var84) { + // handleFight - Loop var84 on var64 (objectId) - Start + if (getRandom(100) > _word32482[var7E]) + continue; + + ++var62; + + if (hasAdequateDefense_2(_teamCharId[var7E], _items[unk_monsterField5_itemId]._attackType)) + continue; + + int16 var7C = getRandom(_items[unk_monsterField5_itemId]._damage); + varInt = var7C - var76; + + if (varInt > 0) { + damagePointsAbsorbed += var76; + originalDamage += varInt; + } else { + damagePointsAbsorbed += var7C; + } + // handleFight - Loop var84 on var64 (objectId) - End + } if (originalDamage < 0) originalDamage = 0; @@ -4029,8 +4065,47 @@ bool EfhEngine::handleFight(int16 monsterId) { copyString(_npcBuf[_teamCharId[var7E]]._name, _characterNamePt2); copyString(_items[unk_monsterField5_itemId]._name, _nameBuffer); if (checkSpecialItemsOnCurrentPlace(unk_monsterField5_itemId)) { - warning("STUB: handleFight - check Damages"); - warning("STUB: handleFight - Cascade of checks"); + // handleFight - check damages - Start + if (var62 == 0) { + sprintf((char *)_messageToBePrinted, "%s%s %s at %s%s with %s %s, but misses!", _enemyNamePt1, _enemyNamePt2, kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2, kPossessive[var70], _nameBuffer); + } else if (hitPoints <= 0) { + sprintf((char *)_messageToBePrinted, "%s%s %s %s%s %swith %s %s, but does no damage!", _enemyNamePt1, _enemyNamePt2, kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2, _attackBuffer, kPossessive[var70], _nameBuffer); + } else if (hitPoints == 1) { + sprintf((char *)_messageToBePrinted, "%s%s %s %s%s %swith %s %s for 1 point", _enemyNamePt1, _enemyNamePt2, kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2, _attackBuffer, kPossessive[var70], _nameBuffer); + if (_npcBuf[_teamCharId[var7E]]._hitPoints <= 0) + getDeathTypeDescription(var7E + 1000, monsterGroupIdOrMonsterId); + else + strcat((char *)_messageToBePrinted, "!"); + } else { + sprintf((char *)_messageToBePrinted, "%s%s %s %s%s %swith %s %s for %d points", _enemyNamePt1, _enemyNamePt2, kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2, _attackBuffer, kPossessive[var70], _nameBuffer, hitPoints); + if (_npcBuf[_teamCharId[var7E]]._hitPoints <= 0) + getDeathTypeDescription(var7E + 1000, monsterGroupIdOrMonsterId); + else + strcat((char *)_messageToBePrinted, "!"); + } + // handleFight - check damages - End + + // handleFight - Add reaction text - start + if (var62 != 0 && originalDamage > 0 && getRandom(100) <= 35 && _npcBuf[_teamCharId[var7E]]._hitPoints > 0) { + if (_npcBuf[_teamCharId[var7E]]._hitPoints - 5 <= originalDamage) { + addReactionText(0); + } else if (_npcBuf[_teamCharId[var7E]]._hitPoints < _npcBuf[_teamCharId[var7E]]._maxHP / 8) { + addReactionText(1); + } else if (_npcBuf[_teamCharId[var7E]]._hitPoints < _npcBuf[_teamCharId[var7E]]._maxHP / 4) { + addReactionText(2); + } else if (_npcBuf[_teamCharId[var7E]]._hitPoints < _npcBuf[_teamCharId[var7E]]._maxHP / 2) { + addReactionText(3); + } else if (_npcBuf[_teamCharId[var7E]]._hitPoints < _npcBuf[_teamCharId[var7E]]._maxHP / 3) { + // CHECKME: Doesn't make any sense to check /3 after /2... I don't get it + addReactionText(4); + } else if (_npcBuf[_teamCharId[var7E]]._maxHP / 8 >= originalDamage) { + addReactionText(5); + } else if (originalDamage == 0 && getRandom(100) < 35) { + addReactionText(6); + } + } + // handleFight - Add reaction text - end + warning("STUB: handleFight - check armor"); warning("STUB: handleFight - check effect"); } else { diff --git a/engines/efh/efh.h b/engines/efh/efh.h index e6ce39afb150..9c13ac6aa2a2 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -376,6 +376,7 @@ class EfhEngine : public Engine { void generateSound(int16 soundType); void genericGenerateSound(int16 soundType, int16 repeatCount); bool hasAdequateDefense(int16 monsterId, uint8 attackType); + bool hasAdequateDefense_2(int16 charId, uint8 attackType); void getDeathTypeDescription(int16 attackerId, int16 victimId); void getXPAndSearchCorpse(int16 charId, char* namePt1, char* namePt2, int16 monsterId); void addReactionText(int16 id); From 73d6cf6b0a1e4bae702156f522725e91e9ea177d Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sun, 19 Dec 2021 22:58:18 +0100 Subject: [PATCH 102/412] EFH: Implement 2 more stubs in handleFight --- engines/efh/efh.cpp | 111 +++++++++++++++++++++++++++++++++++++++++++- engines/efh/efh.h | 2 + 2 files changed, 111 insertions(+), 2 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index d40df381fe0c..37bfeac18d44 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -3895,6 +3895,68 @@ void EfhEngine::handleFight_lastAction_U(int16 teamCharId) { sub1C219(_messageToBePrinted, 1, 2, true); } +char EfhEngine::getFightMessageLastCharacter(char *message) { + char *ptr = message; + + if (ptr == nullptr || *ptr == 0) + return 0; + + char lastChar = *ptr; + while (*ptr != 0) { + lastChar = *ptr++; + } + + return lastChar; +} + +void EfhEngine::sub1D8C2(int16 charId, int16 damage) { + int16 var42 = 0; + int16 var40 = _npcBuf[charId]._possessivePronounSHL6 / 64; + char buffer[40]; + char buffer2[20]; + + if (var40 > 2) { + var40 = 2; + } + + if (damage > 50) + damage = 50; + + for (int16 objectId = 0; objectId < 10; ++objectId) { + if (_npcBuf[charId]._inventory[objectId]._ref == 0x7FFF || (_npcBuf[charId]._inventory[objectId]._stat1 & 0x80) == 0 && _items[_npcBuf[charId]._inventory[objectId]._ref]._defense == 0) + continue; + + int16 var44 = damage - _npcBuf[charId]._inventory[objectId]._stat2; + _npcBuf[charId]._inventory[objectId]._stat2 -= damage; + + if (_npcBuf[charId]._inventory[objectId]._stat2 <= 0) { + copyString(_items[_npcBuf[charId]._inventory[objectId]._ref]._name, buffer2); + removeObject(charId, objectId); + + if (var42 == 0) { + var42 = 1; + sprintf(buffer, ", but %s %s", kPossessive[var40], buffer2); + strcat((char *)_messageToBePrinted, buffer); + } else { + ++var42; + sprintf(buffer, ", %s", buffer2); + strcat((char *)_messageToBePrinted, buffer); + } + } + + if (var44 > 0) + damage = var44; + } + + if (var42 == 0) { + strcat((char *)_messageToBePrinted, "!"); + } else if (var42 > 1 || getFightMessageLastCharacter((char *)_messageToBePrinted) == 's' || getFightMessageLastCharacter((char *)_messageToBePrinted) == 'S') { + strcat((char *)_messageToBePrinted, " are destroyed!"); + } else { + strcat((char *)_messageToBePrinted, " is destroyed!"); + } +} + bool EfhEngine::handleFight(int16 monsterId) { int16 var8C = 0; @@ -4106,8 +4168,53 @@ bool EfhEngine::handleFight(int16 monsterId) { } // handleFight - Add reaction text - end - warning("STUB: handleFight - check armor"); - warning("STUB: handleFight - check effect"); + // handleFight - Check armor - start + if (var76 != 0 && var62 != 0 && _npcBuf[_teamCharId[var7E]]._hitPoints > 0) { + char buffer[80]; + memset(buffer, 0, 80); + if (damagePointsAbsorbed <= 1) + sprintf(buffer, " %s%s's armor absorbs 1 point!", _characterNamePt1, _characterNamePt2); + else + sprintf(buffer, " %s%s',27h,'s armor absorbs %d points!", _characterNamePt1, _characterNamePt2, damagePointsAbsorbed); + + strcat((char *)_messageToBePrinted, buffer); + varInt = (originalDamage + damagePointsAbsorbed) / 10; + sub1D8C2(_teamCharId[var7E], varInt); + } + // handleFight - Check armor - end + + // handleFight - Check effect - start + char buffer[80]; + memset(buffer, 0, 80); + switch (_items[unk_monsterField5_itemId].field_16) { + case 1: + if (getRandom(100) < 20) { + _teamCharStatus[var7E]._status = 1; + _teamCharStatus[var7E]._duration = getRandom(10); + sprintf(buffer, " %s%s falls asleep!", _characterNamePt1, _characterNamePt2); + strcat((char *)_messageToBePrinted, buffer); + } + break; + case 2: + if (getRandom(100) < 20) { + _teamCharStatus[var7E]._status = 2; + _teamCharStatus[var7E]._duration = getRandom(10); + sprintf(buffer, " %s%s is frozen!", _characterNamePt1, _characterNamePt2); + strcat((char *)_messageToBePrinted, buffer); + } + break; + case 5: + case 6: + if (getRandom(100) < 20) { + sprintf(buffer, " %s%s's life energy is gone!", _characterNamePt1, _characterNamePt2); + strcat((char *)_messageToBePrinted, buffer); + _npcBuf[_teamCharId[var7E]]._hitPoints = 0; + } + break; + default: + break; + } + // handleFight - Check effect - end } else { sprintf((char *)_messageToBePrinted, "%s%s tries to use %s %s, but it doesn't work!", _enemyNamePt1, _enemyNamePt2, kPossessive[var70], _nameBuffer); } diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 9c13ac6aa2a2..63cd7ca2b134 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -384,6 +384,8 @@ class EfhEngine : public Engine { void handleFight_lastAction_D(int16 teamCharId); void handleFight_lastAction_H(int16 teamCharId); void handleFight_lastAction_U(int16 teamCharId); + char getFightMessageLastCharacter(char *message); + void sub1D8C2(int16 charId, int16 damage); bool handleFight(int16 monsterId); void displayMenuItemString(int16 menuBoxId, int thisBoxId, int minX, int maxX, int minY, const char *str); void displayStatusMenu(int16 windowId); From 70127ffe6d12733b094ea5c4dd739dab3aaf260c Mon Sep 17 00:00:00 2001 From: Strangerke Date: Mon, 20 Dec 2021 01:21:44 +0100 Subject: [PATCH 103/412] EFH: Implement 1 stubs --- engines/efh/efh.cpp | 127 ++++++++++++++++++++++++++++++++++++++++++-- engines/efh/efh.h | 3 ++ 2 files changed, 127 insertions(+), 3 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 37bfeac18d44..83e43bef327c 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -3246,7 +3246,7 @@ int8 EfhEngine::sub15581(int16 mapPosX, int16 mapPosY, int16 arg4) { } void EfhEngine::sub1BCA7(int16 monsterId) { - warning("STUB: sub1BE89"); + warning("STUB: sub1BCA7"); } void EfhEngine::reset_stru32686() { @@ -3280,10 +3280,131 @@ void EfhEngine::sub1CDFA() { warning("STUB: sub1CDFA"); } +void EfhEngine::sub1CAFD() { + for (int16 counter = 0; counter < 2; ++counter) { + redrawScreen(); + if (counter == 0) + displayFctFullScreen(); + } +} + +int16 EfhEngine::sub1C956(int16 charId, int16 unkFied18Val, int16 arg4) { + warning("STUB: sub1C956"); + return 0; +} + +void EfhEngine::sub1CAB6(int16 charId) { + for (int16 counter = 0; counter < 2; ++counter) { + sub15150(false); + displayLowStatusScreen(false); + drawCombatScreen(charId, false, false); + if (counter == 0) + displayFctFullScreen(); + } +} + bool EfhEngine::sub1CB27() { - warning("STUB: sub1CB27"); + int16 var4 = false; + for (int16 counter1 = 0; counter1 < _teamSize; ++counter1) { + _teamLastAction[counter1] = 0; + if (!isTeamMemberStatusNormal(counter1)) + continue; - return false; + var4 = true; + do { + drawCombatScreen(_teamCharId[counter1], false, true); + Common::KeyCode var1 = handleAndMapInput(true); + switch (var1) { + case Common::KEYCODE_a: + _teamLastAction[counter1] = 'A'; + _word3267A[counter1] = sub1C956(_teamCharId[counter1], 9, true); + if (_word3267A[counter1] == -1) + _teamLastAction[counter1] = 0; + break; + case Common::KEYCODE_d: + _teamLastAction[counter1] = 'D'; + break; + case Common::KEYCODE_h: + _teamLastAction[counter1] = 'H'; + break; + case Common::KEYCODE_r: + for (int16 counter2 = 0; counter2 < _teamSize; ++counter2) { + _teamLastAction[counter2] = 'R'; + } + return true; + case Common::KEYCODE_s: { + int16 var8 = handleStatusMenu(2, _teamCharId[counter1]); + sub1CAB6(_teamCharId[counter1]); + if (var8 > 999) { + if (var8 == 0x7D00) + _teamLastAction[counter1] = 'S'; + } else { + _teamLastAction[counter1] = 'U'; + _word31780[counter1] = var8; + int16 var6 = _npcBuf[_teamCharId[counter1]]._inventory[var8]._ref; + switch (var6 - 1) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 10: + case 12: + case 13: + _word3267A[counter1] = sub1C956(_teamCharId[counter1], 9, false); + break; + + case 9: + case 11: + case 14: + case 15: + case 18: + case 24: + case 25: + case 27: + case 28: + case 29: + case 30: + sub1C219((uint8 *)"Select Character:", 3, 1, false); + _word3267A[counter1] = selectOtherCharFromTeam(); + break; + + case 16: + case 17: + case 26: + _word3267A[counter1] = 0xC8; + break; + + case 19: + case 20: + case 21: + case 22: + case 23: + default: + break; + } + + } + + } + break; + case Common::KEYCODE_t: + sub1CAFD(); + getInputBlocking(); + drawCombatScreen(_teamCharId[counter1], false, true); + break; + default: + break; + } + } while (_teamLastAction[counter1] == 0); + + } + + return var4; } void EfhEngine::sub1BE9A(int16 monsterId) { diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 63cd7ca2b134..be921fbad96c 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -363,6 +363,9 @@ class EfhEngine : public Engine { void resetTeamMonsterIdArray(); bool isTeamMemberStatusNormal(int16 id); void sub1CDFA(); + void sub1CAFD(); + int16 sub1C956(int16 charId, int16 unkFied18Val, int16 arg4); + void sub1CAB6(int16 charId); bool sub1CB27(); void sub1BE9A(int16 monsterId); int16 getTeamMonsterAnimId(); From 668b33d2d9917526f5fa2d0aae3ac2bfe9861443 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Tue, 21 Dec 2021 00:01:23 +0100 Subject: [PATCH 104/412] EFH: Implement getDeathTypeDescription --- engines/efh/efh.cpp | 222 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 221 insertions(+), 1 deletion(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 83e43bef327c..e88f2b65709d 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -3620,7 +3620,227 @@ bool EfhEngine::hasAdequateDefense_2(int16 charId, uint8 attackType) { } void EfhEngine::getDeathTypeDescription(int16 attackerId, int16 victimId) { - warning("STUB - getDeathTypeDescription"); + int16 charId; + int16 possessivePronoun; + + if (attackerId > 999) { + charId = _teamCharId[attackerId - 1000]; + possessivePronoun = _npcBuf[charId]._possessivePronounSHL6 >> 6; + } else { + charId = _teamMonsterIdArray[attackerId]; + possessivePronoun = _mapMonsters[attackerId]._possessivePronounSHL6 >> 6; + } + + if (possessivePronoun > 2) + possessivePronoun = 2; + + int16 deathType; + if (getRandom(100) < 20) { + deathType = 0; + } else { + if (victimId >= 1000) { + charId = _teamCharId[victimId - 1000]; + if (charId == -1) + deathType = 0; + else { + int16 var6 = sub1C80A(charId, 9, true); + if (var6 == 0x7FFF) + deathType = 0; + else + deathType = _items[var6]._attackType + 1; + } + } else if (_teamMonsterIdArray[victimId] == -1) + deathType = 0; + else { + charId = _mapMonsters[_teamMonsterIdArray[victimId]]._itemId_Weapon; + deathType = _items[charId]._attackType; + } + } + + int16 rndDescrForDeathType = getRandom((3)) - 1; + char buffer[80]; + memset(buffer, 0, 80); + sprintf(buffer, "DUDE IS TOAST!"); + switch (deathType) { + case 0: + switch (rndDescrForDeathType) { + case 0: + sprintf(buffer, ", killing %s!", kPersonal[possessivePronoun]); + break; + case 1: + sprintf(buffer, ", slaughtering %s!", kPersonal[possessivePronoun]); + break; + case 2: + sprintf(buffer, ", annihilating %s!", kPersonal[possessivePronoun]); + break; + } + break; + case 1: + switch (rndDescrForDeathType) { + case 0: + sprintf(buffer, ", cutting %s in two!", kPersonal[possessivePronoun]); + break; + case 1: + sprintf(buffer, ", dicing %s into small cubes!", kPersonal[possessivePronoun]); + break; + case 2: + sprintf(buffer, ", butchering %s into lamb chops!", kPersonal[possessivePronoun]); + break; + } + break; + case 2: + switch (rndDescrForDeathType) { + case 0: + sprintf(buffer, ", piercing %s heart!", kPersonal[possessivePronoun]); + break; + case 1: + sprintf(buffer, ", leaving %s a spouting mass of blood!", kPersonal[possessivePronoun]); + break; + case 2: + sprintf(buffer, ", popping %s like a zit!", kPersonal[possessivePronoun]); + break; + } + break; + case 3: + switch (rndDescrForDeathType) { + case 0: + sprintf(buffer, ", pulping %s head over a wide area!", kPersonal[possessivePronoun]); + break; + case 1: + sprintf(buffer, ", smashing %s into a meat patty!", kPersonal[possessivePronoun]); + break; + case 2: + sprintf(buffer, ", squashing %s like a ripe tomato!", kPersonal[possessivePronoun]); + break; + } + break; + case 4: + switch (rndDescrForDeathType) { + case 0: + sprintf(buffer, ", totally incinerating %s!", kPersonal[possessivePronoun]); + break; + case 1: + sprintf(buffer, ", reducing %s to a pile of ash!", kPersonal[possessivePronoun]); + break; + case 2: + sprintf(buffer, ", leaving a blistered mass of flesh behind!"); + break; + } + break; + case 5: + switch (rndDescrForDeathType) { + case 0: + // The original has a typo: popscicle + sprintf(buffer, ", turning %s into a popsicle!", kPersonal[possessivePronoun]); + break; + case 1: + sprintf(buffer, ", encasing %s in a block of ice!", kPersonal[possessivePronoun]); + break; + case 2: + sprintf(buffer, ", shattering %s into shards!", kPersonal[possessivePronoun]); + break; + } + break; + case 6: + switch (rndDescrForDeathType) { + case 0: + sprintf(buffer, ", leaving pudding for brains"); + break; + case 1: + sprintf(buffer, ", bursting %s head like a bubble!", kPersonal[possessivePronoun]); + break; + case 2: + sprintf(buffer, ", turning %s into a mindless vegetable", kPersonal[possessivePronoun]); + break; + } + break; + case 7: + switch (rndDescrForDeathType) { + case 0: + sprintf(buffer, ", reducing %s to an oozing pile of flesh!", kPersonal[possessivePronoun]); + break; + case 1: + sprintf(buffer, ", melting %s like an ice cube in hot coffee!", kPersonal[possessivePronoun]); + break; + case 2: + sprintf(buffer, ", vaporizing %s into a steaming cloud!", kPersonal[possessivePronoun]); + break; + } + break; + case 8: + switch (rndDescrForDeathType) { + case 0: + sprintf(buffer, ", engulfing %s in black smoke puffs!", kPersonal[possessivePronoun]); + break; + case 1: + sprintf(buffer, ", sucking %s into eternity!", kPersonal[possessivePronoun]); + break; + case 2: + sprintf(buffer, ", turning %s into a mindless zombie!", kPersonal[possessivePronoun]); + break; + } + break; + case 9: + case 10: + case 11: + switch (rndDescrForDeathType) { + case 0: + sprintf(buffer, ", completely disintegrating %s!", kPersonal[possessivePronoun]); + break; + case 1: + sprintf(buffer, ", spreading %s into a fine mist!", kPersonal[possessivePronoun]); + break; + case 2: + sprintf(buffer, ", leaving a smoking crater in %s place!", kPersonal[possessivePronoun]); + break; + } + break; + case 12: + case 13: + case 14: + switch (rndDescrForDeathType) { + case 0: + sprintf(buffer, ", tearing a chunk out of %s back!", kPersonal[possessivePronoun]); + break; + case 1: + sprintf(buffer, ", blowing %s brains out!", kPersonal[possessivePronoun]); + break; + case 2: + sprintf(buffer, ", exploding %s entire chest!", kPersonal[possessivePronoun]); + break; + } + break; + case 15: + switch (rndDescrForDeathType) { + case 0: + sprintf(buffer, ", choking %s to death!", kPersonal[possessivePronoun]); + break; + case 1: + sprintf(buffer, ", melting %s lungs!", kPersonal[possessivePronoun]); + break; + case 2: + sprintf(buffer, ", leaving %s gasping for air as %s collapses!", kPersonal[possessivePronoun], kPersonal[possessivePronoun]); + break; + } + break; + case 16: + switch (rndDescrForDeathType) { + case 0: + sprintf(buffer, ", tearing a chunk out of %s back!", kPersonal[possessivePronoun]); + break; + case 1: + sprintf(buffer, ", piercing %s heart!", kPersonal[possessivePronoun]); + break; + case 2: + sprintf(buffer, ", impaling %s brain!", kPersonal[possessivePronoun]); + break; + } + break; + default: + break; + } + + strcat((char *)_messageToBePrinted, buffer); } void EfhEngine::getXPAndSearchCorpse(int16 charId, char *namePt1, char *namePt2, int16 monsterId) { From 7f389610512f5dbe43df42549df147f3959542d7 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Tue, 21 Dec 2021 00:16:29 +0100 Subject: [PATCH 105/412] EFH: Fix issue in getDeathTypeDescription, some renaming --- engines/efh/efh.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index e88f2b65709d..a475a54c8dea 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -3620,15 +3620,14 @@ bool EfhEngine::hasAdequateDefense_2(int16 charId, uint8 attackType) { } void EfhEngine::getDeathTypeDescription(int16 attackerId, int16 victimId) { - int16 charId; int16 possessivePronoun; if (attackerId > 999) { - charId = _teamCharId[attackerId - 1000]; + int16 charId = _teamCharId[attackerId - 1000]; possessivePronoun = _npcBuf[charId]._possessivePronounSHL6 >> 6; } else { - charId = _teamMonsterIdArray[attackerId]; - possessivePronoun = _mapMonsters[attackerId]._possessivePronounSHL6 >> 6; + int16 charId = _teamMonsterIdArray[attackerId]; + possessivePronoun = _mapMonsters[charId]._possessivePronounSHL6 >> 6; } if (possessivePronoun > 2) @@ -3639,7 +3638,7 @@ void EfhEngine::getDeathTypeDescription(int16 attackerId, int16 victimId) { deathType = 0; } else { if (victimId >= 1000) { - charId = _teamCharId[victimId - 1000]; + int16 charId = _teamCharId[victimId - 1000]; if (charId == -1) deathType = 0; else { @@ -3652,8 +3651,8 @@ void EfhEngine::getDeathTypeDescription(int16 attackerId, int16 victimId) { } else if (_teamMonsterIdArray[victimId] == -1) deathType = 0; else { - charId = _mapMonsters[_teamMonsterIdArray[victimId]]._itemId_Weapon; - deathType = _items[charId]._attackType; + int16 itemId = _mapMonsters[_teamMonsterIdArray[victimId]]._itemId_Weapon; + deathType = _items[itemId]._attackType; } } From 9b34c6766aa7f6315534e44a4aed370af58ea522 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Tue, 21 Dec 2021 08:29:14 +0100 Subject: [PATCH 106/412] EFH: Implement getXPAndSearchCorpse --- engines/efh/efh.cpp | 43 +++++++++++++++++++++++++++++++++++++++++-- engines/efh/efh.h | 3 ++- 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index a475a54c8dea..4f6e1ee72f33 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -1483,7 +1483,7 @@ void EfhEngine::handleWinSequence() { free(winSeqBuf4); } -bool EfhEngine::giveItemTo(int16 charId, int16 objectId, int altCharId) { +bool EfhEngine::giveItemTo(int16 charId, int16 objectId, int16 altCharId) { for (int16 newObjectId = 0; newObjectId < 10; ++newObjectId) { if (_npcBuf[charId]._inventory[newObjectId]._ref != 0x7FFF) continue; @@ -3842,8 +3842,47 @@ void EfhEngine::getDeathTypeDescription(int16 attackerId, int16 victimId) { strcat((char *)_messageToBePrinted, buffer); } +bool EfhEngine::characterSearchesMonsterCorpse(int16 charId, int16 monsterId) { + int16 rndVal = getRandom(100); + if (kEncounters[_mapMonsters[monsterId]._MonsterRef]._dropOccurrencePct < rndVal) + return false; + + rndVal = getRandom(5) - 1; + int16 itemId = kEncounters[_mapMonsters[monsterId]._MonsterRef]._dropItemId[rndVal]; + if (itemId == -1) + return false; + + if (!giveItemTo(charId, itemId, 0xFF)) + return false; + + char tmpString[20]; + copyString(_items[itemId]._name, tmpString); + char buffer[80]; + sprintf(buffer, " and finds a %s!", tmpString); + strcat((char *)_messageToBePrinted, buffer); + return true; +} + void EfhEngine::getXPAndSearchCorpse(int16 charId, char *namePt1, char *namePt2, int16 monsterId) { - warning("STUB - getXPAndSearchCorpse"); + int16 xpLevel = getXPLevel(_npcBuf[charId]._xp); + _npcBuf[charId]._xp += kEncounters[_mapMonsters[monsterId]._MonsterRef]._xpGiven; + char buffer[80]; + sprintf(buffer, " %s%s gains %d experience", namePt1, namePt2, kEncounters[_mapMonsters[monsterId]._MonsterRef]._xpGiven); + if (getXPLevel(_npcBuf[charId]._xp) > xpLevel) { + generateSound(15); + int16 var2 = getRandom(20) + getRandom(_npcBuf[charId]._infoScore[4]); + _npcBuf[charId]._hitPoints += var2; + _npcBuf[charId]._maxHP += var2; + _npcBuf[charId]._infoScore[0] += getRandom(3) - 1; + _npcBuf[charId]._infoScore[1] += getRandom(3) - 1; + _npcBuf[charId]._infoScore[2] += getRandom(3) - 1; + _npcBuf[charId]._infoScore[3] += getRandom(3) - 1; + _npcBuf[charId]._infoScore[4] += getRandom(3) - 1; + } + strcat((char *)_messageToBePrinted, buffer); + if (!characterSearchesMonsterCorpse(charId, monsterId)) + strcat((char *)_messageToBePrinted, "!"); + } void EfhEngine::addReactionText(int16 id) { diff --git a/engines/efh/efh.h b/engines/efh/efh.h index be921fbad96c..68eebc5129f0 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -313,7 +313,7 @@ class EfhEngine : public Engine { bool isCharacterATeamMember(int16 id); bool isTPK(); void handleWinSequence(); - bool giveItemTo(int16 charId, int16 objectId, int altCharId); + bool giveItemTo(int16 charId, int16 objectId, int16 altCharId); int16 chooseCharacterToReplace(); int16 handleCharacterJoining(); int16 script_parse(uint8 *str, int posX, int posY, int maxX, int maxY, int argC); @@ -381,6 +381,7 @@ class EfhEngine : public Engine { bool hasAdequateDefense(int16 monsterId, uint8 attackType); bool hasAdequateDefense_2(int16 charId, uint8 attackType); void getDeathTypeDescription(int16 attackerId, int16 victimId); + bool characterSearchesMonsterCorpse(int16 charId, int16 monsterId); void getXPAndSearchCorpse(int16 charId, char* namePt1, char* namePt2, int16 monsterId); void addReactionText(int16 id); void handleFight_lastAction_A(int16 teamCharId); From 2584221af284d6cd6fb9921d9ff3116fbfd8bdbc Mon Sep 17 00:00:00 2001 From: Strangerke Date: Thu, 23 Dec 2021 01:44:05 +0100 Subject: [PATCH 107/412] EFH: Implement 4 more functions --- engines/efh/efh.cpp | 165 ++++++++++++++++++++++++++++++++++++++++---- engines/efh/efh.h | 4 +- 2 files changed, 156 insertions(+), 13 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 4f6e1ee72f33..d70ce45d701f 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -360,8 +360,7 @@ Common::Error EfhEngine::run() { return Common::kNoError; uint32 lastMs = _system->getMillis(); - warning("STUB - Main loop"); - for (;;) { + while(!_shouldQuit) { _system->delayMillis(20); uint32 newMs = _system->getMillis(); @@ -536,9 +535,7 @@ Common::Error EfhEngine::run() { if (handleDeathMenu()) _shouldQuit = true; } - - warning("Main loop - missing implementation"); - + displayFctFullScreen(); } return Common::kNoError; @@ -3245,8 +3242,58 @@ int8 EfhEngine::sub15581(int16 mapPosX, int16 mapPosY, int16 arg4) { return _tileFact[imageSetId * 2]; } -void EfhEngine::sub1BCA7(int16 monsterId) { - warning("STUB: sub1BCA7"); +bool EfhEngine::sub1BC74(int16 monsterId, int16 teamMonsterId) { + for (int16 counter = 0; counter < teamMonsterId; ++counter) { + if (_teamMonsterIdArray[counter] == monsterId) + return true; + } + return false; +} + +void EfhEngine::sub1BCA7(int16 monsterTeamId) { + int16 counter = 0; + if (monsterTeamId != -1 && countPictureRef(monsterTeamId, false)) { + counter = 1; + _teamMonsterIdArray[0] = monsterTeamId; + } + + for (int16 counter2 = 1; counter2 <= 3; ++counter2) { + if (counter >= 5) + break; + + for (int16 monsterId = 0; monsterId < 64; ++monsterId) { + if (_mapMonsters[monsterId]._guess_fullPlaceId == 0xFF) + continue; + + if (((_mapMonsters[monsterId]._possessivePronounSHL6 & 0x3F) != 0x3F || isCharacterATeamMember(_mapMonsters[monsterId]._field_1)) && (_mapMonsters[monsterId]._possessivePronounSHL6 & 0x3F) > 0x3D) + continue; + + if (!checkIfMonsterOnSameLargelMapPlace(monsterId)) + continue; + + bool var6 = false; + for (int16 counter3 = 0; counter3 < 9; ++counter3) { + if (_mapMonsters[monsterId]._pictureRef[counter3] > 0) { + var6 = true; + break; + } + } + + if (var6) { + if (computeMonsterGroupDistance(monsterId) <= counter2 && !sub1BC74(monsterId, counter)) { + _teamMonsterIdArray[counter] = monsterId; + if (++counter >= 5) + break; + } + } + } + } + + if (counter > 4) + return; + + for (int16 id = counter; id < 5; ++id) + _teamMonsterIdArray[id] = -1; } void EfhEngine::reset_stru32686() { @@ -3277,7 +3324,35 @@ bool EfhEngine::isTeamMemberStatusNormal(int16 teamMemberId) { } void EfhEngine::sub1CDFA() { - warning("STUB: sub1CDFA"); + for (int16 counter = 0; counter < 3; ++counter) { + if (_teamCharId[counter] != -1 && counter < _teamSize) { + _stru3244C[counter]._field0 = counter + 1000; + _stru3244C[counter]._field2 = _npcBuf[_teamCharId[counter]]._infoScore[3]; + } else { + _stru3244C[counter]._field0 = -1; + _stru3244C[counter]._field2 = -1; + } + } + + for (int16 counter = 0; counter < 5; ++counter) { + if (_teamMonsterIdArray[counter] == -1) { + _stru3244C[counter + 3]._field0 = -1; + _stru3244C[counter + 3]._field2 = -1; + } else { + _stru3244C[counter + 3]._field0 = counter; + _stru3244C[counter + 3]._field2 = _mapMonsters[_teamMonsterIdArray[counter]]._field_1 + getRandom(20); + } + } + + for (int16 counter = 0; counter < 8; ++counter) { + for (int16 counter2 = 0; counter2 < 8; ++counter2) { + if (_stru3244C[counter]._field2 >= _stru3244C[counter2]._field2) + continue; + + SWAP(_stru3244C[counter]._field0, _stru3244C[counter2]._field0); + SWAP(_stru3244C[counter]._field2, _stru3244C[counter2]._field2); + } + } } void EfhEngine::sub1CAFD() { @@ -3431,8 +3506,75 @@ int16 EfhEngine::getTeamMonsterAnimId() { return retVal; } -void EfhEngine::sub1C4CA(bool WhiteFl) { - warning("STUB: sub1C4CA"); +int16 EfhEngine::sub1BAF9(int16 monsterGroup) { + int16 var2 = 0; + for (int16 counter = 0; counter < 9; ++counter) { + if (sub1BA9B(monsterGroup, counter)) + ++var2; + } + + return var2; +} + +void EfhEngine::sub1C4CA(bool whiteFl) { + int16 textPosY = 20; + for (int16 counter = 0; counter < 5; ++counter) { + if (_teamMonsterIdArray[counter] == -1) + continue; + + int16 var6C = computeMonsterGroupDistance(_teamMonsterIdArray[counter]); + int16 var6E = sub1BAF9(counter); + if (whiteFl) + setTextColorWhite(); + else + setTextColorGrey(); + + setTextPos(129, textPosY); + char buffer[80]; + sprintf(buffer, "%c)", 'A' + counter); + displayStringAtTextPos(buffer); + setTextColorRed(); + int16 var1 = _mapMonsters[_teamMonsterIdArray[counter]]._possessivePronounSHL6 & 0x3F; + if (var1 <= 0x3D) { + sprintf(buffer, "%d %s", var6E, kEncounters[_mapMonsters[_teamMonsterIdArray[counter]]._MonsterRef]._name); + displayStringAtTextPos(buffer); + if (var6E > 1) + displayStringAtTextPos("s"); + } else if (var1 == 0x3E) { + displayStringAtTextPos("(NOT DEFINED)"); + } else if (var1 == 0x3F) { + char stringToDisplay[20]; + copyString(_npcBuf[_mapMonsters[_teamMonsterIdArray[counter]]._field_1]._name, stringToDisplay); + displayStringAtTextPos(stringToDisplay); + } + + setTextPos(228, textPosY); + if (unkFct_checkMonsterField8(counter, true)) { + _textColor = 0xE; + displayStringAtTextPos("Hostile"); + } else { + _textColor = 2; + displayStringAtTextPos("Friendly"); + } + + setTextColorRed(); + switch (var6C) { + case 1: + displayCenteredString("S", 290, 302, textPosY); + break; + case 2: + displayCenteredString("M", 290, 302, textPosY); + break; + case 3: + displayCenteredString("L", 290, 302, textPosY); + break; + default: + displayCenteredString("?", 290, 302, textPosY); + break; + } + + textPosY += 9; + } } void EfhEngine::displayCombatMenu(int16 charId) { @@ -4063,7 +4205,6 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { int16 damagePointsAbsorbed = 0; int16 var64 = _items[unk_monsterField5_itemId]._attacks *_npcBuf[_teamCharId[teamCharId]]._speed; - warning("STUB: handleFight - Action A - Loop var84"); // Action A - Loop var84 - Start for (int16 var84 = 0; var84 < var64; ++var84) { if (getRandom(100) < charScore) { @@ -6097,7 +6238,7 @@ bool EfhEngine::sub16E14() { var68 = true; break; default: - warning("STUB: sub16E14 - Missing mapping ?"); +// warning("STUB: sub16E14 - Missing mapping ?"); break; } } while (!var68); diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 68eebc5129f0..6ba22bfa1de4 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -357,7 +357,8 @@ class EfhEngine : public Engine { void sub22AA8(int16 arg0); bool sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemId, int16 arg8, int16 imageSetId); int8 sub15581(int16 mapPosX, int16 mapPosY, int16 arg4); - void sub1BCA7(int16 monsterId); + bool sub1BC74(int16 monsterId, int16 teamMonsterId); + void sub1BCA7(int16 monsterTeamId); void reset_stru32686(); void sub1BE89(int16 monsterId); void resetTeamMonsterIdArray(); @@ -369,6 +370,7 @@ class EfhEngine : public Engine { bool sub1CB27(); void sub1BE9A(int16 monsterId); int16 getTeamMonsterAnimId(); + int16 sub1BAF9(int16 monsterGroup); void sub1C4CA(bool WhiteFl); void displayCombatMenu(int16 charId); void drawCombatScreen(int16 charId, bool whiteFl, bool forceDrawFl); From 7ac43704a786c504bfca6a0214ed8a378de923e5 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Thu, 23 Dec 2021 20:26:12 +0100 Subject: [PATCH 108/412] EFH: Implement one more stub --- engines/efh/efh.cpp | 84 ++++++++++++++++++++++++++++++++++++++++++--- engines/efh/efh.h | 3 +- 2 files changed, 82 insertions(+), 5 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index d70ce45d701f..b309276d8a55 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -3355,7 +3355,7 @@ void EfhEngine::sub1CDFA() { } } -void EfhEngine::sub1CAFD() { +void EfhEngine::redrawScreenForced() { for (int16 counter = 0; counter < 2; ++counter) { redrawScreen(); if (counter == 0) @@ -3363,9 +3363,85 @@ void EfhEngine::sub1CAFD() { } } +int16 EfhEngine::selectMonsterGroup() { + int16 retVal = -1; + + while (retVal == -1) { + Common::KeyCode input = handleAndMapInput(true); + switch (input) { + case Common::KEYCODE_ESCAPE: + retVal = 27; + break; + case Common::KEYCODE_a: + case Common::KEYCODE_b: + case Common::KEYCODE_c: + case Common::KEYCODE_d: + case Common::KEYCODE_e: + retVal = input - Common::KEYCODE_a; + if (_teamMonsterIdArray[retVal] == -1) + retVal = -1; + break; + default: + break; + } + } + + return retVal; +} + int16 EfhEngine::sub1C956(int16 charId, int16 unkFied18Val, int16 arg4) { - warning("STUB: sub1C956"); - return 0; + int16 varE = -1; + + int16 var6 = sub1C80A(charId, unkFied18Val, true); + int16 range = 0; + if (var6 != 0x7FFF) + range = _items[var6]._range; + + switch (range) { + case 3: + case 2: + ++range; + case 1: + ++range; + case 0: + ++range; + break; + case 4: + return 100; + default: + return varE; + } + + do { + for (int16 counter = 0; counter < 2; ++counter) { + drawCombatScreen(charId, true, false); + if (_teamMonsterIdArray[1] != -1) + sub1C219((uint8 *)"Select Monster Group:", 3, 0, false); + + if (counter == 0) + displayFctFullScreen(); + } + + if (_teamMonsterIdArray[1] == -1) + varE = 0; + else + varE = selectMonsterGroup(); + + if (arg4 == 0) { + if (varE == 27) + varE = 0; + } else if (varE != 27) { + int16 monsterGroupDistance = computeMonsterGroupDistance(_teamMonsterIdArray[varE]); + if (monsterGroupDistance > range) { + varE = 27; + } + } + } while (varE != -1); + + if (varE == 27) + varE = -1; + + return varE; } void EfhEngine::sub1CAB6(int16 charId) { @@ -3468,7 +3544,7 @@ bool EfhEngine::sub1CB27() { } break; case Common::KEYCODE_t: - sub1CAFD(); + redrawScreenForced(); getInputBlocking(); drawCombatScreen(_teamCharId[counter1], false, true); break; diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 6ba22bfa1de4..0521d12dae00 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -364,7 +364,8 @@ class EfhEngine : public Engine { void resetTeamMonsterIdArray(); bool isTeamMemberStatusNormal(int16 id); void sub1CDFA(); - void sub1CAFD(); + void redrawScreenForced(); + int16 selectMonsterGroup(); int16 sub1C956(int16 charId, int16 unkFied18Val, int16 arg4); void sub1CAB6(int16 charId); bool sub1CB27(); From fd7b6755fbd7375e88953c42056cc84750724d28 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Fri, 24 Dec 2021 01:42:29 +0100 Subject: [PATCH 109/412] EFH: Implement 2 more stubs, rename a function --- engines/efh/efh.cpp | 129 +++++++++++++++++++++++++++++++++++++++----- engines/efh/efh.h | 2 +- 2 files changed, 116 insertions(+), 15 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index b309276d8a55..ddc7944d82c6 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -3585,7 +3585,7 @@ int16 EfhEngine::getTeamMonsterAnimId() { int16 EfhEngine::sub1BAF9(int16 monsterGroup) { int16 var2 = 0; for (int16 counter = 0; counter < 9; ++counter) { - if (sub1BA9B(monsterGroup, counter)) + if (isMonsterActive(monsterGroup, counter)) ++var2; } @@ -3741,13 +3741,114 @@ void EfhEngine::handleFight_checkEndEffect(int16 charId) { } int16 EfhEngine::sub1DEC8(int16 groupNumber) { - warning("STUB: sub1DEC8"); - return -1; + int16 var4 = -1; + int16 monsterId = _teamMonsterIdArray[groupNumber]; + + if (monsterId == -1) + return -1; + + for (int16 counter = 0; counter < 9; ++counter) { + if (isMonsterActive(groupNumber, counter)) { + var4 = counter; + break; + } + } + + for (int16 counter = var4 + 1; counter < 9; ++counter) { + if (!isMonsterActive(groupNumber, counter)) + continue; + + if (_mapMonsters[monsterId]._pictureRef[var4] > _mapMonsters[monsterId]._pictureRef[counter]) + var4 = counter; + } + + if (_mapMonsters[monsterId]._pictureRef[var4] <= 0) + return -1; + + return var4; } int16 EfhEngine::getCharacterScore(int16 charId, int16 itemId) { - warning("STUB - getCharacterScore"); - return 90; + int16 totalScore = 0; + switch (_items[itemId]._range) { + case 0: + totalScore = _npcBuf[charId]._passiveScore[5] + _npcBuf[charId]._passiveScore[3] + _npcBuf[charId]._passiveScore[4]; + totalScore += _npcBuf[charId]._infoScore[0] / 5; + totalScore += _npcBuf[charId]._infoScore[2] * 2, + totalScore += _npcBuf[charId]._infoScore[6] / 5; + totalScore += 2 * _npcBuf[charId]._infoScore[5] / 5; + break; + case 1: + totalScore = _npcBuf[charId]._passiveScore[3] + _npcBuf[charId]._passiveScore[4]; + totalScore += _npcBuf[charId]._infoScore[2] * 2; + totalScore += _npcBuf[charId]._infoScore[1] / 5; + totalScore += _npcBuf[charId]._infoScore[3] / 5; + break; + case 2: + case 3: + case 4: + totalScore = _npcBuf[charId]._passiveScore[1]; + totalScore += _npcBuf[charId]._infoScore[2] * 2; + totalScore += _npcBuf[charId]._infoScore[1] / 5; + totalScore += _npcBuf[charId]._infoScore[3] / 5; + totalScore += _npcBuf[charId]._infoScore[8] / 5; + default: + break; + } + + int16 extraScore = 0; + switch (_items[itemId]._attackType) { + case 0: + case 1: + case 2: + if (itemId == 0x3F) + extraScore = _npcBuf[charId]._passiveScore[2]; + else if (itemId == 0x41 || itemId == 0x42 || itemId == 0x6A || itemId == 0x6C || itemId == 0x6D) + extraScore = _npcBuf[charId]._passiveScore[0]; + break; + case 3: + case 4: + case 6: + extraScore = _npcBuf[charId]._infoScore[7]; + break; + case 5: + case 7: + extraScore = _npcBuf[charId]._infoScore[9]; + break; + case 8: + case 9: + extraScore = _npcBuf[charId]._activeScore[12]; + break; + case 10: + extraScore = _npcBuf[charId]._passiveScore[10]; + break; + case 11: + extraScore = _npcBuf[charId]._passiveScore[6]; + break; + case 12: + extraScore = _npcBuf[charId]._passiveScore[7]; + break; + case 13: + extraScore = _npcBuf[charId]._passiveScore[8]; + break; + case 14: + extraScore = _npcBuf[charId]._activeScore[13]; + break; + case 15: + extraScore = _npcBuf[charId]._passiveScore[9]; + break; + default: + break; + } + + extraScore += _items[itemId].field_13; + + int16 grandTotalScore = totalScore + extraScore; + if (grandTotalScore > 60) + grandTotalScore = 60; + + int16 retVal = CLIP(grandTotalScore + 30, 5, 90); + return retVal; } bool EfhEngine::checkSpecialItemsOnCurrentPlace(int16 itemId) { @@ -4257,7 +4358,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { continue; for (int16 var7E = teamMemberId; var7E < var54; ++var7E) { - if (sub1BA9B(groupId, var7E) && var6E) { + if (isMonsterActive(groupId, var7E) && var6E) { int16 var5C; if (unkFct_checkMonsterField8(groupId, true)) { sub1E028(groupId, 9, true); @@ -4634,7 +4735,7 @@ bool EfhEngine::handleFight(int16 monsterId) { } else if (unkFct_checkMonsterField8(monsterGroupIdOrMonsterId, true)) { // handleFight - Loop on var86 - Start for (int16 var86 = 0; var86 < 9; ++var86) { - if (sub1BA9B(monsterGroupIdOrMonsterId, var86)) { + if (isMonsterActive(monsterGroupIdOrMonsterId, var86)) { int16 unk_monsterField5_itemId = _mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._itemId_Weapon; if (unk_monsterField5_itemId == 0xFF) unk_monsterField5_itemId = 0x3F; @@ -5249,7 +5350,7 @@ void EfhEngine::sub1E028(int16 id, uint8 mask, int16 groupFl) { _mapMonsters[monsterId]._field_8 |= mask; } -bool EfhEngine::sub1BA9B(int16 groupId, int16 id) { +bool EfhEngine::isMonsterActive(int16 groupId, int16 id) { if (_mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[id] > 0 && _stru32686[groupId]._field0[id] == 0) return true; return false; @@ -5298,7 +5399,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me strcat((char *)_messageToBePrinted, " The item emits a low droning hum..."); if (getRandom(100) < 50) { for (int16 counter = 0; counter < 9; ++counter) { - if (sub1BA9B(windowId, counter)) { + if (isMonsterActive(windowId, counter)) { ++victims; _stru32686[windowId]._field0[counter] = 1; _stru32686[windowId]._field2[counter] = getRandom(8); @@ -5310,7 +5411,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me if (NumberOfTargets == 0) break; - if (sub1BA9B(windowId, counter)) { + if (isMonsterActive(windowId, counter)) { ++victims; --NumberOfTargets; _stru32686[windowId]._field0[counter] = 1; @@ -5337,7 +5438,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me int16 victim = 0; if (getRandom(100) < 50) { for (int16 varA8 = 0; varA8 < 9; ++varA8) { - if (sub1BA9B(windowId, varA8)) { + if (isMonsterActive(windowId, varA8)) { ++victim; _stru32686[windowId]._field0[varA8] = 2; _stru32686[windowId]._field2[varA8] = getRandom(8); @@ -5349,7 +5450,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me if (varAC == 0) break; - if (sub1BA9B(windowId, varA8)) { + if (isMonsterActive(windowId, varA8)) { ++victim; --varAC; _stru32686[windowId]._field0[varA8] = 2; @@ -5393,7 +5494,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me } } else { for (int16 counter = 0; counter < 9; ++counter) { - if (sub1BA9B(windowId, counter)) { + if (isMonsterActive(windowId, counter)) { if (getRandom(100) < 50) { _mapMonsters[_teamMonsterIdArray[windowId]]._pictureRef[counter] = 0; } @@ -5416,7 +5517,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me } else { strcat((char *)_messageToBePrinted, " A dark fiery whirlwind surrounds the poor victim...the power fades and one victim dies!"); for (int16 counter = 0; counter < 9; ++counter) { - if (sub1BA9B(windowId, counter)) { + if (isMonsterActive(windowId, counter)) { _mapMonsters[_teamMonsterIdArray[windowId]]._pictureRef[counter] = 0; } } diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 0521d12dae00..494053a379ba 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -409,7 +409,7 @@ class EfhEngine : public Engine { void equipCursedItem(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine); void sub191FF(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine); void sub1E028(int16 id, uint8 mask, int16 groupFl); - bool sub1BA9B(int16 groupId, int16 id); + bool isMonsterActive(int16 groupId, int16 id); int16 sub15538(int16 mapPosX, int16 mapPosY); void setCharacterObjectToBroken(int16 charId, int16 objectId); int16 selectOtherCharFromTeam(); From e6e84a6c7e5b46742f14f2ea43601e58c05c6782 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sun, 26 Dec 2021 01:44:20 +0100 Subject: [PATCH 110/412] EFH: Implement sub1BE9A --- engines/efh/efh.cpp | 97 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 95 insertions(+), 2 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index ddc7944d82c6..a4d3b16e7c45 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -3558,9 +3558,102 @@ bool EfhEngine::sub1CB27() { return var4; } +// The parameter isn't used in the original void EfhEngine::sub1BE9A(int16 monsterId) { - warning("STUB sub1BE9A"); -} + int16 var4 = 1; + + // sub1BE9A - 1rst loop counter1_monsterId - Start + for (int16 counter1 = 0; counter1 < 5; ++counter1) { + if (sub1BAF9(counter1)) + continue; + + for (int16 counter2 = 0; counter2 < 9; ++counter2) { + _mapMonsters[_teamMonsterIdArray[counter1]]._pictureRef[counter2] = 0; + _stru32686[counter1]._field0[counter2] = 0; + _stru32686[counter1]._field2[counter2] = 0; + } + + _teamMonsterIdArray[counter1] = -1; + for (int16 counter2 = counter1 + 1; counter2 < 5; ++counter2) { + for (int16 var8 = 0; var8 < 9; ++var8) { + _stru32686[counter1]._field0[var8] = _stru32686[counter2]._field0[var8]; + _stru32686[counter1]._field2[var8] = _stru32686[counter2]._field2[var8]; + } + _teamMonsterIdArray[counter1] = _teamMonsterIdArray[counter2]; + } + + } + // sub1BE9A - 1rst loop counter1_monsterId - End + + var4 = -1; + for (int16 counter1 = 0; counter1 < 5; ++counter1) { + if (_teamMonsterIdArray[counter1] == -1) { + var4 = counter1; + break; + } + } + + if (var4 != -1) { + // sub1BE9A - loop var2 - Start + for (int16 var2 = 1; var2 < 3; ++var2) { + if (var4 >= 5) + break; + + for (int16 counter1 = 0; counter1 < 64; ++counter1) { + if (_mapMonsters[counter1]._guess_fullPlaceId == 0xFF) + continue; + + if (((_mapMonsters[counter1]._possessivePronounSHL6 & 0x3F) == 0x3F && !isCharacterATeamMember(_mapMonsters[counter1]._field_1)) || (_mapMonsters[counter1]._possessivePronounSHL6 & 0x3F) <= 0x3D) { + if (checkIfMonsterOnSameLargelMapPlace(counter1)) { + bool var6 = false; + for (int16 counter2 = 0; counter2 < 9; ++counter2) { + if (_mapMonsters[counter1]._pictureRef[counter2] > 0) { + var6 = true; + break; + } + } + + if (!var6) + continue; + + if (var2 > computeMonsterGroupDistance(counter1)) + continue; + + if (sub1BC74(counter1, var4)) + continue; + + _teamMonsterIdArray[var4] = counter1; + + // The original at this point was doing a loop on counter1, which is not a good idea as + // it was resetting the counter1 to 9 whatever its value before the loop. + // Furthermore, it was accessing _stru32686[counter1]._field0[counter1] which doesn't make + // sense... + // I therefore decided to use another counter as it looks like an original misbehavior/bug. + for (int16 counter2 = 0; counter2 < 9; ++counter2) { + _stru32686[counter1]._field0[counter2] = 0; + } + + if (++var4 >= 5) + break; + } + } + } + } + // sub1BE9A - loop var2 - End + } + + if (var4 == -1 || var4 > 4) + return; + + // sub1BE9A - last loop counter1_monsterId - Start + for (int16 counter1 = var4; counter1 < 5; ++counter1) { + _teamMonsterIdArray[counter1] = -1; + for (int16 counter2 = 0; counter2 < 9; ++counter2) { + _stru32686[counter1]._field0[counter2] = 0x8000; + } + } + // sub1BE9A - last loop counter1_monsterId - End + } int16 EfhEngine::getTeamMonsterAnimId() { int16 retVal = 0xFF; From f3bf1bfbc55d527f644e348afac9b94f345c0e52 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Mon, 27 Dec 2021 21:57:35 +0100 Subject: [PATCH 111/412] EFH: Add some debug traces, some renaming --- engines/efh/detection.cpp | 7 +++++ engines/efh/efh.cpp | 22 +++++++------- engines/efh/efh.h | 10 +++++-- engines/efh/graphics.cpp | 62 ++++++++++++++++++++++++++++++++------- engines/efh/utils.cpp | 13 ++++++++ 5 files changed, 91 insertions(+), 23 deletions(-) diff --git a/engines/efh/detection.cpp b/engines/efh/detection.cpp index 7f570bd78e0a..439f8c54b4dc 100644 --- a/engines/efh/detection.cpp +++ b/engines/efh/detection.cpp @@ -25,6 +25,7 @@ #include "common/textconsole.h" #include "efh/detection.h" +#include "efh/efh.h" namespace Efh { @@ -57,6 +58,12 @@ static const EfhGameDescription gameDescriptions[] = { {AD_TABLE_END_MARKER, kGameTypeNone} }; +static const DebugChannelDef debugFlagList[] = { + {Efh::kDebugEngine, "engine", "Engine debug level"}, + {Efh::kDebugUtils, "utils", "Utils debug level"}, + {Efh::kDebugGraphics, "graphics", "Graphics debug level"}, + DEBUG_CHANNEL_END}; + class EfhMetaEngineDetection : public AdvancedMetaEngineDetection { public: EfhMetaEngineDetection() : AdvancedMetaEngineDetection(gameDescriptions, sizeof(EfhGameDescription), efhGames) { diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index a4d3b16e7c45..c88075ab8eff 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -312,6 +312,7 @@ EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst) memset(_messageToBePrinted, 0, 400); for (int i = 0; i < 8; ++i) _stru3244C[i].init(); + } EfhEngine::~EfhEngine() { @@ -351,6 +352,7 @@ Common::Error EfhEngine::run() { syncSoundSettings(); _soundHandler->init(); */ + initEngine(); sub15150(true); redrawScreen(); @@ -439,7 +441,7 @@ Common::Error EfhEngine::run() { break; case Common::KEYCODE_F5: { // Original is using CTRL-S for (int16 counter = 0; counter < 2; ++counter) { - unkFct_displayMenuBox_2(0); + clearBottomTextZone(0); displayCenteredString("Are You Sure You Want To Save?", 24, 296, 160); if (counter == 0) displayFctFullScreen(); @@ -449,12 +451,12 @@ Common::Error EfhEngine::run() { displayMenuAnswerString("-> Yes <-", 24, 296, 169); getInput(2); saveEfhGame(); - unkFct_displayBox(0); + clearBottomTextZone_2(0); displayLowStatusScreen(true); } else { displayMenuAnswerString("-> No!!! <-", 24, 296, 169); getInput(2); - unkFct_displayBox(0); + clearBottomTextZone_2(0); displayLowStatusScreen(true); } @@ -462,7 +464,7 @@ Common::Error EfhEngine::run() { break; case Common::KEYCODE_F7: { // Original is using CTRL-S for (int16 counter = 0; counter < 2; ++counter) { - unkFct_displayMenuBox_2(0); + clearBottomTextZone(0); displayCenteredString("Are You Sure You Want To Load?", 24, 296, 160); if (counter == 0) displayFctFullScreen(); @@ -472,12 +474,12 @@ Common::Error EfhEngine::run() { displayMenuAnswerString("-> Yes <-", 24, 296, 169); getInput(2); loadEfhGame(); - unkFct_displayBox(0); + clearBottomTextZone_2(0); displayLowStatusScreen(true); } else { displayMenuAnswerString("-> No!!! <-", 24, 296, 169); getInput(2); - unkFct_displayBox(0); + clearBottomTextZone_2(0); displayLowStatusScreen(true); } @@ -1261,7 +1263,7 @@ void EfhEngine::displayLowStatusScreen(bool flag) { for (int counter = 0; counter < 2; ++counter) { if (counter == 0 || flag) { - unkFct_displayMenuBox_2(0); + clearBottomTextZone(0); setTextColorWhite(); displayCenteredString(strName, 16, 88, 152); displayCenteredString(strDef, 104, 128, 152); @@ -2321,7 +2323,7 @@ bool EfhEngine::handleDeathMenu() { redrawScreen(); for (int16 counter = 0; counter < 2; ++counter) { - unkFct_displayMenuBox_2(0); + clearBottomTextZone(0); displayCenteredString("Darkness Prevails...Death Has Taken You!", 24, 296, 153); setTextPos(100, 162); setTextColorWhite(); @@ -2974,7 +2976,7 @@ bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { copyString(_npcBuf[_teamCharId[counter]]._name, _characterNamePt2); sprintf(buffer, "%s asks that %s leave your party.", _enemyNamePt2, _characterNamePt2); for (int16 i = 0; i < 2; ++i) { - unkFct_displayMenuBox_2(0); + clearBottomTextZone(0); _textColor = 0xE; displayCenteredString(buffer, 24, 296, 161); setTextPos(24, 169); @@ -6456,7 +6458,7 @@ bool EfhEngine::sub16E14() { sprintf(buffer, "with %s", dest); } - unkFct_displayMenuBox_2(0); + clearBottomTextZone(0); _textColor = 0xE; displayCenteredString("Interaction", 24, 296, 152); displayCenteredString(buffer, 24, 296, 161); diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 494053a379ba..eeaf9b259f7f 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -55,6 +55,12 @@ namespace Efh { static const int kSavegameVersion = 1; +enum AccessDebugChannels { + kDebugEngine = 1 << 0, + kDebugUtils = 1 << 1, + kDebugGraphics = 1 << 2 +}; + struct EfhGameDescription; class EfhGraphicsStruct { @@ -443,12 +449,12 @@ class EfhEngine : public Engine { void setTextColorRed(); void setTextColorGrey(); void displayStringAtTextPos(const char *message); - void unkFct_displayMenuBox_2(int16 color); + void clearBottomTextZone(int16 color); + void clearBottomTextZone_2(int16 color); void setNextCharacterPos(); void displayCharAtTextPos(char character); void displayWindow(uint8 *buffer, int16 posX, int16 posY, uint8 *dest); void displayColoredMenuBox(int16 minX, int16 minY, int16 maxX, int16 maxY, int16 color); - void unkFct_displayBox(int16 color); // Utils int32 readFileToBuffer(Common::String &filename, uint8 *destBuffer); diff --git a/engines/efh/graphics.cpp b/engines/efh/graphics.cpp index 2ef7f03015e8..19fdfe4b66d0 100644 --- a/engines/efh/graphics.cpp +++ b/engines/efh/graphics.cpp @@ -28,7 +28,7 @@ namespace Efh { void EfhEngine::initPalette() { // Strangerke - values from a tool I wrote in 2008. I can't remember if it's guess work or not. - const uint8 pal[3 * 16] = { + static const uint8 pal[3 * 16] = { 0, 0, 0, 0, 0, 170, 0, 170, 0, @@ -47,15 +47,18 @@ void EfhEngine::initPalette() { 255, 255, 255 }; + debugC(1, kDebugGraphics, "initPalette"); _system->getPaletteManager()->setPalette(pal, 0, 16); _system->updateScreen(); } void EfhEngine::drawLeftCenterBox() { + debugC(1, kDebugGraphics, "drawLeftCenterBox"); drawColoredRect(16, 8, 111, 135, 0); } void EfhEngine::displayAnimFrame() { + debugC(1, kDebugGraphics, "displayAnimFrame"); // The original had a parameter. As it was always equal to zero, it was removed in ScummVM if (_animImageSetId == 0xFF) @@ -76,6 +79,7 @@ void EfhEngine::displayAnimFrame() { } void EfhEngine::displayAnimFrames(int16 animId, bool displayMenuBoxFl) { + debugC(1, kDebugGraphics, "displayAnimFrames %d %s", animId, displayMenuBoxFl ? "True" : "False"); if (animId == 0xFF) return; @@ -98,6 +102,8 @@ void EfhEngine::displayAnimFrames(int16 animId, bool displayMenuBoxFl) { } void EfhEngine::displayFctFullScreen() { + debugC(1, kDebugGraphics, "displayFctFullScreen"); + // CHECKME: 319 is in the original but looks suspicious. // copyDirtyRect(0, 0, 319, 200); @@ -116,9 +122,9 @@ void EfhEngine::copyGraphicBufferFromTo(EfhGraphicsStruct *efh_graphics_struct, } void EfhEngine::displayBufferBmAtPos(BufferBM *bufferBM, int16 posX, int16 posY) { - // TODO: Quick code to display stuff, may require to really reverse the actual function + debugC(1, kDebugGraphics, "displayBufferBmAtPos %d %d", posX, posY); + // CHECKME: Quick code to display stuff, may require to really reverse the actual function uint8 *destPtr = (uint8 *)_mainSurface->getBasePtr(posX, posY); - // warning("%d %d - startX %d startY %d width %d height %d lineDataSize %d fieldD %d", posX, posY, bufferBM->_startX, bufferBM->_startY, bufferBM->_width, bufferBM->_height, bufferBM->_lineDataSize, bufferBM->_fieldD); int counter = 0; for (int line = 0; line < bufferBM->_height; ++line) { for (int col = 0; col < bufferBM->_lineDataSize; ++col) { // _lineDataSize = _width / 2 @@ -133,14 +139,14 @@ void EfhEngine::displayBufferBmAtPos(BufferBM *bufferBM, int16 posX, int16 posY) } void EfhEngine::drawRect(int minX, int minY, int maxX, int maxY) { + debugC(1, kDebugGraphics, "drawRect %d %d %d %d", minX, minY, maxX, maxY); + if (minY > maxY) SWAP(minY, maxY); if (minX > maxX) SWAP(minX, maxX); - // warning("drawRect - _graphicsStruct x %d -> %d, y %d -> %d", _graphicsStruct->_area.left, _graphicsStruct->_area.right, _graphicsStruct->_area.top, _graphicsStruct->_area.bottom); - minX = CLIP(minX, 0, 319); maxX = CLIP(maxX, 0, 319); minY = CLIP(minY, 0, 199); @@ -164,6 +170,8 @@ void EfhEngine::drawRect(int minX, int minY, int maxX, int maxY) { } void EfhEngine::drawColoredRect(int minX, int minY, int maxX, int maxY, int color) { + debugC(1, kDebugGraphics, "drawColoredRect %d %d %d %d %d", minX, minY, maxX, maxY, color); + uint8 oldValue = _defaultBoxColor; _defaultBoxColor = color; drawRect(minX, minY, maxX, maxY); @@ -171,10 +179,12 @@ void EfhEngine::drawColoredRect(int minX, int minY, int maxX, int maxY, int colo } void EfhEngine::clearScreen(int color) { + debugC(1, kDebugGraphics, "clearScreen %d", color); drawColoredRect(0, 0, 320, 200, color); } void EfhEngine::displayRawDataAtPos(uint8 *imagePtr, int16 posX, int16 posY) { + debugC(1, kDebugGraphics, "displayRawDataAtPos %d %d", posX, posY); uint16 height = READ_LE_INT16(imagePtr); uint16 width = READ_LE_INT16(imagePtr + 2); uint8 *imageData = imagePtr + 4; @@ -189,6 +199,7 @@ void EfhEngine::displayRawDataAtPos(uint8 *imagePtr, int16 posX, int16 posY) { } void EfhEngine::drawString(const char *str, int16 startX, int16 startY, uint16 unkFl) { + debugC(1, kDebugGraphics, "drawString %s %d %d %d", str, startX, startY, unkFl); uint8 *curPtr = (uint8 *)str; uint16 lineHeight = _fontDescr._charHeight + _fontDescr._extraVerticalSpace; _unk_sub26437_flag = unkFl & 0x3FFF; @@ -225,22 +236,26 @@ void EfhEngine::drawString(const char *str, int16 startX, int16 startY, uint16 u } void EfhEngine::displayCenteredString(const char *str, int16 minX, int16 maxX, int16 posY) { + debugC(1, kDebugGraphics, "displayCenteredString %s %d-%d %d", str, minX, maxX, posY); uint16 length = getStringWidth(str); int16 startCenteredDisplayX = minX + (maxX - minX - length) / 2; drawString(str, startCenteredDisplayX, posY, _textColor); } void EfhEngine::displayMenuAnswerString(const char *str, int16 minX, int16 maxX, int posY) { + debugC(1, kDebugGraphics, "displayMenuAnswerString %s %d-%d %d", str, minX, maxX, posY); displayCenteredString(str, minX, maxX, posY); displayFctFullScreen(); displayCenteredString(str, minX, maxX, posY); } void EfhEngine::drawMapWindow() { + debugC(1, kDebugGraphics, "drawMapWindow"); drawColoredRect(128, 8, 303, 135, 0); } void EfhEngine::displayGameScreen() { + debugC(1, kDebugGraphics, "displayGameScreen"); clearScreen(0); drawUpperLeftBorders(); drawUpperRightBorders(); @@ -250,17 +265,20 @@ void EfhEngine::displayGameScreen() { } void EfhEngine::drawUpperLeftBorders() { + debugC(1, kDebugGraphics, "drawUpperLeftBorders"); displayRawDataAtPos(_circleImageSubFileArray[0], 0, 0); displayRawDataAtPos(_circleImageSubFileArray[1], 112, 0); displayRawDataAtPos(_circleImageSubFileArray[3], 16, 0); } void EfhEngine::drawUpperRightBorders() { + debugC(1, kDebugGraphics, "drawUpperRightBorders"); displayRawDataAtPos(_circleImageSubFileArray[2], 304, 0); displayRawDataAtPos(_circleImageSubFileArray[4], 128, 0); } void EfhEngine::drawBottomBorders() { + debugC(1, kDebugGraphics, "drawBottomBorders"); displayRawDataAtPos(_circleImageSubFileArray[7], 16, 136); displayRawDataAtPos(_circleImageSubFileArray[8], 16, 192); displayRawDataAtPos(_circleImageSubFileArray[5], 0, 136); @@ -268,7 +286,9 @@ void EfhEngine::drawBottomBorders() { } void EfhEngine::drawChar(uint8 curChar, int16 posX, int posY) { - // Quick hacked display, may require rework + debugC(1, kDebugGraphics, "drawChar %c %d %d", curChar, posX, posY); + + // CHECKME: Quick hacked display, may require rework uint8 *destPtr = (uint8 *)_mainSurface->getBasePtr(posX, posY); int16 charId = curChar - 0x20; @@ -285,6 +305,8 @@ void EfhEngine::drawChar(uint8 curChar, int16 posX, int posY) { } void EfhEngine::setTextColorWhite() { + debugC(1, kDebugGraphics, "setTextColorWhite"); + if (_videoMode == 8) // CGA _textColor = 0x3; else @@ -292,6 +314,8 @@ void EfhEngine::setTextColorWhite() { } void EfhEngine::setTextColorRed() { + debugC(1, kDebugGraphics, "setTextColorRed"); + if (_videoMode == 8) // CGA _textColor = 0x2; else @@ -299,6 +323,8 @@ void EfhEngine::setTextColorRed() { } void EfhEngine::setTextColorGrey() { + debugC(1, kDebugGraphics, "setTextColorGrey"); + if (_videoMode == 8) // CGA _textColor = 0x1; else @@ -306,16 +332,28 @@ void EfhEngine::setTextColorGrey() { } void EfhEngine::displayStringAtTextPos(const char *message) { + debugC(1, kDebugGraphics, "displayStringAtTextPos %s", message); + drawString(message, _textPosX, _textPosY, _textColor); _textPosX += getStringWidth(message) + 1; setNextCharacterPos(); } -void EfhEngine::unkFct_displayMenuBox_2(int16 color) { +void EfhEngine::clearBottomTextZone(int16 color) { + debugC(1, kDebugGraphics, "clearBottomTextZone %d", color); + drawColoredRect(16, 152, 302, 189, color); } +void EfhEngine::clearBottomTextZone_2(int16 color) { + debugC(1, kDebugGraphics, "clearBottomTextZone_2 %d", color); + + displayColoredMenuBox(16, 152, 302, 189, color); +} + void EfhEngine::setNextCharacterPos() { + debugC(1, kDebugGraphics, "setNextCharacterPos"); + if (_textPosX <= 311) return; @@ -327,6 +365,8 @@ void EfhEngine::setNextCharacterPos() { } void EfhEngine::displayCharAtTextPos(char character) { + debugC(1, kDebugGraphics, "displayCharAtTextPos %c", character); + char buffer[2]; buffer[0] = character; buffer[1] = 0; @@ -337,6 +377,8 @@ void EfhEngine::displayCharAtTextPos(char character) { } void EfhEngine::displayWindow(uint8 *buffer, int16 posX, int16 posY, uint8 *dest) { + debugC(1, kDebugGraphics, "displayWindow %d %d", posX, posY); + if (buffer == nullptr) { warning("Target Buffer Not Defined...DCImage!"); // That's the original message... And yes, it's wrong: it's checking the source buffer :) return; @@ -350,13 +392,11 @@ void EfhEngine::displayWindow(uint8 *buffer, int16 posX, int16 posY, uint8 *dest } void EfhEngine::displayColoredMenuBox(int16 minX, int16 minY, int16 maxX, int16 maxY, int16 color) { + debugC(1, kDebugGraphics, "displayColoredMenuBox %d %d -> %d %d %d", minX, minY, maxX, maxY, color); + drawColoredRect(minX, minY, maxX, maxY, color); displayFctFullScreen(); drawColoredRect(minX, minY, maxX, maxY, color); } -void EfhEngine::unkFct_displayBox(int16 color) { - displayColoredMenuBox(16, 152, 302, 189, color); -} - } // End of namespace Efh diff --git a/engines/efh/utils.cpp b/engines/efh/utils.cpp index e8b99457842d..54941c938a5e 100644 --- a/engines/efh/utils.cpp +++ b/engines/efh/utils.cpp @@ -27,6 +27,7 @@ namespace Efh { int32 EfhEngine::readFileToBuffer(Common::String &filename, uint8 *destBuffer) { + debugC(1, kDebugUtils, "readFileToBuffer %s", filename.c_str()); Common::File f; if (!f.open(filename)) error("Unable to find file %s", filename.c_str()); @@ -46,6 +47,7 @@ void EfhEngine::setDefaultNoteDuration() { } void EfhEngine::decryptImpFile(bool techMapFl) { + debugC(1, kDebugUtils, "decryptImpFile %s", techMapFl ? "True" : "False"); uint16 counter = 0; uint16 target; uint8 *curPtr; @@ -84,11 +86,13 @@ void EfhEngine::decryptImpFile(bool techMapFl) { } void EfhEngine::loadImageSet(int imageSetId, uint8 *buffer, uint8 **subFilesArray, uint8 *destBuffer) { + debugC(1, kDebugUtils, "loadImageSet %d", imageSetId); Common::String fileName = Common::String::format("imageset.%d", imageSetId); rImageFile(fileName, buffer, subFilesArray, destBuffer); } void EfhEngine::rImageFile(Common::String filename, uint8 *targetBuffer, uint8 **subFilesArray, uint8 *packedBuffer) { + debugC(1, kDebugUtils, "rImageFile %s", filename.c_str()); readFileToBuffer(filename, packedBuffer); uint32 size = uncompressBuffer(packedBuffer, targetBuffer); // TODO: Keep this dump for debug purposes only @@ -115,6 +119,7 @@ void EfhEngine::rImageFile(Common::String filename, uint8 *targetBuffer, uint8 * } uint32 EfhEngine::uncompressBuffer(uint8 *compressedBuf, uint8 *destBuf) { + debugC(1, kDebugUtils, "uncompressBuffer"); if (compressedBuf == nullptr || destBuf == nullptr) error("uncompressBuffer - Invalid pointer used in parameter list"); @@ -167,6 +172,7 @@ uint32 EfhEngine::uncompressBuffer(uint8 *compressedBuf, uint8 *destBuf) { } int16 EfhEngine::getRandom(int16 maxVal) { + debugC(1, kDebugUtils, "getRandom %d", maxVal); if (maxVal == 0) return 0; @@ -174,6 +180,7 @@ int16 EfhEngine::getRandom(int16 maxVal) { } Common::KeyCode EfhEngine::getLastCharAfterAnimCount(int16 delay) { + debugC(1, kDebugUtils, "getLastCharAfterAnimCount %d", delay); if (delay == 0) return Common::KEYCODE_INVALID; @@ -197,6 +204,7 @@ Common::KeyCode EfhEngine::getLastCharAfterAnimCount(int16 delay) { } Common::KeyCode EfhEngine::getInput(int16 delay) { + debugC(1, kDebugUtils, "getInput %d", delay); if (delay == 0) return Common::KEYCODE_INVALID; @@ -223,6 +231,7 @@ Common::KeyCode EfhEngine::getInput(int16 delay) { } Common::KeyCode EfhEngine::waitForKey() { + debugC(1, kDebugUtils, "waitForKey"); Common::KeyCode retVal = Common::KEYCODE_INVALID; Common::Event event; @@ -256,6 +265,7 @@ Common::KeyCode EfhEngine::mapInputCode(Common::KeyCode input) { } Common::KeyCode EfhEngine::handleAndMapInput(bool animFl) { + debugC(1, kDebugUtils, "handleAndMapInput %s", animFl ? "True" : "False"); // The original checks for the joystick input Common::Event event; _system->getEventManager()->pollEvent(event); @@ -271,6 +281,7 @@ Common::KeyCode EfhEngine::handleAndMapInput(bool animFl) { } Common::KeyCode EfhEngine::getInputBlocking() { + debugC(1, kDebugUtils, "getInputBlocking"); // The original checks for the joystick input Common::Event event; _system->getEventManager()->pollEvent(event); @@ -298,6 +309,7 @@ void EfhEngine::setNumLock() { } void EfhEngine::copyString(char *srcStr, char *destStr) { + debugC(1, kDebugUtils, "copyString %s", srcStr); char lastChar = 1; int16 idx = 0; @@ -308,6 +320,7 @@ void EfhEngine::copyString(char *srcStr, char *destStr) { } bool EfhEngine::getValidationFromUser() { + debugC(1, kDebugUtils, "getValidationFromUser"); Common::KeyCode input = handleAndMapInput(true); if (input == Common::KEYCODE_y) // or if joystick button 1 return true; From 5cb54e592234c411dde985f8d2e0743e0d6a5e4a Mon Sep 17 00:00:00 2001 From: Strangerke Date: Tue, 28 Dec 2021 11:37:09 +0100 Subject: [PATCH 112/412] EFH: Small modification in NPCStruct, some renaming --- engines/efh/efh.cpp | 168 +++++++++++++++++++++----------------------- engines/efh/efh.h | 10 ++- 2 files changed, 86 insertions(+), 92 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index c88075ab8eff..7d96c08af88f 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -102,10 +102,8 @@ void ItemStruct::init() { } void NPCStruct::init() { - for (int i = 0; i < 9; ++i) + for (int i = 0; i < 11; ++i) _name[i] = 0; - field_9 = 0; - field_A = 0; field_B = 0; field_C = 0; field_D = 0; @@ -703,10 +701,8 @@ void EfhEngine::loadNPCS() { uint8 *curPtr = npcLoading; for (int i = 0; i < 99; ++i) { - for (int idx = 0; idx < 9; ++idx) + for (int idx = 0; idx < 11; ++idx) _npcBuf[i]._name[idx] = *curPtr++; - _npcBuf[i].field_9 = *curPtr++; - _npcBuf[i].field_A = *curPtr++; _npcBuf[i].field_B = *curPtr++; _npcBuf[i].field_C = *curPtr++; _npcBuf[i].field_D = *curPtr++; @@ -798,10 +794,10 @@ void EfhEngine::playIntro() { // With GF on the bed displayRawDataAtPos(_circleImageSubFileArray[0], 0, 144); - sub133E5(_imp2PtrArray[0], 6, 150, 268, 186, 0); + sub133E5(_imp2PtrArray[0], 6, 150, 268, 186, false); displayFctFullScreen(); displayRawDataAtPos(_circleImageSubFileArray[0], 0, 144); - sub133E5(_imp2PtrArray[0], 6, 150, 268, 186, 0); + sub133E5(_imp2PtrArray[0], 6, 150, 268, 186, false); lastInput = getLastCharAfterAnimCount(80); if (lastInput == Common::KEYCODE_ESCAPE) return; @@ -809,11 +805,11 @@ void EfhEngine::playIntro() { // Poof displayRawDataAtPos(_circleImageSubFileArray[1], 110, 16); displayRawDataAtPos(_circleImageSubFileArray[0], 0, 144); - sub133E5(_imp2PtrArray[1], 6, 150, 268, 186, 0); + sub133E5(_imp2PtrArray[1], 6, 150, 268, 186, false); displayFctFullScreen(); displayRawDataAtPos(_circleImageSubFileArray[1], 110, 16); displayRawDataAtPos(_circleImageSubFileArray[0], 0, 144); - sub133E5(_imp2PtrArray[1], 6, 150, 268, 186, 0); + sub133E5(_imp2PtrArray[1], 6, 150, 268, 186, false); lastInput = getLastCharAfterAnimCount(80); if (lastInput == Common::KEYCODE_ESCAPE) return; @@ -821,38 +817,38 @@ void EfhEngine::playIntro() { // On the phone displayRawDataAtPos(_circleImageSubFileArray[2], 110, 16); displayRawDataAtPos(_circleImageSubFileArray[0], 0, 144); - sub133E5(_imp2PtrArray[2], 6, 150, 268, 186, 0); + sub133E5(_imp2PtrArray[2], 6, 150, 268, 186, false); displayFctFullScreen(); displayRawDataAtPos(_circleImageSubFileArray[2], 110, 16); displayRawDataAtPos(_circleImageSubFileArray[0], 0, 144); - sub133E5(_imp2PtrArray[2], 6, 150, 268, 186, 0); + sub133E5(_imp2PtrArray[2], 6, 150, 268, 186, false); lastInput = getLastCharAfterAnimCount(80); if (lastInput == Common::KEYCODE_ESCAPE) return; displayRawDataAtPos(_circleImageSubFileArray[0], 0, 144); - sub133E5(_imp2PtrArray[3], 6, 150, 268, 186, 0); + sub133E5(_imp2PtrArray[3], 6, 150, 268, 186, false); displayFctFullScreen(); displayRawDataAtPos(_circleImageSubFileArray[0], 0, 144); - sub133E5(_imp2PtrArray[3], 6, 150, 268, 186, 0); + sub133E5(_imp2PtrArray[3], 6, 150, 268, 186, false); lastInput = getLastCharAfterAnimCount(80); if (lastInput == Common::KEYCODE_ESCAPE) return; displayRawDataAtPos(_circleImageSubFileArray[0], 0, 144); - sub133E5(_imp2PtrArray[4], 6, 150, 268, 186, 0); + sub133E5(_imp2PtrArray[4], 6, 150, 268, 186, false); displayFctFullScreen(); displayRawDataAtPos(_circleImageSubFileArray[0], 0, 144); - sub133E5(_imp2PtrArray[4], 6, 150, 268, 186, 0); + sub133E5(_imp2PtrArray[4], 6, 150, 268, 186, false); lastInput = getLastCharAfterAnimCount(80); if (lastInput == Common::KEYCODE_ESCAPE) return; displayRawDataAtPos(_circleImageSubFileArray[0], 0, 144); - sub133E5(_imp2PtrArray[5], 6, 150, 268, 186, 0); + sub133E5(_imp2PtrArray[5], 6, 150, 268, 186, false); displayFctFullScreen(); displayRawDataAtPos(_circleImageSubFileArray[0], 0, 144); - sub133E5(_imp2PtrArray[5], 6, 150, 268, 186, 0); + sub133E5(_imp2PtrArray[5], 6, 150, 268, 186, false); getLastCharAfterAnimCount(80); } @@ -910,7 +906,7 @@ void EfhEngine::initEngine() { _mapMonsters[i]._posY = 0; _mapMonsters[i]._itemId_Weapon = 0; _mapMonsters[i]._field_6 = 0; - _mapMonsters[i]._MonsterRef = 0; + _mapMonsters[i]._monsterRef = 0; _mapMonsters[i]._field_8 = 0; _mapMonsters[i]._field_9 = 0; _mapMonsters[i]._groupSize = 0; @@ -1005,7 +1001,7 @@ void EfhEngine::initMapMonsters() { for (uint8 counter = 0; counter < groupSize; ++counter) { uint rand100 = getRandom(100); - uint16 pictureRef = kEncounters[_mapMonsters[monsterId]._MonsterRef]._pictureRef; + uint16 pictureRef = kEncounters[_mapMonsters[monsterId]._monsterRef]._pictureRef; if (rand100 <= 25) { uint16 delta = getRandom(pictureRef / 2); @@ -1043,7 +1039,7 @@ void EfhEngine::loadMapMonsters() { _mapMonsters[i]._posY = mapMonstersPtr[29 * i + 4]; _mapMonsters[i]._itemId_Weapon = mapMonstersPtr[29 * i + 5]; _mapMonsters[i]._field_6 = mapMonstersPtr[29 * i + 6]; - _mapMonsters[i]._MonsterRef = mapMonstersPtr[29 * i + 7]; + _mapMonsters[i]._monsterRef = mapMonstersPtr[29 * i + 7]; _mapMonsters[i]._field_8 = mapMonstersPtr[29 * i + 8]; _mapMonsters[i]._field_9 = mapMonstersPtr[29 * i + 9]; _mapMonsters[i]._groupSize = mapMonstersPtr[29 * i + 10]; @@ -1202,7 +1198,7 @@ void EfhEngine::drawMap(bool largeMapFl, int16 mapPosX, int16 mapPosY, int mapSi if (!var4) continue; - var6 = 148 + kEncounters[_mapMonsters[var16]._MonsterRef]._animId; + var6 = 148 + kEncounters[_mapMonsters[var16]._monsterRef]._animId; int16 var1 = _mapMonsters[var16]._possessivePronounSHL6 & 0x3F; if (var1 == 0x3F && isCharacterATeamMember(_mapMonsters[var16]._field_1)) @@ -1547,7 +1543,7 @@ int16 EfhEngine::handleCharacterJoining() { return 2; } -int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, int maxY, int argC) { +int16 EfhEngine::script_parse(uint8 *stringBuffer, int16 posX, int16 posY, int16 maxX, int16 maxY, bool flag) { bool doneFlag = false; int16 var_F2 = -1; int16 var_F0 = 0xFF; @@ -1617,7 +1613,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, switch (var_108) { case 0x00: buffer = script_readNumberArray(buffer, 3, scriptNumberArray); - if (argC != 0) { + if (flag) { if (_largeMapFlag) { _largeMapFlag = false; _techDataId_MapPosX = _mapPosX; @@ -1631,7 +1627,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, } break; case 0x01: - if (argC != 0) { + if (flag) { _largeMapFlag = true; _oldMapPosX = _mapPosX = _techDataId_MapPosX; _oldMapPosY = _mapPosY = _techDataId_MapPosY; @@ -1641,7 +1637,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, break; case 0x02: buffer = script_readNumberArray(buffer, 3, scriptNumberArray); - if (argC != 0) { + if (flag) { if (_word2C8D7) writeTechAndMapFiles(); _oldMapPosX = _mapPosX = scriptNumberArray[1]; @@ -1655,7 +1651,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, break; case 0x03: buffer = script_readNumberArray(buffer, 4, scriptNumberArray); - if (argC != 0) { + if (flag) { int16 var110 = scriptNumberArray[2] - scriptNumberArray[0]; int16 var10E = scriptNumberArray[3] - scriptNumberArray[1]; @@ -1667,7 +1663,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, break; case 0x04: buffer = script_readNumberArray(buffer, 2, scriptNumberArray); - if (argC != 0) { + if (flag) { _mapPosX = scriptNumberArray[0]; _mapPosY = scriptNumberArray[1]; _word2C880 = true; @@ -1676,7 +1672,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, break; case 0x05: buffer = script_readNumberArray(buffer, 4, scriptNumberArray); - if (argC != 0) { + if (flag) { int16 var110 = _teamCharId[scriptNumberArray[0]]; if (var110 != -1) { int16 var10E = scriptNumberArray[1]; @@ -1687,7 +1683,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, break; case 0x06: buffer = script_readNumberArray(buffer, 2, scriptNumberArray); - if (argC != 0) { + if (flag) { int16 var110 = _teamCharId[scriptNumberArray[0]]; if (var110 != -1) { int16 var10E = scriptNumberArray[1]; @@ -1696,20 +1692,20 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, } break; case 0x07: - if (argC != 0) { + if (flag) { totalPartyKill(); // emptyFunction(2); } break; case 0x08: buffer = script_readNumberArray(buffer, 1, scriptNumberArray); - if (argC != 0 && scriptNumberArray[0] != -1) { + if (flag && scriptNumberArray[0] != -1) { _npcBuf[_teamCharId[scriptNumberArray[0]]]._hitPoints = 0; } break; case 0x09: buffer = script_readNumberArray(buffer, 2, scriptNumberArray); - if (argC != 0) { + if (flag) { int16 var110 = _teamCharId[scriptNumberArray[0]]; if (var110 != -1) { int16 var10E = getRandom(scriptNumberArray[1]); @@ -1721,7 +1717,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, break; case 0x0A: buffer = script_readNumberArray(buffer, 1, scriptNumberArray); - if (argC != 0) { + if (flag) { int16 var110 = _teamCharId[scriptNumberArray[0]]; if (var110 != -1) { _npcBuf[var110]._hitPoints = _npcBuf[var110]._maxHP; @@ -1730,7 +1726,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, break; case 0x0B: buffer = script_readNumberArray(buffer, 2, scriptNumberArray); - if (argC != 0) { + if (flag) { int16 var110 = _teamCharId[scriptNumberArray[0]]; if (var110 != -1) { int16 var10E = getRandom(scriptNumberArray[1]); @@ -1742,7 +1738,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, break; case 0x0C: buffer = script_readNumberArray(buffer, 2, scriptNumberArray); - if (argC != 0) { + if (flag) { int16 var110 = _teamCharId[scriptNumberArray[0]]; bool found = false; for (int16 counter = 0; counter < _teamSize && !found; ++counter) { @@ -1758,7 +1754,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, break; case 0x0D: buffer = script_readNumberArray(buffer, 1, scriptNumberArray); - if (argC != 0) { + if (flag) { int16 var110 = _teamCharId[scriptNumberArray[0]]; for (int16 counter = 0; counter < _teamSize; ++counter) { if (giveItemTo(_teamCharId[counter], var110, 0xFF)) @@ -1768,7 +1764,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, break; case 0x0E: buffer = script_readNumberArray(buffer, 3, scriptNumberArray); - if (argC != 0) { + if (flag) { int16 var110 = scriptNumberArray[0]; bool found = false; for (int16 counter = 0; counter < _teamSize && !found; ++counter) { @@ -1788,7 +1784,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, break; case 0x0F: buffer = script_readNumberArray(buffer, 3, scriptNumberArray); - if (argC != 0) { + if (flag) { int16 var110 = scriptNumberArray[0]; if (isCharacterATeamMember(var110)) var_F0 = scriptNumberArray[1]; @@ -1798,16 +1794,16 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, break; case 0x10: buffer = script_readNumberArray(buffer, 1, scriptNumberArray); - if (argC != 0) + if (flag) var_F0 = scriptNumberArray[0]; break; case 0x11: - if (argC != 0) + if (flag) _unkArray2C8AA[0] = 0; break; case 0x12: - if (argC != 0) { + if (flag) { int16 var110 = sub151FD(_mapPosX, _mapPosY); if (var110 != -1) _mapUnknown[var110]._field1 = 0xFF; @@ -1815,7 +1811,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, break; case 0x13: buffer = script_readNumberArray(buffer, 3, scriptNumberArray); - if (argC != 0 && _largeMapFlag) { + if (flag && _largeMapFlag) { _word2C87A = true; loadPlacesFile(scriptNumberArray[0], false); sub15A28(scriptNumberArray[1], scriptNumberArray[2]); @@ -1825,7 +1821,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, break; case 0x14: buffer = script_readNumberArray(buffer, 1, scriptNumberArray); - if (argC != 0) { + if (flag) { int16 var110 = scriptNumberArray[0]; if (!isCharacterATeamMember(var110)) var_EE = var110; @@ -1834,7 +1830,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, break; case 0x15: buffer = script_readNumberArray(buffer, 2, scriptNumberArray); - if (argC != 0) { + if (flag) { _oldMapPosX = _mapPosX = scriptNumberArray[0]; _oldMapPosY = _mapPosY = scriptNumberArray[1]; _largeMapFlag = true; @@ -1843,7 +1839,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, break; case 0x16: buffer = script_readNumberArray(buffer, 1, scriptNumberArray); - if (argC != 0) { + if (flag) { int16 var110 = scriptNumberArray[0]; // TODO: This "if" is useless, it's doing just the same loop and if statement. Consider removing it. if (isCharacterATeamMember(var110)) { @@ -1858,14 +1854,14 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, break; case 0x17: buffer = script_readNumberArray(buffer, 1, scriptNumberArray); - if (argC != 0) { + if (flag) { int16 var110 = scriptNumberArray[0]; displayAnimFrames(var110, true); } break; case 0x18: buffer = script_readNumberArray(buffer, 2, scriptNumberArray); - if (argC != 0) { + if (flag) { int16 var110 = scriptNumberArray[1] - scriptNumberArray[0] + 1; bool found = false; var110 = getRandom(var110) + scriptNumberArray[0] - 1; @@ -1903,7 +1899,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, break; case 0x19: buffer = script_readNumberArray(buffer, 3, scriptNumberArray); - if (argC != 0) { + if (flag) { if (_largeMapFlag) { _mapGameMapPtr[scriptNumberArray[0] * 6 + scriptNumberArray[1]] = scriptNumberArray[2] & 0xFF; } else { @@ -1913,7 +1909,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, break; case 0x1A: buffer = script_readNumberArray(buffer, 2, scriptNumberArray); - if (argC != 0) { + if (flag) { int16 var110 = sub151FD(scriptNumberArray[0], scriptNumberArray[1]); if (var110 != -1) { _mapUnknown[var110]._field1 = 0xFF; @@ -1922,7 +1918,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, break; case 0x1B: buffer = script_readNumberArray(buffer, 3, scriptNumberArray); - if (argC != 0) { + if (flag) { int16 var110 = sub151FD(scriptNumberArray[0], scriptNumberArray[1]); if (var110 != -1) { _mapUnknown[var110]._field1 = 0xFF; @@ -1933,19 +1929,19 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, break; case 0x1C: buffer = script_readNumberArray(buffer, 1, scriptNumberArray); - if (argC != 0) { + if (flag) { _history[scriptNumberArray[0]] = 0xFF; } break; case 0x1D: buffer = script_readNumberArray(buffer, 1, scriptNumberArray); - if (argC != 0) { + if (flag) { _history[scriptNumberArray[0]] = 0; } break; case 0x1E: buffer = script_readNumberArray(buffer, 3, scriptNumberArray); - if (argC != 0) { + if (flag) { if (_history[scriptNumberArray[0]] == 0) var_F0 = scriptNumberArray[2]; else @@ -1954,12 +1950,12 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, break; case 0x1F: buffer = script_readNumberArray(buffer, 1, scriptNumberArray); - if (argC != 0) + if (flag) _unkArray2C8AA[0] = scriptNumberArray[0]; break; case 0x20: - if (argC != 0) { + if (flag) { handleWinSequence(); _system->quit(); } @@ -1983,7 +1979,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int posX, int posY, int maxX, return var_F0; } -void EfhEngine::sub133E5(uint8 *srcPtr, int posX, int posY, int maxX, int maxY, int argC) { +void EfhEngine::sub133E5(uint8 *srcPtr, int16 posX, int16 posY, int16 maxX, int16 maxY, bool flag) { uint16 stringIdx = 0; uint8 *impPtr = srcPtr; memset(_messageToBePrinted, 0, 200); @@ -2005,7 +2001,7 @@ void EfhEngine::sub133E5(uint8 *srcPtr, int posX, int posY, int maxX, int maxY, } } - script_parse(_messageToBePrinted, posX, posY, maxX, maxY, argC); + script_parse(_messageToBePrinted, posX, posY, maxX, maxY, flag); } void EfhEngine::sub221FA(uint8 *impArray, bool flag) { @@ -2015,7 +2011,7 @@ void EfhEngine::sub221FA(uint8 *impArray, bool flag) { if (impArray != nullptr) { _word2C86E = 4; _dword2C856 = impArray; - sub133E5(impArray, 17, 115, 110, 133, 0); + sub133E5(impArray, 17, 115, 110, 133, false); } if (counter == 0 && flag) displayFctFullScreen(); @@ -2115,7 +2111,7 @@ int16 EfhEngine::sub1C219(uint8 *str, int menuType, int arg4, bool displayTeamWi drawColoredRect(minX, maxX, minY, maxY, 0); if (str) - varA = script_parse(str, minX, minY, maxX, maxY, -1); + varA = script_parse(str, minX, minY, maxX, maxY, true); if (displayTeamWindowFl) displayLowStatusScreen(false); @@ -2127,7 +2123,7 @@ int16 EfhEngine::sub1C219(uint8 *str, int menuType, int arg4, bool displayTeamWi else { drawColoredRect(minX, maxX, minY, maxY, 0); if (str) - int16 varC = script_parse(str, minX, minY, maxX, maxY, -1); + int16 varC = script_parse(str, minX, minY, maxX, maxY, true); } if (displayTeamWindowFl) @@ -2832,7 +2828,7 @@ bool EfhEngine::checkPictureRefAvailability(int16 monsterId) { } void EfhEngine::displayMonsterAnim(int16 monsterId) { - int16 animId = kEncounters[_mapMonsters[monsterId]._MonsterRef]._animId; + int16 animId = kEncounters[_mapMonsters[monsterId]._monsterRef]._animId; displayAnimFrames(animId, true); } @@ -3651,7 +3647,7 @@ void EfhEngine::sub1BE9A(int16 monsterId) { for (int16 counter1 = var4; counter1 < 5; ++counter1) { _teamMonsterIdArray[counter1] = -1; for (int16 counter2 = 0; counter2 < 9; ++counter2) { - _stru32686[counter1]._field0[counter2] = 0x8000; + _stru32686[counter1]._field0[counter2] = (int16)0x8000; } } // sub1BE9A - last loop counter1_monsterId - End @@ -3660,19 +3656,19 @@ void EfhEngine::sub1BE9A(int16 monsterId) { int16 EfhEngine::getTeamMonsterAnimId() { int16 retVal = 0xFF; for (int16 counter = 0; counter < 5; ++counter) { - int16 monsterGroupId = _teamMonsterIdArray[counter]; - if (monsterGroupId == -1) + int16 monsterId = _teamMonsterIdArray[counter]; + if (monsterId == -1) continue; - if (!unkFct_checkMonsterField8(monsterGroupId, false)) + if (!unkFct_checkMonsterField8(monsterId, false)) continue; - retVal = kEncounters[_mapMonsters[monsterGroupId]._MonsterRef]._animId; + retVal = kEncounters[_mapMonsters[monsterId]._monsterRef]._animId; break; } if (retVal == 0xFF) - retVal = kEncounters[_mapMonsters[_teamMonsterIdArray[0]]._MonsterRef]._animId; + retVal = kEncounters[_mapMonsters[_teamMonsterIdArray[0]]._monsterRef]._animId; return retVal; } @@ -3707,7 +3703,7 @@ void EfhEngine::sub1C4CA(bool whiteFl) { setTextColorRed(); int16 var1 = _mapMonsters[_teamMonsterIdArray[counter]]._possessivePronounSHL6 & 0x3F; if (var1 <= 0x3D) { - sprintf(buffer, "%d %s", var6E, kEncounters[_mapMonsters[_teamMonsterIdArray[counter]]._MonsterRef]._name); + sprintf(buffer, "%d %s", var6E, kEncounters[_mapMonsters[_teamMonsterIdArray[counter]]._monsterRef]._name); displayStringAtTextPos(buffer); if (var6E > 1) displayStringAtTextPos("s"); @@ -4258,11 +4254,11 @@ void EfhEngine::getDeathTypeDescription(int16 attackerId, int16 victimId) { bool EfhEngine::characterSearchesMonsterCorpse(int16 charId, int16 monsterId) { int16 rndVal = getRandom(100); - if (kEncounters[_mapMonsters[monsterId]._MonsterRef]._dropOccurrencePct < rndVal) + if (kEncounters[_mapMonsters[monsterId]._monsterRef]._dropOccurrencePct < rndVal) return false; rndVal = getRandom(5) - 1; - int16 itemId = kEncounters[_mapMonsters[monsterId]._MonsterRef]._dropItemId[rndVal]; + int16 itemId = kEncounters[_mapMonsters[monsterId]._monsterRef]._dropItemId[rndVal]; if (itemId == -1) return false; @@ -4279,9 +4275,9 @@ bool EfhEngine::characterSearchesMonsterCorpse(int16 charId, int16 monsterId) { void EfhEngine::getXPAndSearchCorpse(int16 charId, char *namePt1, char *namePt2, int16 monsterId) { int16 xpLevel = getXPLevel(_npcBuf[charId]._xp); - _npcBuf[charId]._xp += kEncounters[_mapMonsters[monsterId]._MonsterRef]._xpGiven; + _npcBuf[charId]._xp += kEncounters[_mapMonsters[monsterId]._monsterRef]._xpGiven; char buffer[80]; - sprintf(buffer, " %s%s gains %d experience", namePt1, namePt2, kEncounters[_mapMonsters[monsterId]._MonsterRef]._xpGiven); + sprintf(buffer, " %s%s gains %d experience", namePt1, namePt2, kEncounters[_mapMonsters[monsterId]._monsterRef]._xpGiven); if (getXPLevel(_npcBuf[charId]._xp) > xpLevel) { generateSound(15); int16 var2 = getRandom(20) + getRandom(_npcBuf[charId]._infoScore[4]); @@ -4468,7 +4464,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { var51 >>= 6; int16 var70 = var51; varInt = _teamMonsterIdArray[groupId]; - int16 var5E = kEncounters[_mapMonsters[varInt]._MonsterRef]._nameArticle; + int16 var5E = kEncounters[_mapMonsters[varInt]._monsterRef]._nameArticle; int16 charScore = getCharacterScore(_teamCharId[teamCharId], unk_monsterField5_itemId); int16 var80 = _mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E]; int16 var62 = 0; @@ -4525,7 +4521,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { *_enemyNamePt1 = 0; } - strcpy(_characterNamePt2, kEncounters[_mapMonsters[_teamMonsterIdArray[groupId]]._MonsterRef]._name); + strcpy(_characterNamePt2, kEncounters[_mapMonsters[_teamMonsterIdArray[groupId]]._monsterRef]._name); copyString(_npcBuf[_teamCharId[teamCharId]]._name, _enemyNamePt2); copyString(_items[unk_monsterField5_itemId]._name, _nameBuffer); if (checkSpecialItemsOnCurrentPlace(unk_monsterField5_itemId)) { @@ -4857,7 +4853,7 @@ bool EfhEngine::handleFight(int16 monsterId) { int16 var76 = getRandom(getEquipmentDefense(_teamCharId[var7E], false)); varInt = _teamMonsterIdArray[monsterGroupIdOrMonsterId]; - int16 var70 = kEncounters[_mapMonsters[varInt]._MonsterRef]._nameArticle; + int16 var70 = kEncounters[_mapMonsters[varInt]._monsterRef]._nameArticle; int16 var5E = _npcBuf[_teamCharId[var7E]]._possessivePronounSHL6 >> 6; varInt = _items[unk_monsterField5_itemId].field_13; _word32482[var7E] += (varInt * 5); @@ -4915,7 +4911,7 @@ bool EfhEngine::handleFight(int16 monsterId) { else *_enemyNamePt1 = 0; - strcpy(_enemyNamePt2, kEncounters[_mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._MonsterRef]._name); + strcpy(_enemyNamePt2, kEncounters[_mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._monsterRef]._name); copyString(_npcBuf[_teamCharId[var7E]]._name, _characterNamePt2); copyString(_items[unk_monsterField5_itemId]._name, _nameBuffer); if (checkSpecialItemsOnCurrentPlace(unk_monsterField5_itemId)) { @@ -5018,8 +5014,8 @@ bool EfhEngine::handleFight(int16 monsterId) { } else if (_mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._pictureRef[var86] > 0 && _stru32686[monsterGroupIdOrMonsterId]._field0[var86]) { --_stru32686[monsterGroupIdOrMonsterId]._field2[var86]; if (_stru32686[monsterGroupIdOrMonsterId]._field2[var86] <= 0) { - strcpy(_enemyNamePt2, kEncounters[_mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._MonsterRef]._name); - int16 var70 = kEncounters[_mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._MonsterRef]._nameArticle; + strcpy(_enemyNamePt2, kEncounters[_mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._monsterRef]._name); + int16 var70 = kEncounters[_mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._monsterRef]._nameArticle; if (var70 == 2) strcpy(_enemyNamePt1, "The "); else @@ -5378,7 +5374,7 @@ int16 EfhEngine::displayString_3(const char *str, bool animFl, int16 charId, int script_parse((uint8 *)str, 28, 122, 105, 166, 0); displayFctFullScreen(); } else { - retVal = script_parse((uint8 *)str, 28, 122, 105, 166, -1); + retVal = script_parse((uint8 *)str, 28, 122, 105, 166, true); } } @@ -5516,9 +5512,9 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me } // The original was duplicating this code in each branch of the previous random check. if (victims > 1) { - sprintf(buffer1, "%d %ss fall asleep!", victims, kEncounters[_mapMonsters[_teamMonsterIdArray[windowId]]._MonsterRef]._name); + sprintf(buffer1, "%d %ss fall asleep!", victims, kEncounters[_mapMonsters[_teamMonsterIdArray[windowId]]._monsterRef]._name); } else { - sprintf(buffer1, "%d %s falls asleep!", victims, kEncounters[_mapMonsters[_teamMonsterIdArray[windowId]]._MonsterRef]._name); + sprintf(buffer1, "%d %s falls asleep!", victims, kEncounters[_mapMonsters[_teamMonsterIdArray[windowId]]._monsterRef]._name); } strcat((char *)_messageToBePrinted, buffer1); } @@ -5556,9 +5552,9 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me // : This part is only present in the original in the case < 50, but for me // it's missing in the other case as there's an effect (frozen enemies) but no feedback to the player if (victim > 1) { - sprintf(buffer1, "%d %ss are frozen in place!", victim, kEncounters[_mapMonsters[_teamMonsterIdArray[windowId]]._MonsterRef]._name); + sprintf(buffer1, "%d %ss are frozen in place!", victim, kEncounters[_mapMonsters[_teamMonsterIdArray[windowId]]._monsterRef]._name); } else { - sprintf(buffer1, "%d %s is frozen in place!", victim, kEncounters[_mapMonsters[_teamMonsterIdArray[windowId]]._MonsterRef]._name); + sprintf(buffer1, "%d %s is frozen in place!", victim, kEncounters[_mapMonsters[_teamMonsterIdArray[windowId]]._monsterRef]._name); } strcat((char *)_messageToBePrinted, buffer1); // @@ -6446,7 +6442,7 @@ bool EfhEngine::sub16E14() { for (int16 var6C = 0; var6C < 2; ++var6C) { int16 var1 = _mapMonsters[monsterId]._possessivePronounSHL6 & 0x3F; if (var1 <= 0x3D) { - strcpy(dest, kEncounters[_mapMonsters[monsterId]._MonsterRef]._name); + strcpy(dest, kEncounters[_mapMonsters[monsterId]._monsterRef]._name); if (var6A > 1) strcat(dest, " "); @@ -6454,7 +6450,7 @@ bool EfhEngine::sub16E14() { } else if (var1 == 0x3E) { strcpy(buffer, "(NOT DEFINED)"); } else if (var1 == 0x3F) { // Useless check, it's the last possible value - copyString(_npcBuf[_mapMonsters[monsterId]._MonsterRef]._name, dest); + copyString(_npcBuf[_mapMonsters[monsterId]._monsterRef]._name, dest); sprintf(buffer, "with %s", dest); } diff --git a/engines/efh/efh.h b/engines/efh/efh.h index eeaf9b259f7f..4be294d1e587 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -132,9 +132,7 @@ struct ItemStruct { }; struct NPCStruct { - char _name[9]; - uint8 field_9; - uint8 field_A; + char _name[11]; uint8 field_B; uint8 field_C; uint8 field_D; @@ -213,7 +211,7 @@ struct MapMonster { uint8 _posY; uint8 _itemId_Weapon; uint8 _field_6; - uint8 _MonsterRef; + uint8 _monsterRef; uint8 _field_8; uint8 _field_9; uint8 _groupSize; @@ -322,8 +320,8 @@ class EfhEngine : public Engine { bool giveItemTo(int16 charId, int16 objectId, int16 altCharId); int16 chooseCharacterToReplace(); int16 handleCharacterJoining(); - int16 script_parse(uint8 *str, int posX, int posY, int maxX, int maxY, int argC); - void sub133E5(uint8 *impPtr, int posX, int posY, int maxX, int maxY, int argC); + int16 script_parse(uint8 *str, int16 posX, int16 posY, int16 maxX, int16 maxY, bool flag); + void sub133E5(uint8 *impPtr, int16 posX, int16 posY, int16 maxX, int16 maxY, bool flag); void sub221FA(uint8 *impArray, bool flag); void sub15A28(int16 arg0, int16 arg2); void sub2455E(int16 arg0, int16 arg1, int16 arg2); From 8cffee5e899d03ed5b501a6cd1e57f4eaf2e334e Mon Sep 17 00:00:00 2001 From: Strangerke Date: Wed, 29 Dec 2021 12:25:54 +0100 Subject: [PATCH 113/412] EFH: Turn _mapGameMap and _curPlace into arrays --- engines/efh/efh.cpp | 49 ++++++++++++++++++++++++++------------------- engines/efh/efh.h | 4 ++-- 2 files changed, 30 insertions(+), 23 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 7d96c08af88f..7cbaa1badaa7 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -192,7 +192,6 @@ EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst) _videoMode = 0; _graphicsStruct = nullptr; _mapBitmapRef = nullptr; - _mapGameMapPtr = nullptr; _defaultBoxColor = 0; @@ -881,6 +880,7 @@ void EfhEngine::initEngine() { memset(_map, 0, sizeof(_map)); memset(_places, 0, sizeof(_places)); memset(_curPlace, 0, sizeof(_curPlace)); + memset(_mapGameMap, 0, sizeof(_mapGameMap)); memset(_npcBuf, 0, sizeof(_npcBuf)); memset(_imp1, 0, sizeof(_imp1)); memset(_imp2, 0, sizeof(_imp2)); @@ -914,7 +914,10 @@ void EfhEngine::initEngine() { _mapMonsters[i]._pictureRef[j] = 0; } - _mapGameMapPtr = &_map[2758]; + uint8 *_mapPtr = &_map[2758]; + for (int i = 0; i < 64; ++i) + for (int j = 0; j < 64; ++j) + _mapGameMap[i][j] = *_mapPtr++; _vgaGraphicsStruct2->copy(_vgaGraphicsStruct1); _vgaGraphicsStruct2->_shiftValue = 0x2000; @@ -1163,10 +1166,10 @@ void EfhEngine::drawMap(bool largeMapFl, int16 mapPosX, int16 mapPosY, int mapSi int16 var12 = 128; for (int16 var16 = minX; var16 <= maxX; ++var16) { if (largeMapFl) { - int16 idx = _mapGameMapPtr[(var16 * 64) + counterY]; // 64 = large map size (square) + int16 idx = _mapGameMap[var16][counterY]; displayRawDataAtPos(_imageSetSubFilesArray[idx], var12, var10); } else { - int16 idx = _curPlace[(var16 * 24) + counterY]; // 24 = small map size (square) + int16 idx = _curPlace[var16][counterY]; displayRawDataAtPos(_imageSetSubFilesArray[idx], var12, var10); } var12 += 16; @@ -1901,9 +1904,9 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int16 posX, int16 posY, int16 buffer = script_readNumberArray(buffer, 3, scriptNumberArray); if (flag) { if (_largeMapFlag) { - _mapGameMapPtr[scriptNumberArray[0] * 6 + scriptNumberArray[1]] = scriptNumberArray[2] & 0xFF; + _mapGameMap[scriptNumberArray[0]][scriptNumberArray[1]] = scriptNumberArray[2] & 0xFF; } else { - _curPlace[scriptNumberArray[0] * 24 + scriptNumberArray[1]] = scriptNumberArray[2] & 0xFF; + _curPlace[scriptNumberArray[0]][scriptNumberArray[1]] = scriptNumberArray[2] & 0xFF; } } break; @@ -2033,7 +2036,7 @@ void EfhEngine::sub15A28(int16 arg0, int16 arg2) { for (int16 var8 = 0; var8 <= 23; ++var8) { int16 var4 = counter + varE; int16 var2 = var8 + varC; - _mapGameMapPtr[var2 + 64 * var4] = _curPlace[var8 + counter * 24]; + _mapGameMap[var4][var2] = _curPlace[counter][var8]; } redrawScreen(); } @@ -2042,7 +2045,7 @@ void EfhEngine::sub15A28(int16 arg0, int16 arg2) { for (int16 var8 = 0; var8 <= 23; ++var8) { int16 var4 = counter + varE; int16 var2 = var8 + varC; - _mapGameMapPtr[var2 + 64 * var4] = _curPlace[var8 + counter * 24]; + _mapGameMap[var4][var2] = _curPlace[counter][var8]; } redrawScreen(); } @@ -2398,24 +2401,24 @@ void EfhEngine::computeMapAnimation() { if (_largeMapFlag) { if (_currentTileBankImageSetId[0] != 0) continue; - uint8 var4 = _mapGameMapPtr[counterX * 64 + counterY]; + uint8 var4 = _mapGameMap[counterX][counterY]; if (var4 >= 1 && var4 <= 0xF) { if (getRandom(100) < 50) - _mapGameMapPtr[counterX * 64 + counterY] += 0xC5; + _mapGameMap[counterX][counterY] += 0xC5; } else if (var4 >= 0xC6 && var4 <= 0xD5) { if (getRandom(100) < 50) - _mapGameMapPtr[counterX * 64 + counterY] -= 0xC5; + _mapGameMap[counterX][counterY] -= 0xC5; } } else { if (_currentTileBankImageSetId[0] != 0) continue; - uint8 var4 = _curPlace[counterX * 24 + counterY]; + uint8 var4 = _curPlace[counterX][counterY]; if (var4 >= 1 && var4 <= 0xF) { if (getRandom(100) < 50) - _curPlace[counterX * 24 + counterY] += 0xC5; + _curPlace[counterX][counterY] += 0xC5; } else if (var4 >= 0xC6 && var4 <= 0xD5) { if (getRandom(100) < 50) - _curPlace[counterX * 24 + counterY] -= 0xC5; + _curPlace[counterX][counterY] -= 0xC5; } } } @@ -3106,7 +3109,7 @@ void EfhEngine::sub22AA8(int16 arg0) { if (var2 != 0xFF) var4 = var2; - if (var4 != 0xFFFF) { + if (var4 != -1) { for (int16 counter = 0; counter < 2; ++counter) { if (varA) { displayCenteredString("[DONE]", 128, 303, 117); @@ -3225,9 +3228,9 @@ int8 EfhEngine::sub15581(int16 mapPosX, int16 mapPosY, int16 arg4) { if (_tileFact[imageSetId * 2 + 1] != 0xFF && !_word2C8D5) { if ((arg4 == 1 && _word2C8D7) || (arg4 == 0 && _word2C8D7 && imageSetId != 128 && imageSetId != 121)) { if (_largeMapFlag) { - _mapGameMapPtr[mapPosX * 64 + mapPosY] = _tileFact[imageSetId * 2 + 1]; + _mapGameMap[mapPosX][mapPosY] = _tileFact[imageSetId * 2 + 1]; } else { - _curPlace[mapPosX * 24 + mapPosY] = _tileFact[imageSetId * 2 + 1]; + _curPlace[mapPosX][mapPosY] = _tileFact[imageSetId * 2 + 1]; } _redrawNeededFl = true; @@ -6609,9 +6612,9 @@ void EfhEngine::saveEfhGame() { uint8 EfhEngine::getMapTileInfo(int16 mapPosX, int16 mapPosY) { if (_largeMapFlag) - return _mapGameMapPtr[mapPosX * 64 + mapPosY]; + return _mapGameMap[mapPosX][mapPosY]; - return _curPlace[mapPosX * 24 + mapPosY]; + return _curPlace[mapPosX][mapPosY]; } void EfhEngine::displayNextAnimFrame() { @@ -6650,10 +6653,14 @@ void EfhEngine::setTextPos(int16 textPosX, int16 textPosY) { } void EfhEngine::copyCurrentPlaceToBuffer(int id) { + // Note that 576 = 24 * 24 uint8 *placesPtr = &_places[576 * id]; - // Note that 576 = 24 * 24 - memcpy(_curPlace, placesPtr, 24 * 24); + for (int16 i = 0; i < 24; ++i) { + for (int16 j = 0; j < 24; ++j) { + _curPlace[i][j] = placesPtr[i * 24 + j]; + } + } } } // End of namespace Efh diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 4be294d1e587..e33705d3ca77 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -488,7 +488,7 @@ class EfhEngine : public Engine { uint8 _windowWithBorderBuf[1500]; uint8 _map[7000]; uint8 _places[12000]; - uint8 _curPlace[600]; + uint8 _curPlace[24][24]; NPCStruct _npcBuf[100]; uint8 _imp1[13000]; uint8 _imp2[10000]; @@ -509,7 +509,7 @@ class EfhEngine : public Engine { uint8 *_mapBitmapRef; UnkMapStruct _mapUnknown[100]; MapMonster _mapMonsters[64]; - uint8 *_mapGameMapPtr; + uint8 _mapGameMap[64][64]; uint8 _defaultBoxColor; FontDescr _fontDescr; From b32993001381d5485dc773bba5774d8a7e12f75c Mon Sep 17 00:00:00 2001 From: Strangerke Date: Wed, 29 Dec 2021 14:00:28 +0100 Subject: [PATCH 114/412] EFH: Turn _tileFact into an array of struct, add comments on object types in sub1BC74 --- engines/efh/efh.cpp | 59 ++++++++++++++++++++++++++------------------- engines/efh/efh.h | 11 +++++++-- 2 files changed, 43 insertions(+), 27 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 7cbaa1badaa7..4a79fa492155 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -164,8 +164,11 @@ void Stru32686::init() { } void Stru3244C::init() { - _field0 = 0; - _field2 = 0; + _field0 = _field2 = 0; +} + +void TileFactStruct::init() { + _field0 = _field1 = 0; } EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst), _gameDescription(gd) { @@ -662,7 +665,13 @@ void EfhEngine::loadPlacesFile(uint16 fullPlaceId, bool forceReloadFl) { void EfhEngine::readTileFact() { Common::String fileName = "tilefact"; - readFileToBuffer(fileName, _tileFact); + uint8 tileFactBuff[864]; + readFileToBuffer(fileName, tileFactBuff); + uint8 *curPtr = tileFactBuff; + for (int i = 0; i < 432; ++i) { + _tileFact[i]._field0 = *curPtr++; + _tileFact[i]._field1 = *curPtr++; + } } void EfhEngine::readItems() { @@ -3225,22 +3234,22 @@ int8 EfhEngine::sub15581(int16 mapPosX, int16 mapPosY, int16 arg4) { _word2C880 = false; return -1; } - if (_tileFact[imageSetId * 2 + 1] != 0xFF && !_word2C8D5) { + if (_tileFact[imageSetId]._field1 != 0xFF && !_word2C8D5) { if ((arg4 == 1 && _word2C8D7) || (arg4 == 0 && _word2C8D7 && imageSetId != 128 && imageSetId != 121)) { if (_largeMapFlag) { - _mapGameMap[mapPosX][mapPosY] = _tileFact[imageSetId * 2 + 1]; + _mapGameMap[mapPosX][mapPosY] = _tileFact[imageSetId]._field1; } else { - _curPlace[mapPosX][mapPosY] = _tileFact[imageSetId * 2 + 1]; + _curPlace[mapPosX][mapPosY] = _tileFact[imageSetId]._field1; } _redrawNeededFl = true; - if (_tileFact[imageSetId * 2] == 0) + if (_tileFact[imageSetId]._field0 == 0) return 2; return 1; } } - return _tileFact[imageSetId * 2]; + return _tileFact[imageSetId]._field0; } bool EfhEngine::sub1BC74(int16 monsterId, int16 teamMonsterId) { @@ -5485,7 +5494,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me int16 itemId = _npcBuf[charId]._inventory[objectId]._ref; switch (_items[itemId].field_16 - 1) { - case 0: + case 0: // "Demonic Powers", "MindDomination", "Guilt Trip", "Sleep Grenade", "SleepGrenader" if (argA == 2) { displayString_3("The item emits a low droning hum...", false, charId, windowId, menuId, curMenuLine); } else { @@ -5524,7 +5533,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me varA6 = true; break; - case 1: + case 1: // "Chilling Touch", "Guilt", "Petrify Rod", "Elmer's Gun" if (argA == 2) { displayString_3("The item grows very cold for a moment...", false, charId, windowId, menuId, curMenuLine); } else { @@ -5575,7 +5584,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me varA6 = true; break; - case 4: + case 4: // "Unholy Sinwave", "Holy Water" if (argA == 2) { displayString_3("A dark sense fills your soul...then fades!", false, charId, windowId, menuId, curMenuLine); } else { @@ -5599,7 +5608,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me } varA6 = true; break; - case 5: + case 5: // "Lucifer'sTouch", "Book of Death", "Holy Cross" if (argA == 2) { displayString_3("A dark sense fills your soul...then fades!", false, charId, windowId, menuId, curMenuLine); } else { @@ -5620,7 +5629,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me varA6 = true; break; - case 12: + case 12: // "Terror Gaze", "Servitude Rod", "Despair Ankh", "ConfusionPrism", "Pipe of Peace", "Red Cape", "Peace Symbol", "Hell Badge" if (argA == 2) { displayString_3("There is no apparent affect!", false, charId, windowId, menuId, curMenuLine); } else { @@ -5629,7 +5638,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me } varA6 = true; break; - case 14: { + case 14: { // "Feathered Cap" int16 varAA; if (argA == 2) { displayString_3("Who will use the item?", false, charId, windowId, menuId, curMenuLine); @@ -5653,7 +5662,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me varA6 = true; } break; - case 15: { + case 15: { // "Regal Crown" int16 teamCharId; if (argA == 2) { displayString_3("Who will use the item?", false, charId, windowId, menuId, curMenuLine); @@ -5678,14 +5687,14 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me varA6 = true; } break; - case 16: { + case 16: { // Fairy Dust int16 varAC = _mapPosX; int16 varAA = _mapPosY; _mapPosX = getRandom(_largeMapFlag ? 63 : 23); _mapPosY = getRandom(_largeMapFlag ? 63 : 23); int16 varAE = sub15538(_mapPosX, _mapPosY); - if (_tileFact[2 * varAE] == 0) { + if (_tileFact[varAE]._field0 == 0) { totalPartyKill(); strcpy(buffer1, "The entire party vanishes in a flash... only to appear in stone !"); if (argA == 2) { @@ -5718,11 +5727,11 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me varA6 = true; } break; - case 17: { + case 17: { // "Devil Dust" _mapPosX = _items[itemId].field_19; _mapPosY = _items[itemId].field_1A; int16 varAE = sub15538(_mapPosX, _mapPosY); - if (_tileFact[2 * varAE] == 0) { + if (_tileFact[varAE]._field0 == 0) { totalPartyKill(); strcpy(buffer1, "The entire party vanishes in a flash... only to appear in stone !"); if (argA == 2) { @@ -5773,7 +5782,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me varA6 = true; break; - case 19: + case 19: // "Junk" strcpy(buffer1, " * The item breaks!"); if (argA == 2) { displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); @@ -5783,7 +5792,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me setCharacterObjectToBroken(charId, objectId); varA6 = true; break; - case 23: + case 23: // "Divining Rod" copyString(_items[itemId]._name, buffer2); sprintf(buffer1, "The %s says, '", buffer2); if (_items[itemId].field_19 < _mapPosX) { @@ -5883,7 +5892,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me varA6 = true; } break; - case 26: + case 26: // "Black Sphere" strcpy(buffer1, "The entire party collapses, dead!!!"); if (argA == 2) { displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); @@ -5895,7 +5904,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me // emptyFunction(2); varA6 = true; break; - case 27: { + case 27: { // "Magic Pyramid", "Razor Blade" int16 teamCharId; if (argA == 2) { displayString_3("Who will use the item?", false, charId, windowId, menuId, curMenuLine); @@ -5920,7 +5929,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me varA6 = true; } break; - case 28: + case 28: // "Bugle" if (argA == 2) { displayString_3("The item makes a loud noise!", false, charId, windowId, menuId, curMenuLine); } else { @@ -5938,7 +5947,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me varA6 = true; break; - case 29: { + case 29: { // "Healing Spray", "Healing Elixir", "Curing Potion", "Magic Potion" int16 teamCharId; if (argA == 2) { displayString_3("Who will use the item?", false, charId, windowId, menuId, curMenuLine); diff --git a/engines/efh/efh.h b/engines/efh/efh.h index e33705d3ca77..b01bac7cc800 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -119,7 +119,7 @@ struct ItemStruct { uint8 _defense; uint8 _attacks; uint8 _uses; - uint8 field_13; + int8 field_13; // data contains values from -8 to +8 uint8 _range; uint8 _attackType; uint8 field_16; @@ -232,6 +232,13 @@ struct Stru3244C { void init(); }; +struct TileFactStruct { + uint8 _field0; + uint8 _field1; + + void init(); +}; + class EfhEngine : public Engine { public: EfhEngine(OSystem *syst, const EfhGameDescription *gd); @@ -494,7 +501,7 @@ class EfhEngine : public Engine { uint8 _imp2[10000]; uint8 _titleSong[1024]; ItemStruct _items[300]; - uint8 _tileFact[864]; + TileFactStruct _tileFact[432]; AnimInfo _animInfo[100]; uint8 _history[256]; uint8 _techData[4096]; From 20b099c025535b49146cd88999b32e6472953a2c Mon Sep 17 00:00:00 2001 From: Strangerke Date: Wed, 29 Dec 2021 16:30:02 +0100 Subject: [PATCH 115/412] EFH: Fix loading of _mapGameMap (regression introduced 2 or 3 commits ago) --- engines/efh/efh.cpp | 14 ++++++++++---- engines/efh/efh.h | 2 +- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 4a79fa492155..cc9bb4114f73 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -633,8 +633,8 @@ void EfhEngine::loadTechMapImp(int16 fileId) { readFileToBuffer(fileName, _hiResImageBuf); uncompressBuffer(_hiResImageBuf, _map); // This is not present in the original. - // The purpose is to properly load the mapMonster data in an array of struct in order to use it without being a pain afterwards - loadMapMonsters(); + // The purpose is to properly load the misc map data in arrays in order to use them without being a pain afterwards + loadMapArrays(); loadImageSetToTileBank(1, _mapBitmapRef[0] + 1); loadImageSetToTileBank(2, _mapBitmapRef[1] + 1); @@ -926,7 +926,7 @@ void EfhEngine::initEngine() { uint8 *_mapPtr = &_map[2758]; for (int i = 0; i < 64; ++i) for (int j = 0; j < 64; ++j) - _mapGameMap[i][j] = *_mapPtr++; + _mapGameMap[i][j] = 0; _vgaGraphicsStruct2->copy(_vgaGraphicsStruct1); _vgaGraphicsStruct2->_shiftValue = 0x2000; @@ -1028,7 +1028,7 @@ void EfhEngine::initMapMonsters() { } } -void EfhEngine::loadMapMonsters() { +void EfhEngine::loadMapArrays() { uint8 *_mapUnknownPtr = &_map[2]; for (int i = 0; i < 100; ++i) { @@ -1058,6 +1058,12 @@ void EfhEngine::loadMapMonsters() { for (int j = 0; j < 9; ++j) _mapMonsters[i]._pictureRef[j] = READ_LE_INT16(&mapMonstersPtr[29 * i + 11 + j * 2]); } + + uint8 *mapPtr = &_map[2758]; + for (int i = 0; i < 64; ++i) { + for (int j = 0; j < 64; ++j) + _mapGameMap[i][j] = *mapPtr++; + } } void EfhEngine::saveAnimImageSetId() { diff --git a/engines/efh/efh.h b/engines/efh/efh.h index b01bac7cc800..d36c171e1ebe 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -294,7 +294,7 @@ class EfhEngine : public Engine { void playIntro(); void initEngine(); void initMapMonsters(); - void loadMapMonsters(); + void loadMapArrays(); void saveAnimImageSetId(); int16 getEquipmentDefense(int16 charId, bool flag); uint16 sub1C80A(int16 charId, int field18, bool flag); From d29e4ed7f05730bac4e1d4585cbc15915440a5f9 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Wed, 29 Dec 2021 21:53:46 +0100 Subject: [PATCH 116/412] EFH: Fix unitialized variables in constructor, remove initializations in initEngine() --- engines/efh/efh.cpp | 79 +++++++++++++++------------------------------ 1 file changed, 26 insertions(+), 53 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index cc9bb4114f73..0364f57c135c 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -273,7 +273,7 @@ EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst) _teamMonsterIdArray[i] = -1; _stru32686[i].init(); } - + _unkArray2C8AA[2] = 1; _teamSize = 1; _word2C872 = 0; @@ -304,7 +304,6 @@ EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst) _menuDepth = 0; _word2D0BA = 0; - for (int i = 0; i < 15; ++i) { _word3273A[i] = 0; } @@ -313,6 +312,31 @@ EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst) for (int i = 0; i < 8; ++i) _stru3244C[i].init(); + memset(_bufferCharBM, 0, ARRAYSIZE(_bufferCharBM)); + for (int i = 0; i < 3; ++i) + memset(_tileBank[i], 0, ARRAYSIZE(_tileBank[i])); + memset(_circleImageBuf, 0, ARRAYSIZE(_circleImageBuf)); + memset(_portraitBuf, 0, ARRAYSIZE(_portraitBuf)); + memset(_hiResImageBuf, 0, ARRAYSIZE(_hiResImageBuf)); + memset(_loResImageBuf, 0, ARRAYSIZE(_loResImageBuf)); + memset(_menuBuf, 0, ARRAYSIZE(_menuBuf)); + memset(_windowWithBorderBuf, 0, ARRAYSIZE(_windowWithBorderBuf)); + memset(_map, 0, ARRAYSIZE(_map)); + memset(_places, 0, ARRAYSIZE(_places)); + for (int i = 0; i < 24; ++i) + memset(_curPlace[i], 0, ARRAYSIZE(_curPlace[i])); + memset(_npcBuf, 0, ARRAYSIZE(_npcBuf)); + memset(_imp1, 0, ARRAYSIZE(_imp1)); + memset(_imp2, 0, ARRAYSIZE(_imp2)); + memset(_titleSong, 0, ARRAYSIZE(_titleSong)); + memset(_items, 0, ARRAYSIZE(_items)); + memset(_tileFact, 0, ARRAYSIZE(_tileFact)); + memset(_animInfo, 0, ARRAYSIZE(_animInfo)); + memset(_history, 0, ARRAYSIZE(_history)); + memset(_techData, 0, ARRAYSIZE(_techData)); + memset(_mapMonsters, 0, ARRAYSIZE(_mapMonsters)); + memset(_mapGameMap, 0, ARRAYSIZE(_mapGameMap)); + memset(_imageSetSubFilesArray, 0, ARRAYSIZE(_imageSetSubFilesArray)); } EfhEngine::~EfhEngine() { @@ -872,62 +896,11 @@ Common::String EfhEngine::getSavegameFilename(int slot) { void EfhEngine::initEngine() { _videoMode = 2; // In the original, 2 = VGA/MCGA, EGA = 4, Tandy = 6, cga = 8. - memset(_bufferCharBM, 0, sizeof(_bufferCharBM)); _graphicsStruct = new EfhGraphicsStruct; _graphicsStruct->copy(_vgaGraphicsStruct1); - for (int i = 0; i < 3; ++i) { - memset(_tileBank[i], 0, sizeof(_tileBank[i])); - } - - memset(_circleImageBuf, 0, sizeof(_circleImageBuf)); - memset(_portraitBuf, 0, sizeof(_portraitBuf)); - memset(_hiResImageBuf, 0, sizeof(_hiResImageBuf)); - memset(_loResImageBuf, 0, sizeof(_loResImageBuf)); - memset(_menuBuf, 0, sizeof(_menuBuf)); - memset(_windowWithBorderBuf, 0, sizeof(_windowWithBorderBuf)); - memset(_map, 0, sizeof(_map)); - memset(_places, 0, sizeof(_places)); - memset(_curPlace, 0, sizeof(_curPlace)); - memset(_mapGameMap, 0, sizeof(_mapGameMap)); - memset(_npcBuf, 0, sizeof(_npcBuf)); - memset(_imp1, 0, sizeof(_imp1)); - memset(_imp2, 0, sizeof(_imp2)); - memset(_titleSong, 0, sizeof(_titleSong)); - for (int i = 0; i < 300; ++i) - _items[i].init(); - memset(_tileFact, 0, sizeof(_tileFact)); - - for (int i = 0; i < 100; ++i) - _animInfo[i].init(); - - memset(_history, 0, sizeof(_history)); - memset(_techData, 0, sizeof(_techData)); - _mapBitmapRef = &_map[0]; - // Replaces _mapMonstersPtr which was equal to &_map[902]; - for (int i = 0; i < 64; ++i) { - _mapMonsters[i]._possessivePronounSHL6 = 0; - _mapMonsters[i]._field_1 = 0; - _mapMonsters[i]._guess_fullPlaceId = 0xFF; - _mapMonsters[i]._posX = 0; - _mapMonsters[i]._posY = 0; - _mapMonsters[i]._itemId_Weapon = 0; - _mapMonsters[i]._field_6 = 0; - _mapMonsters[i]._monsterRef = 0; - _mapMonsters[i]._field_8 = 0; - _mapMonsters[i]._field_9 = 0; - _mapMonsters[i]._groupSize = 0; - for (int j = 0; j < 9; ++j) - _mapMonsters[i]._pictureRef[j] = 0; - } - - uint8 *_mapPtr = &_map[2758]; - for (int i = 0; i < 64; ++i) - for (int j = 0; j < 64; ++j) - _mapGameMap[i][j] = 0; - _vgaGraphicsStruct2->copy(_vgaGraphicsStruct1); _vgaGraphicsStruct2->_shiftValue = 0x2000; From c5707c7046027d80ced80700ea426d511e395e71 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sun, 2 Jan 2022 12:47:11 +0100 Subject: [PATCH 117/412] EFH: Put debug traces everywhere --- engines/efh/efh.cpp | 371 +++++++++++++++++++++++++++++++++------ engines/efh/efh.h | 30 ++-- engines/efh/graphics.cpp | 22 +-- engines/efh/utils.cpp | 2 +- 4 files changed, 346 insertions(+), 79 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 0364f57c135c..ad27c79c1606 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -362,7 +362,18 @@ Common::Platform EfhEngine::getPlatform() const { return _platform; } +void EfhEngine::syncSoundSettings() { + Engine::syncSoundSettings(); + + // _sound->syncVolume(); +} + +Common::String EfhEngine::getSavegameFilename(int slot) { + return _targetName + Common::String::format("-%02d.SAV", slot); +} + Common::Error EfhEngine::run() { + debug("run"); s_Engine = this; initialize(); initGraphics(320, 200); @@ -574,6 +585,8 @@ void EfhEngine::initialize() { } void EfhEngine::readAnimInfo() { + debug("readAnimInfo"); + Common::String fileName = "animinfo"; uint8 animInfoBuf[9000]; memset(animInfoBuf, 0, 9000); @@ -599,6 +612,8 @@ void EfhEngine::readAnimInfo() { } void EfhEngine::findMapFile(int16 mapId) { + debug("findMapFile %d", mapId); + if (!_word31E9E) return; @@ -612,7 +627,9 @@ void EfhEngine::findMapFile(int16 mapId) { } void EfhEngine::loadNewPortrait() { - static int16 unkConstRelatedToAnimImageSetId[19] = {0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2}; + debug("loadNewPortrait"); + + static int16 const unkConstRelatedToAnimImageSetId[19] = {0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2}; _unkRelatedToAnimImageSetId = unkConstRelatedToAnimImageSetId[_techId]; if (_currentAnimImageSetId == 200 + _unkRelatedToAnimImageSetId) @@ -625,6 +642,8 @@ void EfhEngine::loadNewPortrait() { } void EfhEngine::loadAnimImageSet() { + debug("loadAnimImageSet"); + if (_currentAnimImageSetId == _animImageSetId || _animImageSetId == 0xFF) return; @@ -638,11 +657,15 @@ void EfhEngine::loadAnimImageSet() { } void EfhEngine::loadHistory() { + debug("loadHistory"); + Common::String fileName = "history"; readFileToBuffer(fileName, _history); } void EfhEngine::loadTechMapImp(int16 fileId) { + debug("loadTechMapImp %d", fileId); + if (fileId == 0xFF) return; @@ -670,6 +693,8 @@ void EfhEngine::loadTechMapImp(int16 fileId) { } void EfhEngine::loadPlacesFile(uint16 fullPlaceId, bool forceReloadFl) { + debug("loadPlacesFile %d %s", fullPlaceId, forceReloadFl ? "True" : "False"); + if (fullPlaceId == 0xFF) return; @@ -688,6 +713,8 @@ void EfhEngine::loadPlacesFile(uint16 fullPlaceId, bool forceReloadFl) { } void EfhEngine::readTileFact() { + debug("readTileFact"); + Common::String fileName = "tilefact"; uint8 tileFactBuff[864]; readFileToBuffer(fileName, tileFactBuff); @@ -699,6 +726,8 @@ void EfhEngine::readTileFact() { } void EfhEngine::readItems() { + debug("readItems"); + Common::String fileName = "items"; uint8 itemBuff[8100]; readFileToBuffer(fileName, itemBuff); @@ -727,6 +756,8 @@ void EfhEngine::readItems() { } void EfhEngine::loadNPCS() { + debug("loadNPCS"); + Common::String fileName = "npcs"; uint8 npcLoading[13400]; readFileToBuffer(fileName, npcLoading); @@ -802,6 +833,8 @@ Common::KeyCode EfhEngine::playSong(uint8 *buffer) { } void EfhEngine::readImpFile(int16 id, bool techMapFl) { + debug("readImpFile %d %s", id, techMapFl ? "True" : "False"); + Common::String fileName = Common::String::format("imp.%d", id); if (techMapFl) @@ -813,6 +846,8 @@ void EfhEngine::readImpFile(int16 id, bool techMapFl) { } void EfhEngine::playIntro() { + debug("playIntro"); + displayRawDataAtPos(_circleImageSubFileArray[0], 0, 0); displayFctFullScreen(); displayRawDataAtPos(_circleImageSubFileArray[0], 0, 0); @@ -884,16 +919,6 @@ void EfhEngine::playIntro() { getLastCharAfterAnimCount(80); } -void EfhEngine::syncSoundSettings() { - Engine::syncSoundSettings(); - -// _sound->syncVolume(); -} - -Common::String EfhEngine::getSavegameFilename(int slot) { - return _targetName + Common::String::format("-%02d.SAV", slot); -} - void EfhEngine::initEngine() { _videoMode = 2; // In the original, 2 = VGA/MCGA, EGA = 4, Tandy = 6, cga = 8. _graphicsStruct = new EfhGraphicsStruct; @@ -973,6 +998,8 @@ void EfhEngine::initEngine() { } void EfhEngine::initMapMonsters() { + debug("initMapMonsters"); + for (uint8 monsterId = 0; monsterId < 64; ++monsterId) { if (_mapMonsters[monsterId]._guess_fullPlaceId == 0xFF) continue; @@ -1002,6 +1029,8 @@ void EfhEngine::initMapMonsters() { } void EfhEngine::loadMapArrays() { + debug("loadMapArrays"); + uint8 *_mapUnknownPtr = &_map[2]; for (int i = 0; i < 100; ++i) { @@ -1040,11 +1069,15 @@ void EfhEngine::loadMapArrays() { } void EfhEngine::saveAnimImageSetId() { + debug("saveAnimImageSetId"); + _oldAnimImageSetId = _animImageSetId; _animImageSetId = 255; } int16 EfhEngine::getEquipmentDefense(int16 charId, bool flag) { + debug("getEquipmentDefense %d %s", charId, flag ? "True" : "False"); + int16 altDef = 0; int16 totalDef = 0; for (int i = 0; i < 10; ++i) { @@ -1071,7 +1104,9 @@ int16 EfhEngine::getEquipmentDefense(int16 charId, bool flag) { return altDef; } -uint16 EfhEngine::sub1C80A(int16 charId, int field18, bool flag) { +uint16 EfhEngine::sub1C80A(int16 charId, int16 field18, bool flag) { + debug("sub1C80A %d %d %s", charId, field18, flag ? "True" : "False"); + for (int i = 0; i < 10; ++i) { if ((_npcBuf[charId]._inventory[i]._stat1 & 0x80) == 0) continue; @@ -1091,6 +1126,8 @@ uint16 EfhEngine::sub1C80A(int16 charId, int field18, bool flag) { } void EfhEngine::sub15150(bool flag) { + debug("sub15150 %s", flag ? "True" : "False"); + uint8 mapTileInfo = getMapTileInfo(_mapPosX, _mapPosY); int16 imageSetId = _currentTileBankImageSetId[mapTileInfo / 72]; @@ -1115,7 +1152,9 @@ void EfhEngine::sub15150(bool flag) { } } -void EfhEngine::drawMap(bool largeMapFl, int16 mapPosX, int16 mapPosY, int mapSize, bool drawHeroFl, bool drawMonstersFl) { +void EfhEngine::drawMap(bool largeMapFl, int16 mapPosX, int16 mapPosY, int16 mapSize, bool drawHeroFl, bool drawMonstersFl) { + debug("drawMap %s %d-%d %d %s %s", largeMapFl ? "True" : "False", mapPosX, mapPosY, mapSize, drawHeroFl ? "True" : "False", drawMonstersFl ? "True" : "False"); + int16 unkPosX = 5; int16 unkPosY = 4; int16 posX = 0; @@ -1209,14 +1248,18 @@ void EfhEngine::drawMap(bool largeMapFl, int16 mapPosX, int16 mapPosY, int mapSi } void EfhEngine::displaySmallMap(int16 posX, int16 posY) { + debugC(6, kDebugEngine, "displaySmallMap %d %d", posX, posY); drawMap(false, posX, posY, 23, _drawHeroOnMapFl, _drawMonstersOnMapFl); } void EfhEngine::displayLargeMap(int16 posX, int16 posY) { + debugC(6, kDebugEngine, "displayLargeMap %d %d", posX, posY); drawMap(true, posX, posY, 63, _drawHeroOnMapFl, _drawMonstersOnMapFl); } void EfhEngine::redrawScreen() { + debug("redrawScreen"); + for (int16 counter = 0; counter < 2; ++counter) { _redrawNeededFl = false; if (!_largeMapFlag) { @@ -1238,6 +1281,8 @@ void EfhEngine::redrawScreen() { } void EfhEngine::displayLowStatusScreen(bool flag) { + debug("displayLowStatusScreen %s", flag ? "True" : "False"); + static char strName[5] = "Name"; static char strDef[4] = "DEF"; static char strHp[3] = "HP"; @@ -1309,6 +1354,8 @@ void EfhEngine::displayLowStatusScreen(bool flag) { } uint8 *EfhEngine::script_readNumberArray(uint8 *srcBuffer, int16 destArraySize, int16 *destArray) { + debug("script_readNumberArray"); + uint8 *buffer = srcBuffer; for (int16 i = 0; i < destArraySize; ++i) { @@ -1319,6 +1366,8 @@ uint8 *EfhEngine::script_readNumberArray(uint8 *srcBuffer, int16 destArraySize, } uint8 *EfhEngine::script_getNumber(uint8 *srcBuffer, int16 *retval) { + debug("script_getNumber"); + uint8 *buffer = srcBuffer; int16 var2 = 0; for (;;) { @@ -1332,12 +1381,15 @@ uint8 *EfhEngine::script_getNumber(uint8 *srcBuffer, int16 *retval) { } void EfhEngine::removeObject(int16 charId, int16 objectId) { + debug("removeObject %d %d", charId, objectId); _npcBuf[charId]._inventory[objectId]._ref = 0x7FFF; _npcBuf[charId]._inventory[objectId]._stat1 = 0; _npcBuf[charId]._inventory[objectId]._stat2 = 0; } void EfhEngine::totalPartyKill() { + debug("totalPartyKill"); + for (int16 counter = 0; counter < 3; ++counter) { if (_teamCharId[counter] != -1) _npcBuf[counter]._hitPoints = 0; @@ -1345,6 +1397,8 @@ void EfhEngine::totalPartyKill() { } void EfhEngine::removeCharacterFromTeam(int16 teamMemberId) { + debug("removeCharacterFromTeam %d", teamMemberId); + int16 charId = _teamCharId[teamMemberId]; _npcBuf[charId].field_12 = _npcBuf[charId].field_B; _npcBuf[charId].field_14 = _npcBuf[charId].field_E; @@ -1364,6 +1418,8 @@ void EfhEngine::removeCharacterFromTeam(int16 teamMemberId) { } void EfhEngine::refreshTeamSize() { + debug("refreshTeamSize"); + _teamSize = 0; for (int16 counter = 0; counter < 3; ++counter) { if (_teamCharId[counter] != -1) @@ -1372,6 +1428,8 @@ void EfhEngine::refreshTeamSize() { } bool EfhEngine::isCharacterATeamMember(int16 id) { + debug("isCharacterATeamMember %d", id); + for (int16 counter = 0; counter < _teamSize; ++counter) { if (_teamCharId[counter] == id) return true; @@ -1381,6 +1439,8 @@ bool EfhEngine::isCharacterATeamMember(int16 id) { } bool EfhEngine::isTPK() { + debug("isTPK"); + int16 zeroedChar = 0; for (int16 counter = 0; counter < _teamSize; ++counter) { if (_npcBuf[_teamCharId[counter]]._hitPoints <= 0) @@ -1391,6 +1451,8 @@ bool EfhEngine::isTPK() { } void EfhEngine::handleWinSequence() { + debugC(1, kDebugEngine, "handleWinSequence"); + saveAnimImageSetId(); findMapFile(18); // clearMemory(); @@ -1411,56 +1473,56 @@ void EfhEngine::handleWinSequence() { } getInput(12); - for (int16 counter2 = 1; counter2 < 8; ++counter2) { + for (int16 animId = 1; animId < 8; ++animId) { for (int16 counter = 0; counter < 2; ++counter) { displayRawDataAtPos(winSeqSubFilesArray1[0], 0, 0); - displayRawDataAtPos(winSeqSubFilesArray2[counter2], 136, 48); + displayRawDataAtPos(winSeqSubFilesArray2[animId], 136, 48); if (counter == 0) displayFctFullScreen(); } getInput(1); } - Common::KeyCode var59 = Common::KEYCODE_INVALID; + Common::KeyCode input = Common::KEYCODE_INVALID; - while(var59 != Common::KEYCODE_ESCAPE) { + while(input != Common::KEYCODE_ESCAPE) { displayRawDataAtPos(winSeqSubFilesArray1[0], 0, 0); displayFctFullScreen(); displayRawDataAtPos(winSeqSubFilesArray1[0], 0, 0); - var59 = getInput(32); - if (var59 != Common::KEYCODE_ESCAPE) { + input = getInput(32); + if (input != Common::KEYCODE_ESCAPE) { displayRawDataAtPos(winSeqSubFilesArray2[10], 136, 72); displayFctFullScreen(); displayRawDataAtPos(winSeqSubFilesArray2[10], 136, 72); - var59 = getInput(1); + input = getInput(1); } - if (var59 != Common::KEYCODE_ESCAPE) { + if (input != Common::KEYCODE_ESCAPE) { displayRawDataAtPos(winSeqSubFilesArray2[11], 136, 72); displayFctFullScreen(); displayRawDataAtPos(winSeqSubFilesArray2[11], 136, 72); - var59 = getInput(1); + input = getInput(1); } - if (var59 != Common::KEYCODE_ESCAPE) { + if (input != Common::KEYCODE_ESCAPE) { displayRawDataAtPos(winSeqSubFilesArray2[12], 136, 72); displayFctFullScreen(); displayRawDataAtPos(winSeqSubFilesArray2[12], 136, 72); - var59 = getInput(1); + input = getInput(1); } - if (var59 != Common::KEYCODE_ESCAPE) { + if (input != Common::KEYCODE_ESCAPE) { displayRawDataAtPos(winSeqSubFilesArray2[13], 136, 72); displayFctFullScreen(); displayRawDataAtPos(winSeqSubFilesArray2[13], 136, 72); - var59 = getInput(1); + input = getInput(1); } - if (var59 != Common::KEYCODE_ESCAPE) { + if (input != Common::KEYCODE_ESCAPE) { displayRawDataAtPos(winSeqSubFilesArray2[14], 136, 72); displayFctFullScreen(); displayRawDataAtPos(winSeqSubFilesArray2[14], 136, 72); - var59 = getInput(1); + input = getInput(1); } } @@ -1470,6 +1532,8 @@ void EfhEngine::handleWinSequence() { } bool EfhEngine::giveItemTo(int16 charId, int16 objectId, int16 altCharId) { + debug("giveItemTo %d %d %d", charId, objectId, altCharId); + for (int16 newObjectId = 0; newObjectId < 10; ++newObjectId) { if (_npcBuf[charId]._inventory[newObjectId]._ref != 0x7FFF) continue; @@ -1491,6 +1555,8 @@ bool EfhEngine::giveItemTo(int16 charId, int16 objectId, int16 altCharId) { } int16 EfhEngine::chooseCharacterToReplace() { + debug("chooseCharacterToReplace"); + Common::KeyCode maxVal = (Common::KeyCode)(Common::KEYCODE_0 + _teamSize); Common::KeyCode input = Common::KEYCODE_INVALID; for (;;) { @@ -1506,6 +1572,8 @@ int16 EfhEngine::chooseCharacterToReplace() { } int16 EfhEngine::handleCharacterJoining() { + debug("handleCharacterJoining"); + static char strReplaceWho[13] = "Replace Who?"; for (int16 counter = 0; counter < 3; ++counter) { if (_teamCharId[counter] == -1) { @@ -1534,7 +1602,9 @@ int16 EfhEngine::handleCharacterJoining() { return 2; } -int16 EfhEngine::script_parse(uint8 *stringBuffer, int16 posX, int16 posY, int16 maxX, int16 maxY, bool flag) { +int16 EfhEngine::script_parse(uint8 *stringBuffer, int16 posX, int16 posY, int16 maxX, int16 maxY, bool flag) { + debug("script_parse %s %d-%d %d-%d %s", (char *) stringBuffer, posX, posY, maxX, maxY, flag ? "True" : "False"); + bool doneFlag = false; int16 var_F2 = -1; int16 var_F0 = 0xFF; @@ -1971,6 +2041,8 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int16 posX, int16 posY, int16 } void EfhEngine::sub133E5(uint8 *srcPtr, int16 posX, int16 posY, int16 maxX, int16 maxY, bool flag) { + debug("sub133E5 %d-%d %d-%d %d", posX, posY, maxX, maxY, flag ? "True" : "False"); + uint16 stringIdx = 0; uint8 *impPtr = srcPtr; memset(_messageToBePrinted, 0, 200); @@ -1996,6 +2068,8 @@ void EfhEngine::sub133E5(uint8 *srcPtr, int16 posX, int16 posY, int16 maxX, int1 } void EfhEngine::sub221FA(uint8 *impArray, bool flag) { + debug("sub221FA %s %s", (char *)impArray, flag ? "True" : "False"); + for (uint8 counter = 0; counter < 2; ++counter) { if (counter == 0 || flag) { drawColoredRect(16, 115, 111, 133, 0); @@ -2011,6 +2085,8 @@ void EfhEngine::sub221FA(uint8 *impArray, bool flag) { } void EfhEngine::sub15A28(int16 arg0, int16 arg2) { + debug("sub15A28 %d %d", arg0, arg2); + _drawHeroOnMapFl = false; int16 varE = arg0 - 11; int16 varC = arg2 - 11; @@ -2043,7 +2119,8 @@ void EfhEngine::sub15A28(int16 arg0, int16 arg2) { } void EfhEngine::sub2455E(int16 arg0, int16 arg2, int16 arg4) { - warning("TODO: sub2455E - check behavior"); + debug("sub2455E %d %d %d", arg0, arg2, arg4); + uint8 varD = kByte2C7D0[arg0]; int16 varC = arg2 - 11; int16 varA = arg4 - 11; @@ -2064,7 +2141,9 @@ void EfhEngine::sub2455E(int16 arg0, int16 arg2, int16 arg4) { } } -int16 EfhEngine::sub1C219(uint8 *str, int menuType, int arg4, bool displayTeamWindowFl) { +int16 EfhEngine::sub1C219(uint8 *str, int16 menuType, int16 arg4, bool displayTeamWindowFl) { + debug("sub1C219 %s %c %c %s", (char *)str, menuType, arg4, displayTeamWindowFl ? "True" : "False"); + int16 varA = 0xFF; int16 minX, maxX, minY, maxY; @@ -2131,6 +2210,8 @@ int16 EfhEngine::sub1C219(uint8 *str, int menuType, int arg4, bool displayTeamWi } int16 EfhEngine::sub151FD(int16 posX, int16 posY) { + debug("sub151FD %d %d", posX, posY); + if (_largeMapFlag) { for (int16 counter = 0; counter < 100; ++counter) { if (_mapUnknown[counter]._field1 == posX && _mapUnknown[counter]._field2 == posY && _mapUnknown[counter]._field0 == 0xFE) @@ -2146,6 +2227,8 @@ int16 EfhEngine::sub151FD(int16 posX, int16 posY) { } bool EfhEngine::isPosOutOfMap(int16 mapPosX, int16 mapPosY) { + debug("isPosOutOfMap %d %d", mapPosX, mapPosY); + int16 maxMapBlocks = _largeMapFlag ? 63 : 23; if (mapPosX == 0 && (mapPosY == 0 || mapPosY == maxMapBlocks)) @@ -2158,6 +2241,8 @@ bool EfhEngine::isPosOutOfMap(int16 mapPosX, int16 mapPosY) { } void EfhEngine::goSouth() { + debug("goSouth"); + if (_largeMapFlag) { if (++_mapPosY > 63) _mapPosY = 63; @@ -2173,6 +2258,8 @@ void EfhEngine::goSouth() { } void EfhEngine::goNorth() { + debug("goNorth"); + if (--_mapPosY < 0) _mapPosY = 0; @@ -2183,6 +2270,8 @@ void EfhEngine::goNorth() { } void EfhEngine::goEast() { + debug("goEast"); + if (_largeMapFlag) { if (++_mapPosX > 63) _mapPosX = 63; @@ -2198,6 +2287,8 @@ void EfhEngine::goEast() { } void EfhEngine::goWest() { + debug("goWest"); + if (--_mapPosX < 0) _mapPosX = 0; @@ -2208,6 +2299,8 @@ void EfhEngine::goWest() { } void EfhEngine::goNorthEast() { + debug("goNorthEast"); + if (--_mapPosY < 0) _mapPosY = 0; @@ -2226,21 +2319,19 @@ void EfhEngine::goNorthEast() { } void EfhEngine::goSouthEast() { + debug("goSouthEast"); + if (_largeMapFlag) { if (++_mapPosX > 63) _mapPosX = 63; - } else { - if (++_mapPosX > 23) - _mapPosX = 23; - } + } else if (++_mapPosX > 23) + _mapPosX = 23; if (_largeMapFlag) { if (++_mapPosY > 63) _mapPosY = 63; - } else { - if (++_mapPosY > 23) - _mapPosY = 23; - } + } else if (++_mapPosY > 23) + _mapPosY = 23; if (isPosOutOfMap(_mapPosX, _mapPosY)) { _mapPosX = _oldMapPosX; @@ -2249,6 +2340,8 @@ void EfhEngine::goSouthEast() { } void EfhEngine::goNorthWest() { + debug("goNorthWest"); + if (--_mapPosY < 0) _mapPosY = 0; @@ -2262,16 +2355,16 @@ void EfhEngine::goNorthWest() { } void EfhEngine::goSouthWest() { + debug("goSouthWest"); + if (--_mapPosX < 0) _mapPosX = 0; if (_largeMapFlag) { if (++_mapPosY > 63) _mapPosY = 63; - } else { - if (++_mapPosY > 23) - _mapPosY = 23; - } + } else if (++_mapPosY > 23) + _mapPosY = 23; if (isPosOutOfMap(_mapPosX, _mapPosY)) { _mapPosX = _oldMapPosX; @@ -2280,6 +2373,8 @@ void EfhEngine::goSouthWest() { } void EfhEngine::handleNewRoundEffects() { + debug("handleNewRoundEffects"); + static int16 regenCounter = 0; if (!_word2C8D7) @@ -2305,6 +2400,8 @@ void EfhEngine::handleNewRoundEffects() { } bool EfhEngine::handleDeathMenu() { + debug("handleDeathMenu"); + displayAnimFrames(20, true); _imageSetSubFilesIdx = 213; redrawScreen(); @@ -2366,6 +2463,8 @@ bool EfhEngine::handleDeathMenu() { } void EfhEngine::computeMapAnimation() { + debug("computeMapAnimation"); + const int16 maxMapBlocks = _largeMapFlag ? 63 : 23; int16 minMapX = _mapPosX - 5; @@ -2414,6 +2513,8 @@ void EfhEngine::computeMapAnimation() { } void EfhEngine::unkFct_anim() { + debug("unkFct_anim"); + setNumLock(); if (_engineInitPending) @@ -2429,6 +2530,8 @@ void EfhEngine::unkFct_anim() { } int8 EfhEngine::sub16B08(int16 monsterId) { + debug("sub16B08 %d", monsterId); + // Simplified version compared to the original int16 maxSize = _largeMapFlag ? 63 : 23; if (_mapMonsters[monsterId]._posX < 0 || _mapMonsters[monsterId]._posY < 0 || _mapMonsters[monsterId]._posX > maxSize || _mapMonsters[monsterId]._posY > maxSize) @@ -2454,6 +2557,8 @@ int8 EfhEngine::sub16B08(int16 monsterId) { } bool EfhEngine::moveMonsterAwayFromTeam(int16 monsterId) { + debug("moveMonsterAwayFromTeam %d", monsterId); + if (_mapMonsters[monsterId]._posX < _mapPosX) { --_mapMonsters[monsterId]._posX; if (_mapMonsters[monsterId]._posY < _mapPosY) @@ -2486,6 +2591,8 @@ bool EfhEngine::moveMonsterAwayFromTeam(int16 monsterId) { } bool EfhEngine::moveMonsterTowardsTeam(int16 monsterId) { + debug("moveMonsterTowardsTeam %d", monsterId); + if (_mapMonsters[monsterId]._posX < _mapPosX) { ++_mapMonsters[monsterId]._posX; if (_mapMonsters[monsterId]._posY < _mapPosY) @@ -2518,7 +2625,8 @@ bool EfhEngine::moveMonsterTowardsTeam(int16 monsterId) { } bool EfhEngine::moveMonsterGroupOther(int16 monsterId, int16 direction) { - + debug("moveMonsterGroupOther %d %d", monsterId, direction); + switch (direction - 1) { case 0: --_mapMonsters[monsterId]._posY; @@ -2554,6 +2662,8 @@ bool EfhEngine::moveMonsterGroupOther(int16 monsterId, int16 direction) { } bool EfhEngine::moveMonsterGroup(int16 monsterId) { + debug("moveMonsterGroup %d", monsterId); + int16 rand100 = getRandom(100); if (rand100 < 30) @@ -2566,7 +2676,9 @@ bool EfhEngine::moveMonsterGroup(int16 monsterId) { return moveMonsterAwayFromTeam(monsterId); } -int16 EfhEngine::computeMonsterGroupDistance(int monsterId) { +int16 EfhEngine::computeMonsterGroupDistance(int16 monsterId) { + debug("computeMonsterGroupDistance %d", monsterId); + int16 monsterPosX = _mapMonsters[monsterId]._posX; int16 monsterPosY = _mapMonsters[monsterId]._posY; @@ -2576,7 +2688,9 @@ int16 EfhEngine::computeMonsterGroupDistance(int monsterId) { return (int16)sqrt(deltaX * deltaX + deltaY * deltaY); } -bool EfhEngine::checkWeaponRange(int16 monsterId, int weaponId) { +bool EfhEngine::checkWeaponRange(int16 monsterId, int16 weaponId) { + debug("checkWeaponRange %d %d", monsterId, weaponId); + static const int16 kRange[5] = {1, 2, 3, 3, 3}; assert(_items[weaponId]._range < 5); @@ -2586,7 +2700,9 @@ bool EfhEngine::checkWeaponRange(int16 monsterId, int weaponId) { return true; } -bool EfhEngine::unkFct_checkMonsterField8(int id, bool teamFlag) { +bool EfhEngine::unkFct_checkMonsterField8(int16 id, bool teamFlag) { + debug("unkFct_checkMonsterField8 %d %s", id, teamFlag ? "True" : "False"); + int16 monsterId = id; if (teamFlag) monsterId = _teamMonsterIdArray[id]; @@ -2604,6 +2720,8 @@ bool EfhEngine::unkFct_checkMonsterField8(int id, bool teamFlag) { } bool EfhEngine::checkTeamWeaponRange(int16 monsterId) { + debug("checkTeamWeaponRange %d", monsterId); + if (!_word2D0BC) return true; @@ -2616,6 +2734,8 @@ bool EfhEngine::checkTeamWeaponRange(int16 monsterId) { } bool EfhEngine::checkIfMonsterOnSameLargelMapPlace(int16 monsterId) { + debug("checkIfMonsterOnSameLargelMapPlace %d", monsterId); + if (_largeMapFlag && _mapMonsters[monsterId]._guess_fullPlaceId == 0xFE) return true; @@ -2626,10 +2746,14 @@ bool EfhEngine::checkIfMonsterOnSameLargelMapPlace(int16 monsterId) { } bool EfhEngine::checkMonsterWeaponRange(int16 monsterId) { + debug("checkMonsterWeaponRange %d", monsterId); + return checkWeaponRange(monsterId, _mapMonsters[monsterId]._itemId_Weapon); } void EfhEngine::sub174A0() { + debug("sub174A0"); + static int16 sub174A0_monsterPosX = -1; static int16 sub174A0_monsterPosY = -1; @@ -2807,6 +2931,8 @@ void EfhEngine::sub174A0() { } bool EfhEngine::checkPictureRefAvailability(int16 monsterId) { + debug("checkPictureRefAvailability %d", monsterId); + if (_mapMonsters[monsterId]._guess_fullPlaceId == 0xFF) return false; @@ -2819,11 +2945,15 @@ bool EfhEngine::checkPictureRefAvailability(int16 monsterId) { } void EfhEngine::displayMonsterAnim(int16 monsterId) { + debug("displayMonsterAnim %d", monsterId); + int16 animId = kEncounters[_mapMonsters[monsterId]._monsterRef]._animId; displayAnimFrames(animId, true); } int16 EfhEngine::countPictureRef(int16 id, bool teamMemberFl) { + debug("countPictureRef %d %s", id, teamMemberFl ? "True" : "False"); + int16 count = 0; int16 monsterId; @@ -2841,6 +2971,8 @@ int16 EfhEngine::countPictureRef(int16 id, bool teamMemberFl) { } bool EfhEngine::checkMonsterGroupDistance1OrLess(int16 monsterId) { + debug("checkMonsterGroupDistance1OrLess %d", monsterId); + if (computeMonsterGroupDistance(monsterId) > 1) return false; @@ -2848,6 +2980,8 @@ bool EfhEngine::checkMonsterGroupDistance1OrLess(int16 monsterId) { } bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { + debug("sub21820 %d %d %d", monsterId, arg2, itemId); + char buffer[80]; memset(buffer, 0, 80); @@ -3011,6 +3145,8 @@ bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { } void EfhEngine::sub221D2(int16 monsterId) { + debug("sub221D2 %d", monsterId); + if (monsterId != -1) { _dword2C856 = nullptr; sub21820(monsterId, 5, -1); @@ -3018,6 +3154,8 @@ void EfhEngine::sub221D2(int16 monsterId) { } void EfhEngine::sub22AA8(int16 arg0) { + debug("sub22AA8 %d", arg0); + int16 var8, varA, varC, varE; var8 = varA = varC = varE = 0; @@ -3121,6 +3259,8 @@ void EfhEngine::sub22AA8(int16 arg0) { } bool EfhEngine::sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemId, int16 arg8, int16 imageSetId) { + debug("sub22293 %d-%d %d %d %d %d", mapPosX, mapPosY, charId, itemId, arg8, imageSetId); + int16 var8 = sub151FD(mapPosX, mapPosY); if (var8 == -1) { @@ -3200,6 +3340,8 @@ bool EfhEngine::sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemI } int8 EfhEngine::sub15581(int16 mapPosX, int16 mapPosY, int16 arg4) { + debug("sub15581 %d-%d %d", mapPosX, mapPosY, arg4); + int16 curTileInfo = getMapTileInfo(mapPosX, mapPosY); int16 imageSetId = _currentTileBankImageSetId[curTileInfo / 72]; imageSetId *= 72; @@ -3232,6 +3374,8 @@ int8 EfhEngine::sub15581(int16 mapPosX, int16 mapPosY, int16 arg4) { } bool EfhEngine::sub1BC74(int16 monsterId, int16 teamMonsterId) { + debug("sub1BC74 %d %d", monsterId, teamMonsterId); + for (int16 counter = 0; counter < teamMonsterId; ++counter) { if (_teamMonsterIdArray[counter] == monsterId) return true; @@ -3240,6 +3384,8 @@ bool EfhEngine::sub1BC74(int16 monsterId, int16 teamMonsterId) { } void EfhEngine::sub1BCA7(int16 monsterTeamId) { + debug("sub1BCA7 %d", monsterTeamId); + int16 counter = 0; if (monsterTeamId != -1 && countPictureRef(monsterTeamId, false)) { counter = 1; @@ -3286,6 +3432,7 @@ void EfhEngine::sub1BCA7(int16 monsterTeamId) { } void EfhEngine::reset_stru32686() { + debug("reset_stru32686"); for (int16 counter1 = 0; counter1 < 5; ++counter1) { for (int16 counter2 = 0; counter2 < 9; ++counter2) { _stru32686[counter1]._field0[counter2] = 0; @@ -3295,17 +3442,22 @@ void EfhEngine::reset_stru32686() { } void EfhEngine::sub1BE89(int16 monsterId) { + debug("sub1BE89 %d", monsterId); sub1BCA7(monsterId); reset_stru32686(); } void EfhEngine::resetTeamMonsterIdArray() { + debug("resetTeamMonsterIdArray"); + for (int i = 0; i < 5; ++i) { _teamMonsterIdArray[i] = -1; } } bool EfhEngine::isTeamMemberStatusNormal(int16 teamMemberId) { + debug("isTeamMemberStatusNormal %d", teamMemberId); + if (_npcBuf[_teamCharId[teamMemberId]]._hitPoints > 0 && _teamCharStatus[teamMemberId]._status == 0) return true; @@ -3313,6 +3465,8 @@ bool EfhEngine::isTeamMemberStatusNormal(int16 teamMemberId) { } void EfhEngine::sub1CDFA() { + debug("sub1CDFA"); + for (int16 counter = 0; counter < 3; ++counter) { if (_teamCharId[counter] != -1 && counter < _teamSize) { _stru3244C[counter]._field0 = counter + 1000; @@ -3345,6 +3499,8 @@ void EfhEngine::sub1CDFA() { } void EfhEngine::redrawScreenForced() { + debug("redrawScreenForced"); + for (int16 counter = 0; counter < 2; ++counter) { redrawScreen(); if (counter == 0) @@ -3353,6 +3509,8 @@ void EfhEngine::redrawScreenForced() { } int16 EfhEngine::selectMonsterGroup() { + debug("selectMonsterGroup"); + int16 retVal = -1; while (retVal == -1) { @@ -3379,6 +3537,8 @@ int16 EfhEngine::selectMonsterGroup() { } int16 EfhEngine::sub1C956(int16 charId, int16 unkFied18Val, int16 arg4) { + debug("sub1C956 %d %d %d", charId, unkFied18Val, arg4); + int16 varE = -1; int16 var6 = sub1C80A(charId, unkFied18Val, true); @@ -3434,6 +3594,8 @@ int16 EfhEngine::sub1C956(int16 charId, int16 unkFied18Val, int16 arg4) { } void EfhEngine::sub1CAB6(int16 charId) { + debug("sub1CAB6 %d", charId); + for (int16 counter = 0; counter < 2; ++counter) { sub15150(false); displayLowStatusScreen(false); @@ -3444,7 +3606,9 @@ void EfhEngine::sub1CAB6(int16 charId) { } bool EfhEngine::sub1CB27() { - int16 var4 = false; + debug("sub1CB27"); + + bool var4 = false; for (int16 counter1 = 0; counter1 < _teamSize; ++counter1) { _teamLastAction[counter1] = 0; if (!isTeamMemberStatusNormal(counter1)) @@ -3549,6 +3713,8 @@ bool EfhEngine::sub1CB27() { // The parameter isn't used in the original void EfhEngine::sub1BE9A(int16 monsterId) { + debug("sub1BE9A %d", monsterId); + int16 var4 = 1; // sub1BE9A - 1rst loop counter1_monsterId - Start @@ -3645,6 +3811,8 @@ void EfhEngine::sub1BE9A(int16 monsterId) { } int16 EfhEngine::getTeamMonsterAnimId() { + debug("getTeamMonsterAnimId"); + int16 retVal = 0xFF; for (int16 counter = 0; counter < 5; ++counter) { int16 monsterId = _teamMonsterIdArray[counter]; @@ -3665,6 +3833,8 @@ int16 EfhEngine::getTeamMonsterAnimId() { } int16 EfhEngine::sub1BAF9(int16 monsterGroup) { + debug("sub1BAF9 %d", monsterGroup); + int16 var2 = 0; for (int16 counter = 0; counter < 9; ++counter) { if (isMonsterActive(monsterGroup, counter)) @@ -3675,6 +3845,8 @@ int16 EfhEngine::sub1BAF9(int16 monsterGroup) { } void EfhEngine::sub1C4CA(bool whiteFl) { + debug("sub1C4CA %s", whiteFl ? "True" : "False"); + int16 textPosY = 20; for (int16 counter = 0; counter < 5; ++counter) { if (_teamMonsterIdArray[counter] == -1) @@ -3736,6 +3908,8 @@ void EfhEngine::sub1C4CA(bool whiteFl) { } void EfhEngine::displayCombatMenu(int16 charId) { + debug("displayCombatMenu %d", charId); + char buffer[80]; copyString(_npcBuf[charId]._name, buffer); strcat(buffer, ":"); @@ -3769,6 +3943,8 @@ void EfhEngine::displayCombatMenu(int16 charId) { } void EfhEngine::drawCombatScreen(int16 charId, bool whiteFl, bool forceDrawFl) { + debug("drawCombatScreen %d %s %s", charId, whiteFl ? "True" : "False", forceDrawFl ? "True" : "False"); + for (int16 counter = 0; counter < 2; ++counter) { if (counter == 0 || forceDrawFl) { drawMapWindow(); @@ -3787,6 +3963,8 @@ void EfhEngine::drawCombatScreen(int16 charId, bool whiteFl, bool forceDrawFl) { } void EfhEngine::handleFight_checkEndEffect(int16 charId) { + debug("handleFight_checkEndEffect %d", charId); + // In the original, this function is part of handleFight. // It has been split for readability purposes. if (_teamCharStatus[charId]._status == 0) @@ -3823,6 +4001,8 @@ void EfhEngine::handleFight_checkEndEffect(int16 charId) { } int16 EfhEngine::sub1DEC8(int16 groupNumber) { + debug("sub1DEC8 %d", groupNumber); + int16 var4 = -1; int16 monsterId = _teamMonsterIdArray[groupNumber]; @@ -3851,6 +4031,8 @@ int16 EfhEngine::sub1DEC8(int16 groupNumber) { } int16 EfhEngine::getCharacterScore(int16 charId, int16 itemId) { + debug("getCharacterScore %d %d", charId, itemId); + int16 totalScore = 0; switch (_items[itemId]._range) { case 0: @@ -3934,6 +4116,8 @@ int16 EfhEngine::getCharacterScore(int16 charId, int16 itemId) { } bool EfhEngine::checkSpecialItemsOnCurrentPlace(int16 itemId) { + debug("checkSpecialItemsOnCurrentPlace %d", itemId); + switch(_techData[_techDataId_MapPosX * 64 + _techDataId_MapPosY]) { case 1: if ((itemId < 0x58 || itemId > 0x68) && (itemId < 0x86 || itemId > 0x89) && (itemId < 0x74 || itemId > 0x76) && (itemId != 0x8C)) @@ -3995,6 +4179,8 @@ void EfhEngine::genericGenerateSound(int16 soundType, int16 repeatCount) { } bool EfhEngine::hasAdequateDefense(int16 monsterId, uint8 attackType) { + debug("hasAdequateDefense %d %d", monsterId, attackType); + int16 itemId = _mapMonsters[monsterId]._itemId_Weapon; if (_items[itemId].field_16 != 0) @@ -4004,6 +4190,8 @@ bool EfhEngine::hasAdequateDefense(int16 monsterId, uint8 attackType) { } bool EfhEngine::hasAdequateDefense_2(int16 charId, uint8 attackType) { + debug("hasAdequateDefense_2 %d %d", charId, attackType); + int16 itemId = _npcBuf[charId]._unkItemId; if (_items[itemId].field_16 == 0 && _items[itemId].field17_attackTypeDefense == attackType) @@ -4021,6 +4209,8 @@ bool EfhEngine::hasAdequateDefense_2(int16 charId, uint8 attackType) { } void EfhEngine::getDeathTypeDescription(int16 attackerId, int16 victimId) { + debug("getDeathTypeDescription %d %d", attackerId, victimId); + int16 possessivePronoun; if (attackerId > 999) { @@ -4244,6 +4434,8 @@ void EfhEngine::getDeathTypeDescription(int16 attackerId, int16 victimId) { } bool EfhEngine::characterSearchesMonsterCorpse(int16 charId, int16 monsterId) { + debug("characterSearchesMonsterCorpse %d %d", charId, monsterId); + int16 rndVal = getRandom(100); if (kEncounters[_mapMonsters[monsterId]._monsterRef]._dropOccurrencePct < rndVal) return false; @@ -4265,6 +4457,8 @@ bool EfhEngine::characterSearchesMonsterCorpse(int16 charId, int16 monsterId) { } void EfhEngine::getXPAndSearchCorpse(int16 charId, char *namePt1, char *namePt2, int16 monsterId) { + debug("getXPAndSearchCorpse %d %s%s %d", charId, namePt1, namePt2, monsterId); + int16 xpLevel = getXPLevel(_npcBuf[charId]._xp); _npcBuf[charId]._xp += kEncounters[_mapMonsters[monsterId]._monsterRef]._xpGiven; char buffer[80]; @@ -4287,6 +4481,8 @@ void EfhEngine::getXPAndSearchCorpse(int16 charId, char *namePt1, char *namePt2, } void EfhEngine::addReactionText(int16 id) { + debug("addReactionText %d", id); + int16 rand3 = getRandom(3); char buffer[80]; memset(buffer, 0, 80); @@ -4405,6 +4601,8 @@ void EfhEngine::addReactionText(int16 id) { } void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { + debug("handleFight_lastAction_A %d", teamCharId); + // In the original, this function is part of handleFight. // It has been split for readability purposes. @@ -4628,6 +4826,8 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { } void EfhEngine::handleFight_lastAction_D(int16 teamCharId) { + debug("handleFight_lastAction_D %d", teamCharId); + _word32482[teamCharId] -= 40; copyString(_npcBuf[_teamCharId[teamCharId]]._name, _enemyNamePt2); int16 var70 = _npcBuf[_teamCharId[teamCharId]]._possessivePronounSHL6 >> 6; @@ -4642,6 +4842,8 @@ void EfhEngine::handleFight_lastAction_D(int16 teamCharId) { } void EfhEngine::handleFight_lastAction_H(int16 teamCharId) { + debug("handleFight_lastAction_H %d", teamCharId); + // In the original, this function is part of handleFight. // It has been split for readability purposes. @@ -4659,6 +4861,8 @@ void EfhEngine::handleFight_lastAction_H(int16 teamCharId) { } void EfhEngine::handleFight_lastAction_U(int16 teamCharId) { + debug("handleFight_lastAction_U %d", teamCharId); + // In the original, this function is part of handleFight. // It has been split for readability purposes. int16 unk_monsterField5_itemId = _npcBuf[_teamCharId[teamCharId]]._inventory[_word31780[teamCharId]]._ref; @@ -4675,6 +4879,8 @@ void EfhEngine::handleFight_lastAction_U(int16 teamCharId) { } char EfhEngine::getFightMessageLastCharacter(char *message) { + debug("getFightMessageLastCharacter %s", message); + char *ptr = message; if (ptr == nullptr || *ptr == 0) @@ -4689,6 +4895,8 @@ char EfhEngine::getFightMessageLastCharacter(char *message) { } void EfhEngine::sub1D8C2(int16 charId, int16 damage) { + debug("sub1D8C2 %d %d", charId, damage); + int16 var42 = 0; int16 var40 = _npcBuf[charId]._possessivePronounSHL6 / 64; char buffer[40]; @@ -4737,6 +4945,8 @@ void EfhEngine::sub1D8C2(int16 charId, int16 damage) { } bool EfhEngine::handleFight(int16 monsterId) { + debug("handleFight %d", monsterId); + int16 var8C = 0; sub1BE89(monsterId); @@ -5042,7 +5252,9 @@ bool EfhEngine::handleFight(int16 monsterId) { return true; } -void EfhEngine::displayMenuItemString(int16 menuBoxId, int thisBoxId, int minX, int maxX, int minY, const char *str) { +void EfhEngine::displayMenuItemString(int16 menuBoxId, int16 thisBoxId, int16 minX, int16 maxX, int16 minY, const char *str) { + debug("displayMenuItemString %d %d %d->%d %d %s", menuBoxId, thisBoxId, minX, maxX, minY, str); + char buffer[20]; memset(buffer, 0, 20); @@ -5066,6 +5278,8 @@ void EfhEngine::displayMenuItemString(int16 menuBoxId, int thisBoxId, int minX, } void EfhEngine::displayStatusMenu(int16 windowId) { + debug("displayStatusMenu %d", windowId); + for (int16 counter = 0; counter < 9; ++counter) { drawColoredRect(80, 39 + 14 * counter, 134, 47 + 14 * counter, 0); } @@ -5087,6 +5301,8 @@ void EfhEngine::displayStatusMenu(int16 windowId) { } void EfhEngine::countRightWindowItems(int16 menuId, int16 charId) { + debug("countRightWindowItems %d %d", menuId, charId); + int16 var2 = 0; int16 var4 = 0; _word2D0BA = 0; @@ -5134,6 +5350,8 @@ void EfhEngine::countRightWindowItems(int16 menuId, int16 charId) { } int16 EfhEngine::getXPLevel(int32 xp) { + debug("getXPLevel %ld", xp); + int16 level = 0; int16 var6 = 1500; @@ -5153,6 +5371,8 @@ int16 EfhEngine::getXPLevel(int32 xp) { } void EfhEngine::displayCharacterSummary(int16 curMenuLine, int16 npcId) { + debug("displayCharacterSummary %d %d", curMenuLine, npcId); + char buffer1[40]; char buffer2[40]; memset(buffer1, 0, 40); @@ -5252,6 +5472,8 @@ void EfhEngine::displayCharacterSummary(int16 curMenuLine, int16 npcId) { } void EfhEngine::displayCharacterInformationOrSkills(int16 curMenuLine, int16 charId) { + debug("displayCharacterInformationOrSkills %d %d", curMenuLine, charId); + char buffer[40]; memset(buffer, 0, 40); @@ -5290,6 +5512,8 @@ void EfhEngine::displayCharacterInformationOrSkills(int16 curMenuLine, int16 cha } void EfhEngine::displayStatusMenuActions(int16 menuId, int16 curMenuLine, int16 npcId) { + debug("displayStatusMenuActions %d %d %d", menuId, curMenuLine, npcId); + drawColoredRect(144, 15, 310, 184, 0); displayCenteredString("(ESCape Aborts)", 144, 310, 175); _textColor = 0x0E; @@ -5335,6 +5559,8 @@ void EfhEngine::displayStatusMenuActions(int16 menuId, int16 curMenuLine, int16 } void EfhEngine::unk_StatusMenu(int16 windowId, int16 menuId, int16 curMenuLine, int16 charId, bool unusedFl, bool refreshFl) { + debug("unk_StatusMenu %d %d %d %d %s", windowId, menuId, curMenuLine, charId, refreshFl ? "True" : "False"); + displayStatusMenu(windowId); countRightWindowItems(menuId, charId); @@ -5345,6 +5571,8 @@ void EfhEngine::unk_StatusMenu(int16 windowId, int16 menuId, int16 curMenuLine, } void EfhEngine::sub18E80(int16 charId, int16 windowId, int16 menuId, int16 curMenuLine) { + debug("sub18E80 %d %d %d %d", charId, windowId, menuId, curMenuLine); + for (int counter = 0; counter < 2; ++counter) { displayWindow(_menuBuf, 0, 0, _hiResImageBuf); unk_StatusMenu(windowId, menuId, curMenuLine, charId, true, false); @@ -5355,6 +5583,8 @@ void EfhEngine::sub18E80(int16 charId, int16 windowId, int16 menuId, int16 curMe } int16 EfhEngine::displayString_3(const char *str, bool animFl, int16 charId, int16 windowId, int16 menuId, int16 curMenuLine) { + debug("displayString_3 % %s %d %d %d %d", str, animFl ? "True" : "False", charId, windowId, menuId, curMenuLine); + int16 retVal = 0; for (int16 counter = 0; counter < 2; ++counter) { @@ -5378,20 +5608,25 @@ int16 EfhEngine::displayString_3(const char *str, bool animFl, int16 charId, int } bool EfhEngine::isItemCursed(int16 itemId) { + debugC(6, kDebugEngine, "isItemCursed %d", itemId); + if (_items[itemId].field_16 == 21 || _items[itemId].field_16 == 22 || _items[itemId].field_16 == 23) return true; return false; } -bool EfhEngine::hasObjectEquipped(int16 charId, int16 _objectId) { - if ((_npcBuf[charId]._inventory[_objectId]._stat1 & 0x80) == 0) +bool EfhEngine::hasObjectEquipped(int16 charId, int16 objectId) { + debug("hasObjectEquipped %d %d", charId, objectId); + if ((_npcBuf[charId]._inventory[objectId]._stat1 & 0x80) == 0) return false; return true; } void EfhEngine::equipCursedItem(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine) { + debug("equipCursedItem %d %d %d %d %d", charId, objectId, windowId, menuId, curMenuLine); + int16 itemId = _npcBuf[charId]._inventory[objectId]._ref; if (isItemCursed(itemId)) { @@ -5403,6 +5638,8 @@ void EfhEngine::equipCursedItem(int16 charId, int16 objectId, int16 windowId, in } void EfhEngine::sub191FF(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine) { + debug("sub191FF %d %d %d %d %d", charId, objectId, windowId, menuId, curMenuLine); + int16 itemId = _npcBuf[charId]._inventory[objectId]._ref; if (hasObjectEquipped(charId, objectId)) { @@ -5421,6 +5658,8 @@ void EfhEngine::sub191FF(int16 charId, int16 objectId, int16 windowId, int16 men } void EfhEngine::sub1E028(int16 id, uint8 mask, int16 groupFl) { + debug("sub1E028 %d 0x%X %d", id, mask, groupFl); + int16 monsterId; if (groupFl) { monsterId = _teamMonsterIdArray[id]; @@ -5433,12 +5672,16 @@ void EfhEngine::sub1E028(int16 id, uint8 mask, int16 groupFl) { } bool EfhEngine::isMonsterActive(int16 groupId, int16 id) { + debug("isMonsterActive %d %d", groupId, id); + if (_mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[id] > 0 && _stru32686[groupId]._field0[id] == 0) return true; return false; } int16 EfhEngine::sub15538(int16 mapPosX, int16 mapPosY) { + debug("sub15538 %d-%d", mapPosX, mapPosY); + int16 mapTileInfo = getMapTileInfo(mapPosX, mapPosY); int16 imageSetId = mapTileInfo / 72; @@ -5446,10 +5689,14 @@ int16 EfhEngine::sub15538(int16 mapPosX, int16 mapPosY) { } void EfhEngine::setCharacterObjectToBroken(int16 charId, int16 objectId) { + debug("setCharacterObjectToBroken %d %d", charId, objectId); + _npcBuf[charId]._inventory[objectId]._ref = 0x7FFF; } int16 EfhEngine::selectOtherCharFromTeam() { + debug("selectOtherCharFromTeam"); + Common::KeyCode maxVal = (Common::KeyCode) (Common::KEYCODE_0 + _teamSize); Common::KeyCode input = Common::KEYCODE_INVALID; for (;;) { @@ -5465,6 +5712,8 @@ int16 EfhEngine::selectOtherCharFromTeam() { } int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine, int16 argA) { + debug("sub19E2E %d %d %d %d %d %d", charId, objectId, windowId, menuId, curMenuLine, argA); + char buffer1[80]; char buffer2[80]; @@ -6034,6 +6283,8 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me } int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { + debug("handleStatusMenu %d %d", gameMode, charId); + int16 menuId = 9; int16 var16 = -1; int16 windowId = -1; @@ -6395,6 +6646,8 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { } bool EfhEngine::sub16E14() { + debug("sub16E14"); + int16 var68 = 0; char dest[20]; char buffer[80]; @@ -6512,6 +6765,8 @@ bool EfhEngine::sub16E14() { } void EfhEngine::loadImageSetToTileBank(int16 tileBankId, int16 imageSetId) { + debug("loadImageSetToTileBank %d %d", tileBankId, imageSetId); + // TODO: all the values of titleBankId and imageSetId are hardcoded. When all the calls are implemented, fix the values to avoid to have to decrease them int16 bankId = tileBankId - 1; int16 setId = imageSetId - 1; @@ -6542,6 +6797,8 @@ void EfhEngine::checkProtection() { } void EfhEngine::loadEfhGame() { + debug("loadEfhGame"); + // The original used a loop to check for the presence of the savegame on the current floppy. // When the savegame wasn't found, it was displaying a screen asking for Disk 1 and was setting a flag used // to call a function after loading right before returning. @@ -6599,6 +6856,8 @@ void EfhEngine::saveEfhGame() { } uint8 EfhEngine::getMapTileInfo(int16 mapPosX, int16 mapPosY) { + debug("getMapTileInfo %d-%d", mapPosX, mapPosY); + if (_largeMapFlag) return _mapGameMap[mapPosX][mapPosY]; @@ -6606,6 +6865,8 @@ uint8 EfhEngine::getMapTileInfo(int16 mapPosX, int16 mapPosY) { } void EfhEngine::displayNextAnimFrame() { + debug("displayNextAnimFrame"); + if (++_unkAnimRelatedIndex >= 15) _unkAnimRelatedIndex = 0; @@ -6617,6 +6878,8 @@ void EfhEngine::writeTechAndMapFiles() { } uint16 EfhEngine::getStringWidth(const char *buffer) { + debug("getStringWidth %s", buffer); + uint16 retVal = 0; for (;;) { @@ -6636,11 +6899,15 @@ uint16 EfhEngine::getStringWidth(const char *buffer) { } void EfhEngine::setTextPos(int16 textPosX, int16 textPosY) { + debugC(6, kDebugEngine, "setTextPos %d-%d", textPosX, textPosY); + _textPosX = textPosX; _textPosY = textPosY; } -void EfhEngine::copyCurrentPlaceToBuffer(int id) { +void EfhEngine::copyCurrentPlaceToBuffer(int16 id) { + debug("copyCurrentPlaceToBuffer %d", id); + // Note that 576 = 24 * 24 uint8 *placesPtr = &_places[576 * id]; diff --git a/engines/efh/efh.h b/engines/efh/efh.h index d36c171e1ebe..4374f04d2239 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -297,21 +297,21 @@ class EfhEngine : public Engine { void loadMapArrays(); void saveAnimImageSetId(); int16 getEquipmentDefense(int16 charId, bool flag); - uint16 sub1C80A(int16 charId, int field18, bool flag); + uint16 sub1C80A(int16 charId, int16 field18, bool flag); void displayLowStatusScreen(bool flag); void loadImageSetToTileBank(int16 tileBankId, int16 imageSetId); void restoreAnimImageSetId(); void checkProtection(); void loadEfhGame(); void saveEfhGame(); - void copyCurrentPlaceToBuffer(int id); + void copyCurrentPlaceToBuffer(int16 id); uint8 getMapTileInfo(int16 mapPosX, int16 mapPosY); void displayNextAnimFrame(); void writeTechAndMapFiles(); uint16 getStringWidth(const char *buffer); void setTextPos(int16 textPosX, int16 textPosY); void sub15150(bool flag); - void drawMap(bool largeMapFl, int16 mapPosX, int16 mapPosY, int mapSize, bool drawHeroFl, bool drawMonstersFl); + void drawMap(bool largeMapFl, int16 mapPosX, int16 mapPosY, int16 mapSize, bool drawHeroFl, bool drawMonstersFl); void displaySmallMap(int16 posX, int16 posY); void displayLargeMap(int16 posX, int16 posY); void redrawScreen(); @@ -332,7 +332,7 @@ class EfhEngine : public Engine { void sub221FA(uint8 *impArray, bool flag); void sub15A28(int16 arg0, int16 arg2); void sub2455E(int16 arg0, int16 arg1, int16 arg2); - int16 sub1C219(uint8 *str, int menuType, int arg4, bool displayTeamWindowFl); + int16 sub1C219(uint8 *str, int16 menuType, int16 arg4, bool displayTeamWindowFl); int16 sub151FD(int16 posX, int16 posY); bool isPosOutOfMap(int16 mapPosX, int16 mapPosY); void goSouth(); @@ -352,9 +352,9 @@ class EfhEngine : public Engine { bool moveMonsterTowardsTeam(int16 monsterId); bool moveMonsterGroupOther(int16 monsterId, int16 direction); bool moveMonsterGroup(int16 monsterId); - int16 computeMonsterGroupDistance(int monsterId); - bool checkWeaponRange(int16 monsterId, int weaponId); - bool unkFct_checkMonsterField8(int id, bool teamFlag); + int16 computeMonsterGroupDistance(int16 monsterId); + bool checkWeaponRange(int16 monsterId, int16 weaponId); + bool unkFct_checkMonsterField8(int16 id, bool teamFlag); bool checkTeamWeaponRange(int16 monsterId); bool checkIfMonsterOnSameLargelMapPlace(int16 monsterId); bool checkMonsterWeaponRange(int16 monsterId); @@ -405,7 +405,7 @@ class EfhEngine : public Engine { char getFightMessageLastCharacter(char *message); void sub1D8C2(int16 charId, int16 damage); bool handleFight(int16 monsterId); - void displayMenuItemString(int16 menuBoxId, int thisBoxId, int minX, int maxX, int minY, const char *str); + void displayMenuItemString(int16 menuBoxId, int16 thisBoxId, int16 minX, int16 maxX, int16 minY, const char *str); void displayStatusMenu(int16 windowId); void countRightWindowItems(int16 menuId, int16 charId); int16 getXPLevel(int32 xp); @@ -416,7 +416,7 @@ class EfhEngine : public Engine { void sub18E80(int16 charId, int16 windowId, int16 menuId, int16 curMenuLine); int16 displayString_3(const char *str, bool animFl, int16 charId, int16 windowId, int16 menuId, int16 curMenuLine); bool isItemCursed(int16 itemId); - bool hasObjectEquipped(int16 charId, int16 _objectId); + bool hasObjectEquipped(int16 charId, int16 objectId); void equipCursedItem(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine); void sub191FF(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine); void sub1E028(int16 id, uint8 mask, int16 groupFl); @@ -437,19 +437,19 @@ class EfhEngine : public Engine { void copyDirtyRect(int16 minX, int16 minY, int16 maxX, int16 maxY); void copyGraphicBufferFromTo(EfhGraphicsStruct *efh_graphics_struct, EfhGraphicsStruct *efh_graphics_struct1, const Common::Rect &rect, int16 min_x, int16 min_y); void displayBufferBmAtPos(BufferBM *bufferBM, int16 posX, int16 posY); - void drawRect(int minX, int minY, int maxX, int maxY); - void drawColoredRect(int minX, int minY, int maxX, int maxY, int color); - void clearScreen(int color); + void drawRect(int16 minX, int16 minY, int16 maxX, int16 maxY); + void drawColoredRect(int16 minX, int16 minY, int16 maxX, int16 maxY, int16 color); + void clearScreen(int16 color); void displayRawDataAtPos(uint8 *imagePtr, int16 posX, int16 posY); void drawString(const char *str, int16 startX, int16 startY, uint16 unkFl); void displayCenteredString(const char *str, int16 minX, int16 maxX, int16 posY); - void displayMenuAnswerString(const char *str, int16 minX, int16 maxX, int posY); + void displayMenuAnswerString(const char *str, int16 minX, int16 maxX, int16 posY); void drawMapWindow(); void displayGameScreen(); void drawUpperLeftBorders(); void drawUpperRightBorders(); void drawBottomBorders(); - void drawChar(uint8 curChar, int16 posX, int posY); + void drawChar(uint8 curChar, int16 posX, int16 posY); void setTextColorWhite(); void setTextColorRed(); void setTextColorGrey(); @@ -465,7 +465,7 @@ class EfhEngine : public Engine { int32 readFileToBuffer(Common::String &filename, uint8 *destBuffer); void setDefaultNoteDuration(); void decryptImpFile(bool techMapFl); - void loadImageSet(int imageSetId, uint8 *buffer, uint8 **subFilesArray, uint8 *destBuffer); + void loadImageSet(int16 imageSetId, uint8 *buffer, uint8 **subFilesArray, uint8 *destBuffer); void rImageFile(Common::String filename, uint8 *targetBuffer, uint8 **subFilesArray, uint8 *packedBuffer); uint32 uncompressBuffer(uint8 *compressedBuf, uint8 *destBuf); int16 getRandom(int16 maxVal); diff --git a/engines/efh/graphics.cpp b/engines/efh/graphics.cpp index 19fdfe4b66d0..2bb1a426fe28 100644 --- a/engines/efh/graphics.cpp +++ b/engines/efh/graphics.cpp @@ -138,8 +138,8 @@ void EfhEngine::displayBufferBmAtPos(BufferBM *bufferBM, int16 posX, int16 posY) // _system->updateScreen(); } -void EfhEngine::drawRect(int minX, int minY, int maxX, int maxY) { - debugC(1, kDebugGraphics, "drawRect %d %d %d %d", minX, minY, maxX, maxY); +void EfhEngine::drawRect(int16 minX, int16 minY, int16 maxX, int16 maxY) { + debugC(1, kDebugGraphics, "drawRect %d-%d %d-%d", minX, minY, maxX, maxY); if (minY > maxY) SWAP(minY, maxY); @@ -147,10 +147,10 @@ void EfhEngine::drawRect(int minX, int minY, int maxX, int maxY) { if (minX > maxX) SWAP(minX, maxX); - minX = CLIP(minX, 0, 319); - maxX = CLIP(maxX, 0, 319); - minY = CLIP(minY, 0, 199); - maxY = CLIP(maxY, 0, 199); + minX = CLIP(minX, 0, 319); + maxX = CLIP(maxX, 0, 319); + minY = CLIP(minY, 0, 199); + maxY = CLIP(maxY, 0, 199); int deltaY = 1 + maxY - minY; int deltaX = 1 + maxX - minX; @@ -169,8 +169,8 @@ void EfhEngine::drawRect(int minX, int minY, int maxX, int maxY) { } } -void EfhEngine::drawColoredRect(int minX, int minY, int maxX, int maxY, int color) { - debugC(1, kDebugGraphics, "drawColoredRect %d %d %d %d %d", minX, minY, maxX, maxY, color); +void EfhEngine::drawColoredRect(int16 minX, int16 minY, int16 maxX, int16 maxY, int16 color) { + debugC(1, kDebugGraphics, "drawColoredRect %d-%d %d-%d %d", minX, minY, maxX, maxY, color); uint8 oldValue = _defaultBoxColor; _defaultBoxColor = color; @@ -178,7 +178,7 @@ void EfhEngine::drawColoredRect(int minX, int minY, int maxX, int maxY, int colo _defaultBoxColor = oldValue; } -void EfhEngine::clearScreen(int color) { +void EfhEngine::clearScreen(int16 color) { debugC(1, kDebugGraphics, "clearScreen %d", color); drawColoredRect(0, 0, 320, 200, color); } @@ -242,7 +242,7 @@ void EfhEngine::displayCenteredString(const char *str, int16 minX, int16 maxX, i drawString(str, startCenteredDisplayX, posY, _textColor); } -void EfhEngine::displayMenuAnswerString(const char *str, int16 minX, int16 maxX, int posY) { +void EfhEngine::displayMenuAnswerString(const char *str, int16 minX, int16 maxX, int16 posY) { debugC(1, kDebugGraphics, "displayMenuAnswerString %s %d-%d %d", str, minX, maxX, posY); displayCenteredString(str, minX, maxX, posY); displayFctFullScreen(); @@ -285,7 +285,7 @@ void EfhEngine::drawBottomBorders() { displayRawDataAtPos(_circleImageSubFileArray[6], 304, 136); } -void EfhEngine::drawChar(uint8 curChar, int16 posX, int posY) { +void EfhEngine::drawChar(uint8 curChar, int16 posX, int16 posY) { debugC(1, kDebugGraphics, "drawChar %c %d %d", curChar, posX, posY); // CHECKME: Quick hacked display, may require rework diff --git a/engines/efh/utils.cpp b/engines/efh/utils.cpp index 54941c938a5e..5f6393a4b99e 100644 --- a/engines/efh/utils.cpp +++ b/engines/efh/utils.cpp @@ -85,7 +85,7 @@ void EfhEngine::decryptImpFile(bool techMapFl) { dump.close(); } -void EfhEngine::loadImageSet(int imageSetId, uint8 *buffer, uint8 **subFilesArray, uint8 *destBuffer) { +void EfhEngine::loadImageSet(int16 imageSetId, uint8 *buffer, uint8 **subFilesArray, uint8 *destBuffer) { debugC(1, kDebugUtils, "loadImageSet %d", imageSetId); Common::String fileName = Common::String::format("imageset.%d", imageSetId); rImageFile(fileName, buffer, subFilesArray, destBuffer); From 902e1f06f2a8939f88fbe215045ee6d25c19b3da Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sun, 2 Jan 2022 23:18:18 +0100 Subject: [PATCH 118/412] EFH: Fix an issue in displayAnimFrame, small refactoring, add some debug traces --- engines/efh/efh.cpp | 34 ++++++++++++++++++++++------------ engines/efh/efh.h | 5 +---- engines/efh/graphics.cpp | 4 ++-- 3 files changed, 25 insertions(+), 18 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index ad27c79c1606..8bbf3431a0ae 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -70,7 +70,7 @@ void UnkMapStruct::init() { } void UnkAnimStruct::init() { - field0 = field1 = field2 = field3 = 0; + memset(_field, 0, 4); } void AnimInfo::init() { @@ -206,7 +206,7 @@ EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst) _word31E9E = false; _oldAnimImageSetId = -1; - _animImageSetId = 254; + _animImageSetId = 0xFE; _paletteTransformationConstant = 10; for (int i = 0; i < 12; ++i) @@ -585,29 +585,39 @@ void EfhEngine::initialize() { } void EfhEngine::readAnimInfo() { - debug("readAnimInfo"); + debugC(6, kDebugEngine, "readAnimInfo"); Common::String fileName = "animinfo"; uint8 animInfoBuf[9000]; memset(animInfoBuf, 0, 9000); uint8 *curPtr = animInfoBuf; - + readFileToBuffer(fileName, animInfoBuf); for (int i = 0; i < 100; ++i) { for (int id = 0; id < 15; ++id) { - _animInfo[i]._unkAnimArray[id].field0 = *curPtr++; - _animInfo[i]._unkAnimArray[id].field1 = *curPtr++; - _animInfo[i]._unkAnimArray[id].field2 = *curPtr++; - _animInfo[i]._unkAnimArray[id].field3 = *curPtr++; + _animInfo[i]._unkAnimArray[id]._field[0] = *curPtr++; + _animInfo[i]._unkAnimArray[id]._field[1] = *curPtr++; + _animInfo[i]._unkAnimArray[id]._field[2] = *curPtr++; + _animInfo[i]._unkAnimArray[id]._field[3] = *curPtr++; + + debugC(6, kDebugEngine, "%d %d %d %d", _animInfo[i]._unkAnimArray[id]._field[0], _animInfo[i]._unkAnimArray[id]._field[1], _animInfo[i]._unkAnimArray[id]._field[2], _animInfo[i]._unkAnimArray[id]._field[3]); } - for (int id = 0; id < 10; ++id) + Common::String debugStr = ""; + for (int id = 0; id < 10; ++id) { _animInfo[i]._field3C_startY[id] = *curPtr++; + debugStr += Common::String::format("%d ", _animInfo[i]._field3C_startY[id]); + } + debugC(6, kDebugEngine, "%s", debugStr.c_str()); + debugStr = ""; for (int id = 0; id < 10; ++id) { _animInfo[i]._field46_startX[id] = READ_LE_INT16(curPtr); curPtr += 2; + debugStr += Common::String::format("%d ", _animInfo[i]._field46_startX[id]); } + debugC(6, kDebugEngine, "%s", debugStr.c_str()); + debugC(6, kDebugEngine, "---------"); } } @@ -1069,10 +1079,10 @@ void EfhEngine::loadMapArrays() { } void EfhEngine::saveAnimImageSetId() { - debug("saveAnimImageSetId"); + debugC(6, kDebugEngine, "saveAnimImageSetId"); _oldAnimImageSetId = _animImageSetId; - _animImageSetId = 255; + _animImageSetId = 0xFF; } int16 EfhEngine::getEquipmentDefense(int16 charId, bool flag) { @@ -6765,7 +6775,7 @@ bool EfhEngine::sub16E14() { } void EfhEngine::loadImageSetToTileBank(int16 tileBankId, int16 imageSetId) { - debug("loadImageSetToTileBank %d %d", tileBankId, imageSetId); + debugC(3, kDebugEngine, "loadImageSetToTileBank %d %d", tileBankId, imageSetId); // TODO: all the values of titleBankId and imageSetId are hardcoded. When all the calls are implemented, fix the values to avoid to have to decrease them int16 bankId = tileBankId - 1; diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 4374f04d2239..cdeddbc228ac 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -98,10 +98,7 @@ struct UnkMapStruct { }; struct UnkAnimStruct { - uint8 field0; - uint8 field1; - uint8 field2; - uint8 field3; + int8 _field[4]; void init(); }; diff --git a/engines/efh/graphics.cpp b/engines/efh/graphics.cpp index 2bb1a426fe28..9566d95ffb8e 100644 --- a/engines/efh/graphics.cpp +++ b/engines/efh/graphics.cpp @@ -71,8 +71,8 @@ void EfhEngine::displayAnimFrame() { displayRawDataAtPos(_portraitSubFilesArray[0], 16, 8); for (int i = 0; i < 4; ++i) { - int16 var2 = _animInfo[_animImageSetId]._unkAnimArray[_unkAnimRelatedIndex].field0; - if (var2 == 0xFF) + int8 var2 = _animInfo[_animImageSetId]._unkAnimArray[_unkAnimRelatedIndex]._field[i]; + if (var2 == -1) continue; displayRawDataAtPos(_portraitSubFilesArray[var2 + 1], _animInfo[_animImageSetId]._field46_startX[var2] + 16, _animInfo[_animImageSetId]._field3C_startY[var2] + 8); } From 11c5a8989117d6e4774c263324903c635e742cbe Mon Sep 17 00:00:00 2001 From: Strangerke Date: Mon, 3 Jan 2022 23:49:38 +0100 Subject: [PATCH 119/412] EFH: Fix delay, fix a kind of collision --- engines/efh/efh.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 8bbf3431a0ae..c867b6760ec6 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -401,7 +401,7 @@ Common::Error EfhEngine::run() { _system->delayMillis(20); uint32 newMs = _system->getMillis(); - if (newMs - lastMs >= 200) { + if (newMs - lastMs >= 220) { lastMs = newMs; unkFct_anim(); } @@ -527,7 +527,7 @@ Common::Error EfhEngine::run() { if ((_mapPosX != _oldMapPosX || _mapPosY != _oldMapPosY) && !_shouldQuit) { int16 var4 = sub16E14(); - if (!_word2C8D5 || var4 != 0) { + if (_word2C8D5 != 0 || var4 != 0) { _oldMapPosX = _mapPosX; _oldMapPosY = _mapPosY; _oldImageSetSubFilesIdx = _imageSetSubFilesIdx; From f9471c12ed0e1c4851cffd543454540488ff431f Mon Sep 17 00:00:00 2001 From: Strangerke Date: Tue, 4 Jan 2022 08:39:04 +0100 Subject: [PATCH 120/412] EFH: Some renaming --- engines/efh/efh.cpp | 14 +++++++------- engines/efh/efh.h | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index c867b6760ec6..a8885219aefa 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -298,7 +298,7 @@ EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst) _word2C87A = false; _unk_sub26437_flag = 0; _word2C8D9 = false; - _word2C8D5 = false; + _dbgForceMonsterBlock = false; _word2D0BC = false; _word2C8D2 = false; _menuDepth = 0; @@ -526,8 +526,8 @@ Common::Error EfhEngine::run() { } if ((_mapPosX != _oldMapPosX || _mapPosY != _oldMapPosY) && !_shouldQuit) { - int16 var4 = sub16E14(); - if (_word2C8D5 != 0 || var4 != 0) { + bool collisionFl = checkMonsterCollision(); + if (_dbgForceMonsterBlock || collisionFl) { _oldMapPosX = _mapPosX; _oldMapPosY = _mapPosY; _oldImageSetSubFilesIdx = _imageSetSubFilesIdx; @@ -3365,7 +3365,7 @@ int8 EfhEngine::sub15581(int16 mapPosX, int16 mapPosY, int16 arg4) { _word2C880 = false; return -1; } - if (_tileFact[imageSetId]._field1 != 0xFF && !_word2C8D5) { + if (_tileFact[imageSetId]._field1 != 0xFF && !_dbgForceMonsterBlock) { if ((arg4 == 1 && _word2C8D7) || (arg4 == 0 && _word2C8D7 && imageSetId != 128 && imageSetId != 121)) { if (_largeMapFlag) { _mapGameMap[mapPosX][mapPosY] = _tileFact[imageSetId]._field1; @@ -6655,8 +6655,8 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { return 0; } -bool EfhEngine::sub16E14() { - debug("sub16E14"); +bool EfhEngine::checkMonsterCollision() { + debug("checkMonsterCollision"); int16 var68 = 0; char dest[20]; @@ -6760,7 +6760,7 @@ bool EfhEngine::sub16E14() { var68 = true; break; default: -// warning("STUB: sub16E14 - Missing mapping ?"); +// warning("STUB: checkMonsterCollision - Missing mapping ?"); break; } } while (!var68); diff --git a/engines/efh/efh.h b/engines/efh/efh.h index cdeddbc228ac..3bfbf0e7a7d8 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -423,7 +423,7 @@ class EfhEngine : public Engine { int16 selectOtherCharFromTeam(); int16 sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine, int16 argA); int16 handleStatusMenu(int16 gameMode, int16 charId); - bool sub16E14(); + bool checkMonsterCollision(); // Graphics void initPalette(); @@ -571,7 +571,7 @@ class EfhEngine : public Engine { uint16 _word2C86E; uint8 *_dword2C856; bool _word2C8D9; - bool _word2C8D5; // CHECKME: always 0? + bool _dbgForceMonsterBlock; // Original debug flag? Always false. bool _word2D0BC; bool _word2C8D2; int16 _menuDepth; From 2435653bc8d7afbde49d2a93efa5a933417db55b Mon Sep 17 00:00:00 2001 From: Strangerke Date: Thu, 6 Jan 2022 08:38:07 +0100 Subject: [PATCH 121/412] EFH: Some renaming, improve some comments --- engines/efh/efh.cpp | 77 +++++++++++++++++++++++---------------------- engines/efh/efh.h | 8 ++--- 2 files changed, 43 insertions(+), 42 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index a8885219aefa..56534ef0d791 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -288,8 +288,8 @@ EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst) _textPosY = 0; _lastMainPlaceId = 0; - _word2C86E = 0; - _dword2C856 = nullptr; + _tempTextDelay = 0; + _tempTextPtr = nullptr; _word2C880 = false; _redrawNeededFl = false; _word2C8D7 = true; @@ -453,7 +453,7 @@ Common::Error EfhEngine::run() { case Common::KEYCODE_F1: if (_teamCharId[0] != -1) { handleStatusMenu(1, _teamCharId[0]); - _dword2C856 = nullptr; + _tempTextPtr = nullptr; sub15150(true); _redrawNeededFl = true; } @@ -461,7 +461,7 @@ Common::Error EfhEngine::run() { case Common::KEYCODE_F2: if (_teamCharId[1] != -1) { handleStatusMenu(1, _teamCharId[1]); - _dword2C856 = nullptr; + _tempTextPtr = nullptr; sub15150(true); _redrawNeededFl = true; } @@ -469,7 +469,7 @@ Common::Error EfhEngine::run() { case Common::KEYCODE_F3: if (_teamCharId[2] != -1) { handleStatusMenu(1, _teamCharId[2]); - _dword2C856 = nullptr; + _tempTextPtr = nullptr; sub15150(true); _redrawNeededFl = true; } @@ -558,9 +558,9 @@ Common::Error EfhEngine::run() { if (!_shouldQuit) { handleNewRoundEffects(); - if (_word2C86E > 0) { - if (--_word2C86E == 0) { - sub221FA(nullptr, true); + if (_tempTextDelay > 0) { + if (--_tempTextDelay == 0) { + displayMiddleLeftTempText(nullptr, true); } } } @@ -871,10 +871,10 @@ void EfhEngine::playIntro() { // With GF on the bed displayRawDataAtPos(_circleImageSubFileArray[0], 0, 144); - sub133E5(_imp2PtrArray[0], 6, 150, 268, 186, false); + drawText(_imp2PtrArray[0], 6, 150, 268, 186, false); displayFctFullScreen(); displayRawDataAtPos(_circleImageSubFileArray[0], 0, 144); - sub133E5(_imp2PtrArray[0], 6, 150, 268, 186, false); + drawText(_imp2PtrArray[0], 6, 150, 268, 186, false); lastInput = getLastCharAfterAnimCount(80); if (lastInput == Common::KEYCODE_ESCAPE) return; @@ -882,11 +882,11 @@ void EfhEngine::playIntro() { // Poof displayRawDataAtPos(_circleImageSubFileArray[1], 110, 16); displayRawDataAtPos(_circleImageSubFileArray[0], 0, 144); - sub133E5(_imp2PtrArray[1], 6, 150, 268, 186, false); + drawText(_imp2PtrArray[1], 6, 150, 268, 186, false); displayFctFullScreen(); displayRawDataAtPos(_circleImageSubFileArray[1], 110, 16); displayRawDataAtPos(_circleImageSubFileArray[0], 0, 144); - sub133E5(_imp2PtrArray[1], 6, 150, 268, 186, false); + drawText(_imp2PtrArray[1], 6, 150, 268, 186, false); lastInput = getLastCharAfterAnimCount(80); if (lastInput == Common::KEYCODE_ESCAPE) return; @@ -894,38 +894,38 @@ void EfhEngine::playIntro() { // On the phone displayRawDataAtPos(_circleImageSubFileArray[2], 110, 16); displayRawDataAtPos(_circleImageSubFileArray[0], 0, 144); - sub133E5(_imp2PtrArray[2], 6, 150, 268, 186, false); + drawText(_imp2PtrArray[2], 6, 150, 268, 186, false); displayFctFullScreen(); displayRawDataAtPos(_circleImageSubFileArray[2], 110, 16); displayRawDataAtPos(_circleImageSubFileArray[0], 0, 144); - sub133E5(_imp2PtrArray[2], 6, 150, 268, 186, false); + drawText(_imp2PtrArray[2], 6, 150, 268, 186, false); lastInput = getLastCharAfterAnimCount(80); if (lastInput == Common::KEYCODE_ESCAPE) return; displayRawDataAtPos(_circleImageSubFileArray[0], 0, 144); - sub133E5(_imp2PtrArray[3], 6, 150, 268, 186, false); + drawText(_imp2PtrArray[3], 6, 150, 268, 186, false); displayFctFullScreen(); displayRawDataAtPos(_circleImageSubFileArray[0], 0, 144); - sub133E5(_imp2PtrArray[3], 6, 150, 268, 186, false); + drawText(_imp2PtrArray[3], 6, 150, 268, 186, false); lastInput = getLastCharAfterAnimCount(80); if (lastInput == Common::KEYCODE_ESCAPE) return; displayRawDataAtPos(_circleImageSubFileArray[0], 0, 144); - sub133E5(_imp2PtrArray[4], 6, 150, 268, 186, false); + drawText(_imp2PtrArray[4], 6, 150, 268, 186, false); displayFctFullScreen(); displayRawDataAtPos(_circleImageSubFileArray[0], 0, 144); - sub133E5(_imp2PtrArray[4], 6, 150, 268, 186, false); + drawText(_imp2PtrArray[4], 6, 150, 268, 186, false); lastInput = getLastCharAfterAnimCount(80); if (lastInput == Common::KEYCODE_ESCAPE) return; displayRawDataAtPos(_circleImageSubFileArray[0], 0, 144); - sub133E5(_imp2PtrArray[5], 6, 150, 268, 186, false); + drawText(_imp2PtrArray[5], 6, 150, 268, 186, false); displayFctFullScreen(); displayRawDataAtPos(_circleImageSubFileArray[0], 0, 144); - sub133E5(_imp2PtrArray[5], 6, 150, 268, 186, false); + drawText(_imp2PtrArray[5], 6, 150, 268, 186, false); getLastCharAfterAnimCount(80); } @@ -1147,12 +1147,12 @@ void EfhEngine::sub15150(bool flag) { for (int counter = 0; counter < 2; ++counter) { if (counter == 0 || flag) { displayGameScreen(); - // TODO: _word2C86E is some kind of counter - if (_word2C86E != 0) { - // TODO: _dword2C856 is most likely an "Imp" Array + // Redraw temp text if one is displayed currently + // _tempTextDelay determines whether a temp text is displayed in the middle-left zone + if (_tempTextDelay != 0) { // Note: the original was doing the check in the opposite order, which looks really suspicious - if ((_dword2C856 != nullptr) && (_dword2C856[0] != 0x30)) { - sub221FA(_dword2C856, false); + if ((_tempTextPtr != nullptr) && (_tempTextPtr[0] != 0x30)) { + displayMiddleLeftTempText(_tempTextPtr, false); } } } @@ -2050,8 +2050,8 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int16 posX, int16 posY, int16 return var_F0; } -void EfhEngine::sub133E5(uint8 *srcPtr, int16 posX, int16 posY, int16 maxX, int16 maxY, bool flag) { - debug("sub133E5 %d-%d %d-%d %d", posX, posY, maxX, maxY, flag ? "True" : "False"); +void EfhEngine::drawText(uint8 *srcPtr, int16 posX, int16 posY, int16 maxX, int16 maxY, bool flag) { + debug("drawText %d-%d %d-%d %d", posX, posY, maxX, maxY, flag ? "True" : "False"); uint16 stringIdx = 0; uint8 *impPtr = srcPtr; @@ -2077,16 +2077,17 @@ void EfhEngine::sub133E5(uint8 *srcPtr, int16 posX, int16 posY, int16 maxX, int1 script_parse(_messageToBePrinted, posX, posY, maxX, maxY, flag); } -void EfhEngine::sub221FA(uint8 *impArray, bool flag) { - debug("sub221FA %s %s", (char *)impArray, flag ? "True" : "False"); +void EfhEngine::displayMiddleLeftTempText(uint8 *impArray, bool flag) { + debugC(3, kDebugEngine, "displayMiddleLeftTempText %s %s", (char *)impArray, flag ? "True" : "False"); for (uint8 counter = 0; counter < 2; ++counter) { if (counter == 0 || flag) { + // clear middle-left text area drawColoredRect(16, 115, 111, 133, 0); if (impArray != nullptr) { - _word2C86E = 4; - _dword2C856 = impArray; - sub133E5(impArray, 17, 115, 110, 133, false); + _tempTextDelay = 4; + _tempTextPtr = impArray; + drawText(impArray, 17, 115, 110, 133, false); } if (counter == 0 && flag) displayFctFullScreen(); @@ -3158,7 +3159,7 @@ void EfhEngine::sub221D2(int16 monsterId) { debug("sub221D2 %d", monsterId); if (monsterId != -1) { - _dword2C856 = nullptr; + _tempTextPtr = nullptr; sub21820(monsterId, 5, -1); } } @@ -3170,9 +3171,9 @@ void EfhEngine::sub22AA8(int16 arg0) { var8 = varA = varC = varE = 0; if (arg0 <= 0xFE) { - if (_dword2C856) { - _dword2C856 = nullptr; - sub221FA(_dword2C856, true); + if (_tempTextPtr) { + _tempTextPtr = nullptr; + displayMiddleLeftTempText(_tempTextPtr, true); } if (_word2C8D2) sub15150(true); @@ -3275,7 +3276,7 @@ bool EfhEngine::sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemI if (var8 == -1) { if (imageSetId != -1 && *_imp2PtrArray[imageSetId] != 0x30) - sub221FA(_imp2PtrArray[imageSetId], true); + displayMiddleLeftTempText(_imp2PtrArray[imageSetId], true); } else if (var8 == 0) { if (_mapUnknown[var8]._field3 == 0xFF) { sub22AA8(_mapUnknown[var8]._field5); // word! @@ -6752,7 +6753,7 @@ bool EfhEngine::checkMonsterCollision() { case Common::KEYCODE_s: // Status var6A = handleStatusMenu(1, _teamCharId[0]); var68 = true; - _dword2C856 = nullptr; + _tempTextPtr = nullptr; sub15150(true); break; case Common::KEYCODE_t: // Talk diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 3bfbf0e7a7d8..3662a7ceabd6 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -325,8 +325,8 @@ class EfhEngine : public Engine { int16 chooseCharacterToReplace(); int16 handleCharacterJoining(); int16 script_parse(uint8 *str, int16 posX, int16 posY, int16 maxX, int16 maxY, bool flag); - void sub133E5(uint8 *impPtr, int16 posX, int16 posY, int16 maxX, int16 maxY, bool flag); - void sub221FA(uint8 *impArray, bool flag); + void drawText(uint8 *impPtr, int16 posX, int16 posY, int16 maxX, int16 maxY, bool flag); + void displayMiddleLeftTempText(uint8 *impArray, bool flag); void sub15A28(int16 arg0, int16 arg2); void sub2455E(int16 arg0, int16 arg1, int16 arg2); int16 sub1C219(uint8 *str, int16 menuType, int16 arg4, bool displayTeamWindowFl); @@ -568,8 +568,8 @@ class EfhEngine : public Engine { int16 _techDataId_MapPosX, _techDataId_MapPosY; uint16 _lastMainPlaceId; - uint16 _word2C86E; - uint8 *_dword2C856; + uint16 _tempTextDelay; + uint8 *_tempTextPtr; bool _word2C8D9; bool _dbgForceMonsterBlock; // Original debug flag? Always false. bool _word2D0BC; From 6796634043eeb44dfdcfc5ca7217e641866c415b Mon Sep 17 00:00:00 2001 From: Strangerke Date: Fri, 7 Jan 2022 08:38:56 +0100 Subject: [PATCH 122/412] EFH: more renaming --- engines/efh/efh.cpp | 76 +++++++++++++++++++++++---------------------- engines/efh/efh.h | 10 +++--- 2 files changed, 44 insertions(+), 42 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 56534ef0d791..0c9b92d57b01 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -297,10 +297,10 @@ EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst) _drawMonstersOnMapFl = true; _word2C87A = false; _unk_sub26437_flag = 0; - _word2C8D9 = false; + _dbgForceDisplayUpperRightBorder = false; _dbgForceMonsterBlock = false; _word2D0BC = false; - _word2C8D2 = false; + _statusMenuActive = false; _menuDepth = 0; _word2D0BA = 0; @@ -389,8 +389,8 @@ Common::Error EfhEngine::run() { */ initEngine(); - sub15150(true); - redrawScreen(); + drawGameScreenAndTempText(true); + drawScreen(); displayLowStatusScreen(true); if (!_protectionPassed) @@ -454,7 +454,7 @@ Common::Error EfhEngine::run() { if (_teamCharId[0] != -1) { handleStatusMenu(1, _teamCharId[0]); _tempTextPtr = nullptr; - sub15150(true); + drawGameScreenAndTempText(true); _redrawNeededFl = true; } break; @@ -462,7 +462,7 @@ Common::Error EfhEngine::run() { if (_teamCharId[1] != -1) { handleStatusMenu(1, _teamCharId[1]); _tempTextPtr = nullptr; - sub15150(true); + drawGameScreenAndTempText(true); _redrawNeededFl = true; } break; @@ -470,7 +470,7 @@ Common::Error EfhEngine::run() { if (_teamCharId[2] != -1) { handleStatusMenu(1, _teamCharId[2]); _tempTextPtr = nullptr; - sub15150(true); + drawGameScreenAndTempText(true); _redrawNeededFl = true; } break; @@ -551,7 +551,7 @@ Common::Error EfhEngine::run() { } if (_redrawNeededFl && !_shouldQuit) { - redrawScreen(); + drawScreen(); displayLowStatusScreen(true); } @@ -1135,14 +1135,16 @@ uint16 EfhEngine::sub1C80A(int16 charId, int16 field18, bool flag) { return 0x7FFF; } -void EfhEngine::sub15150(bool flag) { - debug("sub15150 %s", flag ? "True" : "False"); +void EfhEngine::drawGameScreenAndTempText(bool flag) { + debugC(2, kDebugEngine, "drawGameScreenAndTempText %s", flag ? "True" : "False"); + #if 0 + // This code is present in the original, but looks strictly useless. uint8 mapTileInfo = getMapTileInfo(_mapPosX, _mapPosY); int16 imageSetId = _currentTileBankImageSetId[mapTileInfo / 72]; int16 mapImageSetId = (imageSetId * 72) + (mapTileInfo % 72); - // CHECKME : Why do we compute this Id if we don't use it? + #endif for (int counter = 0; counter < 2; ++counter) { if (counter == 0 || flag) { @@ -1267,8 +1269,8 @@ void EfhEngine::displayLargeMap(int16 posX, int16 posY) { drawMap(true, posX, posY, 63, _drawHeroOnMapFl, _drawMonstersOnMapFl); } -void EfhEngine::redrawScreen() { - debug("redrawScreen"); +void EfhEngine::drawScreen() { + debug("drawScreen"); for (int16 counter = 0; counter < 2; ++counter) { _redrawNeededFl = false; @@ -1276,13 +1278,13 @@ void EfhEngine::redrawScreen() { if (_fullPlaceId != 0xFF) displaySmallMap(_mapPosX, _mapPosY); - if (_word2C8D9) + if (_dbgForceDisplayUpperRightBorder) drawUpperRightBorders(); } else { if (_techId != 0xFF) displayLargeMap(_mapPosX, _mapPosY); - if (_word2C8D9) + if (_dbgForceDisplayUpperRightBorder) drawUpperRightBorders(); } if (counter == 0) @@ -2113,7 +2115,7 @@ void EfhEngine::sub15A28(int16 arg0, int16 arg2) { int16 var2 = var8 + varC; _mapGameMap[var4][var2] = _curPlace[counter][var8]; } - redrawScreen(); + drawScreen(); } for (int16 counter = 1; counter <= 23; counter += 2) { @@ -2122,7 +2124,7 @@ void EfhEngine::sub15A28(int16 arg0, int16 arg2) { int16 var2 = var8 + varC; _mapGameMap[var4][var2] = _curPlace[counter][var8]; } - redrawScreen(); + drawScreen(); } getLastCharAfterAnimCount(3); @@ -2415,7 +2417,7 @@ bool EfhEngine::handleDeathMenu() { displayAnimFrames(20, true); _imageSetSubFilesIdx = 213; - redrawScreen(); + drawScreen(); for (int16 counter = 0; counter < 2; ++counter) { clearBottomTextZone(0); @@ -3175,8 +3177,8 @@ void EfhEngine::sub22AA8(int16 arg0) { _tempTextPtr = nullptr; displayMiddleLeftTempText(_tempTextPtr, true); } - if (_word2C8D2) - sub15150(true); + if (_statusMenuActive) + drawGameScreenAndTempText(true); int16 var4 = arg0; @@ -3513,7 +3515,7 @@ void EfhEngine::redrawScreenForced() { debug("redrawScreenForced"); for (int16 counter = 0; counter < 2; ++counter) { - redrawScreen(); + drawScreen(); if (counter == 0) displayFctFullScreen(); } @@ -3608,7 +3610,7 @@ void EfhEngine::sub1CAB6(int16 charId) { debug("sub1CAB6 %d", charId); for (int16 counter = 0; counter < 2; ++counter) { - sub15150(false); + drawGameScreenAndTempText(false); displayLowStatusScreen(false); drawCombatScreen(charId, false, false); if (counter == 0) @@ -6305,7 +6307,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { saveAnimImageSetId(); - _word2C8D2 = true; + _statusMenuActive = true; _menuDepth = 0; sub18E80(charId, windowId, menuId, curMenuLine); @@ -6467,7 +6469,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { sub191FF(charId, objectId, windowId, menuId, curMenuLine); if (gameMode == 2) { restoreAnimImageSetId(); - _word2C8D2 = false; + _statusMenuActive = false; return 0x7D00; } break; @@ -6476,11 +6478,11 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { itemId = _npcBuf[charId]._inventory[objectId]._ref; if (gameMode == 2) { restoreAnimImageSetId(); - _word2C8D2 = false; + _statusMenuActive = false; return objectId; } else { if (sub22293(_mapPosX, _mapPosY, charId, itemId, 2, -1)) { - _word2C8D2 = false; + _statusMenuActive = false; return -1; } else { sub19E2E(charId, objectId, windowId, menuId, curMenuLine, 2); @@ -6505,7 +6507,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { removeObject(charId, objectId); int16 var8 = sub22293(_mapPosX, _mapPosY, charId, itemId, 3, -1); if (var8 != 0) { - _word2C8D2 = false; + _statusMenuActive = false; return -1; } } @@ -6562,7 +6564,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { removeObject(charId, objectId); if (gameMode == 2) { restoreAnimImageSetId(); - _word2C8D2 = false; + _statusMenuActive = false; return 0x7D00; } } @@ -6586,13 +6588,13 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { removeObject(charId, objectId); if (gameMode == 2) { restoreAnimImageSetId(); - _word2C8D2 = false; + _statusMenuActive = false; return 0x7D00; } bool var8 = sub22293(_mapPosX, _mapPosY, charId, itemId, 1, -1); if (var8) { - _word2C8D2 = false; + _statusMenuActive = false; return -1; } } @@ -6605,7 +6607,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { } else { bool var8 = sub22293(_mapPosX, _mapPosY, charId, objectId, 4, -1); if (var8) { - _word2C8D2 = false; + _statusMenuActive = false; return -1; } } @@ -6617,7 +6619,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { } else { bool var8 = sub22293(_mapPosX, _mapPosY, charId, objectId, 4, -1); if (var8) { - _word2C8D2 = false; + _statusMenuActive = false; return -1; } } @@ -6629,7 +6631,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { } else { bool var8 = sub22293(_mapPosX, _mapPosY, charId, objectId, 4, -1); if (var8) { - _word2C8D2 = false; + _statusMenuActive = false; return -1; } } @@ -6648,7 +6650,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { if (menuId == 8) { restoreAnimImageSetId(); - _word2C8D2 = false; + _statusMenuActive = false; return 0x7FFF; } } @@ -6754,7 +6756,7 @@ bool EfhEngine::checkMonsterCollision() { var6A = handleStatusMenu(1, _teamCharId[0]); var68 = true; _tempTextPtr = nullptr; - sub15150(true); + drawGameScreenAndTempText(true); break; case Common::KEYCODE_t: // Talk sub221D2(monsterId); @@ -6804,7 +6806,7 @@ void EfhEngine::checkProtection() { //CHECKME : Well, yeah, some code may be missing there. Who knows. _protectionPassed = true; - sub15150(true); + drawGameScreenAndTempText(true); } void EfhEngine::loadEfhGame() { @@ -6867,7 +6869,7 @@ void EfhEngine::saveEfhGame() { } uint8 EfhEngine::getMapTileInfo(int16 mapPosX, int16 mapPosY) { - debug("getMapTileInfo %d-%d", mapPosX, mapPosY); + debugC(3, kDebugEngine, "getMapTileInfo %d-%d", mapPosX, mapPosY); if (_largeMapFlag) return _mapGameMap[mapPosX][mapPosY]; diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 3662a7ceabd6..5aaa306973b5 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -307,11 +307,11 @@ class EfhEngine : public Engine { void writeTechAndMapFiles(); uint16 getStringWidth(const char *buffer); void setTextPos(int16 textPosX, int16 textPosY); - void sub15150(bool flag); + void drawGameScreenAndTempText(bool flag); void drawMap(bool largeMapFl, int16 mapPosX, int16 mapPosY, int16 mapSize, bool drawHeroFl, bool drawMonstersFl); void displaySmallMap(int16 posX, int16 posY); void displayLargeMap(int16 posX, int16 posY); - void redrawScreen(); + void drawScreen(); uint8 *script_readNumberArray(uint8 *buffer, int16 destArraySize, int16 *destArray); uint8 *script_getNumber(uint8 *srcBuffer, int16 *retval); void removeObject(int16 charId, int16 objectId); @@ -554,7 +554,6 @@ class EfhEngine : public Engine { int16 _word2C872; bool _word2C880; bool _redrawNeededFl; - bool _word2C8D7; bool _drawHeroOnMapFl; bool _drawMonstersOnMapFl; bool _word2C87A; @@ -570,10 +569,11 @@ class EfhEngine : public Engine { uint16 _tempTextDelay; uint8 *_tempTextPtr; - bool _word2C8D9; + bool _dbgForceDisplayUpperRightBorder; // Original debug flag? Always false. bool _dbgForceMonsterBlock; // Original debug flag? Always false. + bool _word2C8D7; // Original debug flag? Always true. bool _word2D0BC; - bool _word2C8D2; + bool _statusMenuActive; int16 _menuDepth; int16 _word2D0BA; int16 _word32680[3]; From a651ff0b9dd3f4055e09b33a94d8fce9b72d37c7 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Fri, 7 Jan 2022 23:30:36 +0100 Subject: [PATCH 123/412] EFH: Fix missing initialization in handleFight --- engines/efh/efh.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 0c9b92d57b01..aef7cd918ca2 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -4961,6 +4961,7 @@ bool EfhEngine::handleFight(int16 monsterId) { debug("handleFight %d", monsterId); int16 var8C = 0; + _word2D0BC = true; sub1BE89(monsterId); From cadc61de7acf5294bc8b1e92f0d5be7d4e251f66 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Tue, 11 Jan 2022 23:10:32 +0100 Subject: [PATCH 124/412] EFH: Fix debug string for drawText --- engines/efh/efh.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index aef7cd918ca2..9ea4e27cc43f 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -2053,7 +2053,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int16 posX, int16 posY, int16 } void EfhEngine::drawText(uint8 *srcPtr, int16 posX, int16 posY, int16 maxX, int16 maxY, bool flag) { - debug("drawText %d-%d %d-%d %d", posX, posY, maxX, maxY, flag ? "True" : "False"); + debug("drawText %d-%d %d-%d %s", posX, posY, maxX, maxY, flag ? "True" : "False"); uint16 stringIdx = 0; uint8 *impPtr = srcPtr; From c253ae5a54d8ec97d4ea42ab37175035db39ba7b Mon Sep 17 00:00:00 2001 From: Strangerke Date: Tue, 24 May 2022 22:27:10 +0100 Subject: [PATCH 125/412] EFH: Fix getStringWidth (fix 2nd text page in the intro) --- engines/efh/efh.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 9ea4e27cc43f..2d2d5b6035c2 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -6909,6 +6909,9 @@ uint16 EfhEngine::getStringWidth(const char *buffer) { retVal += _fontDescr._widthArray[curChar - 0x20] + 1; } + if (retVal) + retVal--; + return retVal; } From 8f5128f1a3019ce24b96ce6390a42b413938f4c8 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Wed, 25 May 2022 23:13:56 +0100 Subject: [PATCH 126/412] EFH: Some renaming in script_parse --- engines/efh/efh.cpp | 64 ++++++++++++++++++++++----------------------- 1 file changed, 31 insertions(+), 33 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 2d2d5b6035c2..833d2bad1335 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -1621,24 +1621,23 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int16 posX, int16 posY, int16 int16 var_F2 = -1; int16 var_F0 = 0xFF; int16 var_EE = 0xFF; - const char *stringToDisplay = " "; - uint16 curLine = 0; + uint16 curLineNb = 0; int16 numbLines = (1 + maxY - posY) / 9; int16 width = maxX - posX; - int16 var_114 = getStringWidth(stringToDisplay); + int16 spaceWidth = getStringWidth(" "); uint8 *buffer = stringBuffer; - char var_EC[80]; - char dest[150]; - memset(var_EC, 0, sizeof(var_EC)); - memset(dest, 0, sizeof(dest)); - int16 var_116 = 0; - setTextPos(posX, curLine * 9 + posY); + char nextWord[80]; + char curLine[150]; + memset(nextWord, 0, sizeof(nextWord)); + memset(curLine, 0, sizeof(curLine)); + int16 curWordPos = 0; + setTextPos(posX, curLineNb * 9 + posY); while (!doneFlag) { uint8 curChar = *buffer; if (curChar != 0x5E && curChar != 0x20 && curChar != 0 && curChar != 0x7C) { var_F2 = 0; - var_EC[var_116++] = curChar; + nextWord[curWordPos++] = curChar; ++buffer; continue; } @@ -1649,28 +1648,28 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int16 posX, int16 posY, int16 else if (curChar == 0x7C) var_F2 = 0; - var_EC[var_116] = 0; - int16 var_11A = getStringWidth(var_EC); - int16 var_118 = var_114 + getStringWidth(dest); + nextWord[curWordPos] = 0; + int16 widthNextWord = getStringWidth(nextWord); + int16 widthCurrentLine = spaceWidth + getStringWidth(curLine); - if (var_118 + var_11A > width || curChar == 0x7C) { - if (curLine >= numbLines) { + if (widthCurrentLine + widthNextWord > width || curChar == 0x7C) { + if (curLineNb >= numbLines) { doneFlag = true; } else { if (var_F2 == 0) - displayStringAtTextPos(dest); - - *dest = 0; - strcpy(dest, var_EC); - strcat(dest, " "); - ++curLine; - setTextPos(posX, posY + curLine * 9); - var_116 = 0; + displayStringAtTextPos(curLine); + + *curLine = 0; + strcpy(curLine, nextWord); + strcat(curLine, " "); + ++curLineNb; + setTextPos(posX, posY + curLineNb * 9); + curWordPos = 0; } } else { - strcat(dest, var_EC); - strcat(dest, " "); - var_116 = 0; + strcat(curLine, nextWord); + strcat(curLine, " "); + curWordPos = 0; } ++buffer; continue; @@ -1955,11 +1954,11 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int16 posX, int16 posY, int16 } else { copyString(_npcBuf[_teamCharId[counter]]._name, _enemyNamePt2); copyString(_items[var110]._name, _nameBuffer); - sprintf(dest, "%s finds a %s!", _enemyNamePt2, _nameBuffer); + sprintf(curLine, "%s finds a %s!", _enemyNamePt2, _nameBuffer); drawMapWindow(); displayFctFullScreen(); drawMapWindow(); - var110 = sub1C219((uint8 *)dest, 1, 2, true); + var110 = sub1C219((uint8 *)curLine, 1, 2, true); displayFctFullScreen(); } @@ -2037,8 +2036,8 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int16 posX, int16 posY, int16 } } - if (*dest != 0 && curLine < numbLines && var_F2 == 0) - displayStringAtTextPos(dest); + if (*curLine != 0 && curLineNb < numbLines && var_F2 == 0) + displayStringAtTextPos(curLine); if (var_EE != 0xFF) { displayLowStatusScreen(true); @@ -2441,8 +2440,7 @@ bool EfhEngine::handleDeathMenu() { displayFctFullScreen(); } - bool found; - for (found = false; !found;) { + for (bool found = false; !found;) { Common::KeyCode input = waitForKey(); switch (input) { case Common::KEYCODE_l: @@ -6892,7 +6890,7 @@ void EfhEngine::writeTechAndMapFiles() { } uint16 EfhEngine::getStringWidth(const char *buffer) { - debug("getStringWidth %s", buffer); + debugC(6, kDebugEngine, "getStringWidth %s", buffer); uint16 retVal = 0; From 70147a0310ce49d37ac1c351128697dcc55e3e1e Mon Sep 17 00:00:00 2001 From: Strangerke Date: Thu, 26 May 2022 08:12:24 +0100 Subject: [PATCH 127/412] EFH: Fix display of the last part of the intro --- engines/efh/efh.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 833d2bad1335..166c315a56b7 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -856,7 +856,7 @@ void EfhEngine::readImpFile(int16 id, bool techMapFl) { } void EfhEngine::playIntro() { - debug("playIntro"); + debugC(6, "playIntro"); displayRawDataAtPos(_circleImageSubFileArray[0], 0, 0); displayFctFullScreen(); @@ -921,9 +921,11 @@ void EfhEngine::playIntro() { if (lastInput == Common::KEYCODE_ESCAPE) return; + displayRawDataAtPos(_circleImageSubFileArray[3], 110, 16); displayRawDataAtPos(_circleImageSubFileArray[0], 0, 144); drawText(_imp2PtrArray[5], 6, 150, 268, 186, false); displayFctFullScreen(); + displayRawDataAtPos(_circleImageSubFileArray[3], 110, 16); displayRawDataAtPos(_circleImageSubFileArray[0], 0, 144); drawText(_imp2PtrArray[5], 6, 150, 268, 186, false); getLastCharAfterAnimCount(80); @@ -2524,13 +2526,13 @@ void EfhEngine::computeMapAnimation() { } void EfhEngine::unkFct_anim() { - debug("unkFct_anim"); - setNumLock(); if (_engineInitPending) return; + debug("unkFct_anim"); + if (_animImageSetId != 0xFF) { displayNextAnimFrame(); displayFctFullScreen(); From cbe49b22ce3dd9bf241f843c9a65e567cd48adb2 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Mon, 30 May 2022 22:51:44 +0100 Subject: [PATCH 128/412] EFH: Fix getInputBlocking --- engines/efh/utils.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/engines/efh/utils.cpp b/engines/efh/utils.cpp index 5f6393a4b99e..b97acb13ad1e 100644 --- a/engines/efh/utils.cpp +++ b/engines/efh/utils.cpp @@ -289,6 +289,8 @@ Common::KeyCode EfhEngine::getInputBlocking() { uint32 lastMs = _system->getMillis(); while (retVal == Common::KEYCODE_INVALID) { + _system->getEventManager()->pollEvent(event); + if (event.type == Common::EVENT_KEYUP) { retVal = event.kbd.keycode; } From c66d0eee230983e6bf4481de569a13a937e602a2 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Mon, 30 May 2022 22:54:19 +0100 Subject: [PATCH 129/412] EFH: Fix opening dialog when using phone booth --- engines/efh/efh.cpp | 95 +++++++++++++++++++++++---------------------- engines/efh/efh.h | 12 +++--- 2 files changed, 55 insertions(+), 52 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 166c315a56b7..71bd83813cc6 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -65,7 +65,7 @@ void InvObject::init() { } void UnkMapStruct::init() { - _field0 = _field1 = _field2 = _field3 = _field4 = 0; + _placeId = _posX = _posY = _field3 = _field4 = 0; _field5 = _field7 = 0; } @@ -299,7 +299,7 @@ EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst) _unk_sub26437_flag = 0; _dbgForceDisplayUpperRightBorder = false; _dbgForceMonsterBlock = false; - _word2D0BC = false; + _ongoingFightFl = false; _statusMenuActive = false; _menuDepth = 0; _word2D0BA = 0; @@ -761,7 +761,7 @@ void EfhEngine::readItems() { _items[i].field_19 = *curPtr++; _items[i].field_1A = *curPtr++; - warning("%s\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x", _items[i]._name, _items[i]._damage, _items[i]._defense, _items[i]._attacks, _items[i]._uses, _items[i].field_13, _items[i]._range, _items[i]._attackType, _items[i].field_16, _items[i].field17_attackTypeDefense, _items[i].field_18, _items[i].field_19, _items[i].field_1A); +// warning("%s\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x", _items[i]._name, _items[i]._damage, _items[i]._defense, _items[i]._attacks, _items[i]._uses, _items[i].field_13, _items[i]._range, _items[i]._attackType, _items[i].field_16, _items[i].field17_attackTypeDefense, _items[i].field_18, _items[i].field_19, _items[i].field_1A); } } @@ -856,7 +856,7 @@ void EfhEngine::readImpFile(int16 id, bool techMapFl) { } void EfhEngine::playIntro() { - debugC(6, "playIntro"); + debugC(6, kDebugEngine, "playIntro"); displayRawDataAtPos(_circleImageSubFileArray[0], 0, 0); displayFctFullScreen(); @@ -1046,9 +1046,9 @@ void EfhEngine::loadMapArrays() { uint8 *_mapUnknownPtr = &_map[2]; for (int i = 0; i < 100; ++i) { - _mapUnknown[i]._field0 = _mapUnknownPtr[9 * i]; - _mapUnknown[i]._field1 = _mapUnknownPtr[9 * i + 1]; - _mapUnknown[i]._field2 = _mapUnknownPtr[9 * i + 2]; + _mapUnknown[i]._placeId = _mapUnknownPtr[9 * i]; + _mapUnknown[i]._posX = _mapUnknownPtr[9 * i + 1]; + _mapUnknown[i]._posY = _mapUnknownPtr[9 * i + 2]; _mapUnknown[i]._field3 = _mapUnknownPtr[9 * i + 3]; _mapUnknown[i]._field4 = _mapUnknownPtr[9 * i + 4]; _mapUnknown[i]._field5 = READ_LE_UINT16(&_mapUnknownPtr[9 * i + 5]); @@ -1167,7 +1167,7 @@ void EfhEngine::drawGameScreenAndTempText(bool flag) { } void EfhEngine::drawMap(bool largeMapFl, int16 mapPosX, int16 mapPosY, int16 mapSize, bool drawHeroFl, bool drawMonstersFl) { - debug("drawMap %s %d-%d %d %s %s", largeMapFl ? "True" : "False", mapPosX, mapPosY, mapSize, drawHeroFl ? "True" : "False", drawMonstersFl ? "True" : "False"); + debugC(6, kDebugEngine, "drawMap %s %d-%d %d %s %s", largeMapFl ? "True" : "False", mapPosX, mapPosY, mapSize, drawHeroFl ? "True" : "False", drawMonstersFl ? "True" : "False"); int16 unkPosX = 5; int16 unkPosY = 4; @@ -1295,7 +1295,7 @@ void EfhEngine::drawScreen() { } void EfhEngine::displayLowStatusScreen(bool flag) { - debug("displayLowStatusScreen %s", flag ? "True" : "False"); + debugC(6, kDebugEngine, "displayLowStatusScreen %s", flag ? "True" : "False"); static char strName[5] = "Name"; static char strDef[4] = "DEF"; @@ -1880,7 +1880,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int16 posX, int16 posY, int16 if (flag) { int16 var110 = sub151FD(_mapPosX, _mapPosY); if (var110 != -1) - _mapUnknown[var110]._field1 = 0xFF; + _mapUnknown[var110]._posX = 0xFF; } break; case 0x13: @@ -1966,7 +1966,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int16 posX, int16 posY, int16 var110 = sub151FD(_mapPosX, _mapPosY); if (var110 != -1) { - _mapUnknown[var110]._field1 = 0xFF; + _mapUnknown[var110]._posX = 0xFF; } _redrawNeededFl = true; } @@ -1986,7 +1986,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int16 posX, int16 posY, int16 if (flag) { int16 var110 = sub151FD(scriptNumberArray[0], scriptNumberArray[1]); if (var110 != -1) { - _mapUnknown[var110]._field1 = 0xFF; + _mapUnknown[var110]._posX = 0xFF; } } break; @@ -1995,10 +1995,10 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int16 posX, int16 posY, int16 if (flag) { int16 var110 = sub151FD(scriptNumberArray[0], scriptNumberArray[1]); if (var110 != -1) { - _mapUnknown[var110]._field1 = 0xFF; + _mapUnknown[var110]._posX = 0xFF; } - _mapUnknown[scriptNumberArray[2]]._field1 = scriptNumberArray[0]; - _mapUnknown[scriptNumberArray[2]]._field2 = scriptNumberArray[1]; + _mapUnknown[scriptNumberArray[2]]._posX = scriptNumberArray[0]; + _mapUnknown[scriptNumberArray[2]]._posY = scriptNumberArray[1]; } break; case 0x1C: @@ -2228,12 +2228,12 @@ int16 EfhEngine::sub151FD(int16 posX, int16 posY) { if (_largeMapFlag) { for (int16 counter = 0; counter < 100; ++counter) { - if (_mapUnknown[counter]._field1 == posX && _mapUnknown[counter]._field2 == posY && _mapUnknown[counter]._field0 == 0xFE) + if (_mapUnknown[counter]._posX == posX && _mapUnknown[counter]._posY == posY && _mapUnknown[counter]._placeId == 0xFE) return counter; } } else { for (int16 counter = 0; counter < 100; ++counter) { - if (_mapUnknown[counter]._field1 == posX && _mapUnknown[counter]._field2 == posY && _mapUnknown[counter]._field0 == _fullPlaceId) + if (_mapUnknown[counter]._posX == posX && _mapUnknown[counter]._posY == posY && _mapUnknown[counter]._placeId == _fullPlaceId) return counter; } } @@ -2702,7 +2702,7 @@ int16 EfhEngine::computeMonsterGroupDistance(int16 monsterId) { } bool EfhEngine::checkWeaponRange(int16 monsterId, int16 weaponId) { - debug("checkWeaponRange %d %d", monsterId, weaponId); + debugC(6, kDebugEngine, "checkWeaponRange %d %d", monsterId, weaponId); static const int16 kRange[5] = {1, 2, 3, 3, 3}; @@ -2714,7 +2714,7 @@ bool EfhEngine::checkWeaponRange(int16 monsterId, int16 weaponId) { } bool EfhEngine::unkFct_checkMonsterField8(int16 id, bool teamFlag) { - debug("unkFct_checkMonsterField8 %d %s", id, teamFlag ? "True" : "False"); + debugC(6, kDebugEngine, "unkFct_checkMonsterField8 %d %s", id, teamFlag ? "True" : "False"); int16 monsterId = id; if (teamFlag) @@ -2733,9 +2733,9 @@ bool EfhEngine::unkFct_checkMonsterField8(int16 id, bool teamFlag) { } bool EfhEngine::checkTeamWeaponRange(int16 monsterId) { - debug("checkTeamWeaponRange %d", monsterId); + debugC(6, kDebugEngine, "checkTeamWeaponRange %d", monsterId); - if (!_word2D0BC) + if (!_ongoingFightFl) return true; for (int16 counter = 0; counter < 5; ++counter) { @@ -2746,8 +2746,8 @@ bool EfhEngine::checkTeamWeaponRange(int16 monsterId) { return true; } -bool EfhEngine::checkIfMonsterOnSameLargelMapPlace(int16 monsterId) { - debug("checkIfMonsterOnSameLargelMapPlace %d", monsterId); +bool EfhEngine::checkIfMonsterOnSameLargeMapPlace(int16 monsterId) { + debugC(6, kDebugEngine, "checkIfMonsterOnSameLargeMapPlace %d", monsterId); if (_largeMapFlag && _mapMonsters[monsterId]._guess_fullPlaceId == 0xFE) return true; @@ -2759,7 +2759,7 @@ bool EfhEngine::checkIfMonsterOnSameLargelMapPlace(int16 monsterId) { } bool EfhEngine::checkMonsterWeaponRange(int16 monsterId) { - debug("checkMonsterWeaponRange %d", monsterId); + debugC(6, kDebugEngine, "checkMonsterWeaponRange %d", monsterId); return checkWeaponRange(monsterId, _mapMonsters[monsterId]._itemId_Weapon); } @@ -2787,7 +2787,7 @@ void EfhEngine::sub174A0() { if (!checkTeamWeaponRange(monsterId)) continue; - if (!checkIfMonsterOnSameLargelMapPlace(monsterId)) + if (!checkIfMonsterOnSameLargeMapPlace(monsterId)) continue; int16 var4 = _mapMonsters[monsterId]._posX; @@ -2944,7 +2944,7 @@ void EfhEngine::sub174A0() { } bool EfhEngine::checkPictureRefAvailability(int16 monsterId) { - debug("checkPictureRefAvailability %d", monsterId); + debugC(6, kDebugEngine, "checkPictureRefAvailability %d", monsterId); if (_mapMonsters[monsterId]._guess_fullPlaceId == 0xFF) return false; @@ -3005,7 +3005,7 @@ bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { if (countPictureRef(monsterId, false) < 1) return false; - if (!checkIfMonsterOnSameLargelMapPlace(monsterId)) + if (!checkIfMonsterOnSameLargeMapPlace(monsterId)) return false; if (!checkMonsterGroupDistance1OrLess(monsterId)) @@ -3192,9 +3192,9 @@ void EfhEngine::sub22AA8(int16 arg0) { if (var12 == nullptr) break; + if (varE == 0) + memset(_messageToBePrinted, 0, 400); do { - if (varE == 0) - memset(_messageToBePrinted, 0, 400); switch (*var12) { case 0x00: case 0x0A: @@ -3223,6 +3223,8 @@ void EfhEngine::sub22AA8(int16 arg0) { var8 = -1; break; default: + _messageToBePrinted[varE++] = *var12; + varC++; break; } var12 += 1; @@ -3264,7 +3266,8 @@ void EfhEngine::sub22AA8(int16 arg0) { if (var2 != 0xFF) var4 = var2; } - } while (var4 != -1 && var4 != 0xFF); + + } while (varA == 0 && var4 != -1); } } @@ -3279,7 +3282,7 @@ bool EfhEngine::sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemI if (var8 == -1) { if (imageSetId != -1 && *_imp2PtrArray[imageSetId] != 0x30) displayMiddleLeftTempText(_imp2PtrArray[imageSetId], true); - } else if (var8 == 0) { + } else if (arg8 == 0) { if (_mapUnknown[var8]._field3 == 0xFF) { sub22AA8(_mapUnknown[var8]._field5); // word! return true; @@ -3416,7 +3419,7 @@ void EfhEngine::sub1BCA7(int16 monsterTeamId) { if (((_mapMonsters[monsterId]._possessivePronounSHL6 & 0x3F) != 0x3F || isCharacterATeamMember(_mapMonsters[monsterId]._field_1)) && (_mapMonsters[monsterId]._possessivePronounSHL6 & 0x3F) > 0x3D) continue; - if (!checkIfMonsterOnSameLargelMapPlace(monsterId)) + if (!checkIfMonsterOnSameLargeMapPlace(monsterId)) continue; bool var6 = false; @@ -3732,7 +3735,7 @@ void EfhEngine::sub1BE9A(int16 monsterId) { // sub1BE9A - 1rst loop counter1_monsterId - Start for (int16 counter1 = 0; counter1 < 5; ++counter1) { - if (sub1BAF9(counter1)) + if (countMonsterGroupMembers(counter1)) continue; for (int16 counter2 = 0; counter2 < 9; ++counter2) { @@ -3772,7 +3775,7 @@ void EfhEngine::sub1BE9A(int16 monsterId) { continue; if (((_mapMonsters[counter1]._possessivePronounSHL6 & 0x3F) == 0x3F && !isCharacterATeamMember(_mapMonsters[counter1]._field_1)) || (_mapMonsters[counter1]._possessivePronounSHL6 & 0x3F) <= 0x3D) { - if (checkIfMonsterOnSameLargelMapPlace(counter1)) { + if (checkIfMonsterOnSameLargeMapPlace(counter1)) { bool var6 = false; for (int16 counter2 = 0; counter2 < 9; ++counter2) { if (_mapMonsters[counter1]._pictureRef[counter2] > 0) { @@ -3845,16 +3848,16 @@ int16 EfhEngine::getTeamMonsterAnimId() { return retVal; } -int16 EfhEngine::sub1BAF9(int16 monsterGroup) { - debug("sub1BAF9 %d", monsterGroup); +int16 EfhEngine::countMonsterGroupMembers(int16 monsterGroup) { + debugC(9, kDebugEngine, "countMonsterGroupMembers %d", monsterGroup); - int16 var2 = 0; + int16 result = 0; for (int16 counter = 0; counter < 9; ++counter) { if (isMonsterActive(monsterGroup, counter)) - ++var2; + ++result; } - return var2; + return result; } void EfhEngine::sub1C4CA(bool whiteFl) { @@ -3866,7 +3869,7 @@ void EfhEngine::sub1C4CA(bool whiteFl) { continue; int16 var6C = computeMonsterGroupDistance(_teamMonsterIdArray[counter]); - int16 var6E = sub1BAF9(counter); + int16 var6E = countMonsterGroupMembers(counter); if (whiteFl) setTextColorWhite(); else @@ -4961,13 +4964,13 @@ bool EfhEngine::handleFight(int16 monsterId) { debug("handleFight %d", monsterId); int16 var8C = 0; - _word2D0BC = true; + _ongoingFightFl = true; sub1BE89(monsterId); if (_teamMonsterIdArray[0] == -1) { resetTeamMonsterIdArray(); - _word2D0BC = false; + _ongoingFightFl = false; displayAnimFrames(0xFE, true); return true; } @@ -4977,14 +4980,14 @@ bool EfhEngine::handleFight(int16 monsterId) { for (bool mainLoopCond = false; !mainLoopCond;) { if (isTPK()) { resetTeamMonsterIdArray(); - _word2D0BC = false; + _ongoingFightFl = false; displayAnimFrames(0xFE, true); return false; } if (_teamMonsterIdArray[0] == -1) { resetTeamMonsterIdArray(); - _word2D0BC = false; + _ongoingFightFl = false; displayAnimFrames(0xFE, true); return true; } @@ -4998,7 +5001,7 @@ bool EfhEngine::handleFight(int16 monsterId) { if (!sub1CB27()) { resetTeamMonsterIdArray(); - _word2D0BC = false; + _ongoingFightFl = false; totalPartyKill(); displayAnimFrames(0xFE, true); return false; @@ -5261,7 +5264,7 @@ bool EfhEngine::handleFight(int16 monsterId) { } resetTeamMonsterIdArray(); - _word2D0BC = false; + _ongoingFightFl = false; displayAnimFrames(0xFE, true); return true; } diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 5aaa306973b5..5e901c6264c8 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -86,9 +86,9 @@ struct InvObject { }; struct UnkMapStruct { - uint8 _field0; - uint8 _field1; - uint8 _field2; + uint8 _placeId; + uint8 _posX; + uint8 _posY; uint8 _field3; uint8 _field4; uint16 _field5; @@ -353,7 +353,7 @@ class EfhEngine : public Engine { bool checkWeaponRange(int16 monsterId, int16 weaponId); bool unkFct_checkMonsterField8(int16 id, bool teamFlag); bool checkTeamWeaponRange(int16 monsterId); - bool checkIfMonsterOnSameLargelMapPlace(int16 monsterId); + bool checkIfMonsterOnSameLargeMapPlace(int16 monsterId); bool checkMonsterWeaponRange(int16 monsterId); void sub174A0(); bool checkPictureRefAvailability(int16 monsterId); @@ -379,7 +379,7 @@ class EfhEngine : public Engine { bool sub1CB27(); void sub1BE9A(int16 monsterId); int16 getTeamMonsterAnimId(); - int16 sub1BAF9(int16 monsterGroup); + int16 countMonsterGroupMembers(int16 monsterGroup); void sub1C4CA(bool WhiteFl); void displayCombatMenu(int16 charId); void drawCombatScreen(int16 charId, bool whiteFl, bool forceDrawFl); @@ -572,7 +572,7 @@ class EfhEngine : public Engine { bool _dbgForceDisplayUpperRightBorder; // Original debug flag? Always false. bool _dbgForceMonsterBlock; // Original debug flag? Always false. bool _word2C8D7; // Original debug flag? Always true. - bool _word2D0BC; + bool _ongoingFightFl; bool _statusMenuActive; int16 _menuDepth; int16 _word2D0BA; From 0acc221f4f253246fc51c0b4205d37f3f9ab7280 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Tue, 31 May 2022 07:36:47 +0100 Subject: [PATCH 130/412] EFH: Fix the display of the gate first message and the board. --- engines/efh/utils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engines/efh/utils.cpp b/engines/efh/utils.cpp index b97acb13ad1e..58721a564592 100644 --- a/engines/efh/utils.cpp +++ b/engines/efh/utils.cpp @@ -56,7 +56,7 @@ void EfhEngine::decryptImpFile(bool techMapFl) { _imp2PtrArray[counter++] = curPtr = _imp2; target = 431; } else { - _imp2PtrArray[counter++] = curPtr = _imp1; + _imp1PtrArray[counter++] = curPtr = _imp1; target = 99; } From 14bb81d797acf4473ce6fe7b2150cc0c38961e18 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Wed, 1 Jun 2022 20:55:39 +0100 Subject: [PATCH 131/412] EFH: Fix bugs in opcode 12 and 13, fix issues in readNumberArray and getNumber --- engines/efh/efh.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 71bd83813cc6..52b918a682c6 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -1371,7 +1371,7 @@ uint8 *EfhEngine::script_readNumberArray(uint8 *srcBuffer, int16 destArraySize, debug("script_readNumberArray"); uint8 *buffer = srcBuffer; - + buffer++; for (int16 i = 0; i < destArraySize; ++i) { buffer = script_getNumber(buffer, &destArray[i]); } @@ -1391,6 +1391,7 @@ uint8 *EfhEngine::script_getNumber(uint8 *srcBuffer, int16 *retval) { return buffer; } var2 = var2 * 10 + curChar - 0x30; + buffer++; } } @@ -1682,7 +1683,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int16 posX, int16 posY, int16 int16 var_108 = 0; buffer = script_getNumber(buffer, &var_108); int16 scriptNumberArray[10]; - memset(scriptNumberArray, 0, ARRAYSIZE(scriptNumberArray)); + memset(scriptNumberArray, 0, sizeof(scriptNumberArray)); switch (var_108) { case 0x00: @@ -1813,7 +1814,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int16 posX, int16 posY, int16 case 0x0C: buffer = script_readNumberArray(buffer, 2, scriptNumberArray); if (flag) { - int16 var110 = _teamCharId[scriptNumberArray[0]]; + int16 var110 = scriptNumberArray[0]; bool found = false; for (int16 counter = 0; counter < _teamSize && !found; ++counter) { for (int16 objectId = 0; objectId < 10; ++objectId) { @@ -1829,7 +1830,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int16 posX, int16 posY, int16 case 0x0D: buffer = script_readNumberArray(buffer, 1, scriptNumberArray); if (flag) { - int16 var110 = _teamCharId[scriptNumberArray[0]]; + int16 var110 = scriptNumberArray[0]; for (int16 counter = 0; counter < _teamSize; ++counter) { if (giveItemTo(_teamCharId[counter], var110, 0xFF)) break; @@ -2156,7 +2157,7 @@ void EfhEngine::sub2455E(int16 arg0, int16 arg2, int16 arg4) { } int16 EfhEngine::sub1C219(uint8 *str, int16 menuType, int16 arg4, bool displayTeamWindowFl) { - debug("sub1C219 %s %c %c %s", (char *)str, menuType, arg4, displayTeamWindowFl ? "True" : "False"); + debug("sub1C219 %s %d %d %s", (char *)str, menuType, arg4, displayTeamWindowFl ? "True" : "False"); int16 varA = 0xFF; int16 minX, maxX, minY, maxY; From d1acf3e1f78e8d725d6120564272b8724f76bcfc Mon Sep 17 00:00:00 2001 From: Strangerke Date: Wed, 1 Jun 2022 21:15:12 +0100 Subject: [PATCH 132/412] EFH: Fix readNumberArray. It's now possible to teleport!! \o/ --- engines/efh/efh.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 52b918a682c6..838a70733ede 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -1371,8 +1371,8 @@ uint8 *EfhEngine::script_readNumberArray(uint8 *srcBuffer, int16 destArraySize, debug("script_readNumberArray"); uint8 *buffer = srcBuffer; - buffer++; for (int16 i = 0; i < destArraySize; ++i) { + buffer++; buffer = script_getNumber(buffer, &destArray[i]); } From abfd4848ed67a8b223c595ecbcbb885fe8e83cef Mon Sep 17 00:00:00 2001 From: Strangerke Date: Wed, 1 Jun 2022 23:31:50 +0100 Subject: [PATCH 133/412] EFH: Fix transparency --- engines/efh/graphics.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/engines/efh/graphics.cpp b/engines/efh/graphics.cpp index 9566d95ffb8e..cd24bfcba956 100644 --- a/engines/efh/graphics.cpp +++ b/engines/efh/graphics.cpp @@ -39,7 +39,7 @@ void EfhEngine::initPalette() { 170, 170, 170, 85, 85, 85, 85, 85, 255, - 1, 1, 1, + 1, 1, 1, // Color 0xA is for transparency 85, 255, 255, 255, 85, 85, 255, 85, 255, @@ -128,8 +128,10 @@ void EfhEngine::displayBufferBmAtPos(BufferBM *bufferBM, int16 posX, int16 posY) int counter = 0; for (int line = 0; line < bufferBM->_height; ++line) { for (int col = 0; col < bufferBM->_lineDataSize; ++col) { // _lineDataSize = _width / 2 - destPtr[320 * line + 2 * col] = bufferBM->_dataPtr[counter] >> 4; - destPtr[320 * line + 2 * col + 1] = bufferBM->_dataPtr[counter] & 0xF; + if (bufferBM->_dataPtr[counter] >> 4 != 0xA) + destPtr[320 * line + 2 * col] = bufferBM->_dataPtr[counter] >> 4; + if ((bufferBM->_dataPtr[counter] & 0xF) != 0xA) + destPtr[320 * line + 2 * col + 1] = bufferBM->_dataPtr[counter] & 0xF; ++counter; } } From fb064ef2233dcbe6fa2b6920135e6b07e7e42393 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Thu, 2 Jun 2022 01:08:52 +0100 Subject: [PATCH 134/412] EFH: Fix DrawColorRect usage in sub1C219 (fix display when reading descriptions or dialogs) --- engines/efh/efh.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 838a70733ede..3cb751a8b59b 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -2194,7 +2194,7 @@ int16 EfhEngine::sub1C219(uint8 *str, int16 menuType, int16 arg4, bool displayTe break; } - drawColoredRect(minX, maxX, minY, maxY, 0); + drawColoredRect(minX, minY, maxX, maxY, 0); if (str) varA = script_parse(str, minX, minY, maxX, maxY, true); @@ -2206,7 +2206,7 @@ int16 EfhEngine::sub1C219(uint8 *str, int16 menuType, int16 arg4, bool displayTe if (_word2C87A != 0) _word2C87A = 0; else { - drawColoredRect(minX, maxX, minY, maxY, 0); + drawColoredRect(minX, minY, maxX, maxY, 0); if (str) int16 varC = script_parse(str, minX, minY, maxX, maxY, true); } @@ -2218,7 +2218,7 @@ int16 EfhEngine::sub1C219(uint8 *str, int16 menuType, int16 arg4, bool displayTe int16 varC = getLastCharAfterAnimCount(_guessAnimationAmount); if (arg4 == 3) - drawColoredRect(minX, maxX, minY, maxY, 0); + drawColoredRect(minX, minY, maxX, maxY, 0); } return varA; @@ -3229,7 +3229,7 @@ void EfhEngine::sub22AA8(int16 arg0) { break; } var12 += 1; - int16 var2; + int16 var2 = 0xFF ; if (var8 != 0 || varA != 0) { var8 = 0; _messageToBePrinted[varE] = 0; From a3916952a6300b77d09fb6a6c4920a89c5dc55e7 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Thu, 2 Jun 2022 08:05:48 +0100 Subject: [PATCH 135/412] EFH: Some renaming, add a note in drawChar --- engines/efh/efh.cpp | 13 ++++++------- engines/efh/efh.h | 3 +-- engines/efh/graphics.cpp | 16 ++++++++++------ 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 3cb751a8b59b..94fe69a1ad17 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -296,7 +296,6 @@ EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst) _drawHeroOnMapFl = true; _drawMonstersOnMapFl = true; _word2C87A = false; - _unk_sub26437_flag = 0; _dbgForceDisplayUpperRightBorder = false; _dbgForceMonsterBlock = false; _ongoingFightFl = false; @@ -1680,12 +1679,12 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int16 posX, int16 posY, int16 // At this point, curChar == 0x5E ++buffer; - int16 var_108 = 0; - buffer = script_getNumber(buffer, &var_108); + int16 opCode = 0; + buffer = script_getNumber(buffer, &opCode); int16 scriptNumberArray[10]; memset(scriptNumberArray, 0, sizeof(scriptNumberArray)); - switch (var_108) { + switch (opCode) { case 0x00: buffer = script_readNumberArray(buffer, 3, scriptNumberArray); if (flag) { @@ -2203,8 +2202,8 @@ int16 EfhEngine::sub1C219(uint8 *str, int16 menuType, int16 arg4, bool displayTe if (arg4 != 0) { displayFctFullScreen(); - if (_word2C87A != 0) - _word2C87A = 0; + if (_word2C87A) + _word2C87A = false; else { drawColoredRect(minX, minY, maxX, maxY, 0); if (str) @@ -3900,7 +3899,7 @@ void EfhEngine::sub1C4CA(bool whiteFl) { _textColor = 0xE; displayStringAtTextPos("Hostile"); } else { - _textColor = 2; + _textColor = 0x2; displayStringAtTextPos("Friendly"); } diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 5e901c6264c8..f67c48ce14a8 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -438,7 +438,7 @@ class EfhEngine : public Engine { void drawColoredRect(int16 minX, int16 minY, int16 maxX, int16 maxY, int16 color); void clearScreen(int16 color); void displayRawDataAtPos(uint8 *imagePtr, int16 posX, int16 posY); - void drawString(const char *str, int16 startX, int16 startY, uint16 unkFl); + void drawString(const char *str, int16 startX, int16 startY, uint16 textColor); void displayCenteredString(const char *str, int16 minX, int16 maxX, int16 posY); void displayMenuAnswerString(const char *str, int16 minX, int16 maxX, int16 posY); void drawMapWindow(); @@ -557,7 +557,6 @@ class EfhEngine : public Engine { bool _drawHeroOnMapFl; bool _drawMonstersOnMapFl; bool _word2C87A; - int16 _unk_sub26437_flag; int16 _imageSetSubFilesIdx; int16 _oldImageSetSubFilesIdx; diff --git a/engines/efh/graphics.cpp b/engines/efh/graphics.cpp index cd24bfcba956..c31fdc61e385 100644 --- a/engines/efh/graphics.cpp +++ b/engines/efh/graphics.cpp @@ -200,17 +200,16 @@ void EfhEngine::displayRawDataAtPos(uint8 *imagePtr, int16 posX, int16 posY) { displayBufferBmAtPos(&_imageDataPtr, posX, posY); } -void EfhEngine::drawString(const char *str, int16 startX, int16 startY, uint16 unkFl) { - debugC(1, kDebugGraphics, "drawString %s %d %d %d", str, startX, startY, unkFl); +void EfhEngine::drawString(const char *str, int16 startX, int16 startY, uint16 textColor) { + debugC(1, kDebugGraphics, "drawString %s %d %d %d", str, startX, startY, textColor); uint8 *curPtr = (uint8 *)str; uint16 lineHeight = _fontDescr._charHeight + _fontDescr._extraVerticalSpace; - _unk_sub26437_flag = unkFl & 0x3FFF; int16 minX = startX; - int16 minY = startY; // Used in case 0x8000 - int16 var6 = _fontDescr._extraLines[0] + startY - 1; // Used in case 0x8000 - if (unkFl & 0x8000) { + if (textColor & 0x8000) { warning("STUB - drawString - 0x8000"); + // int16 minY = startY; // Used in case 0x8000 + // int16 var6 = _fontDescr._extraLines[0] + startY - 1; // Used in case 0x8000 } for (uint8 curChar = *curPtr++; curChar != 0; curChar = *curPtr++) { @@ -291,6 +290,11 @@ void EfhEngine::drawChar(uint8 curChar, int16 posX, int16 posY) { debugC(1, kDebugGraphics, "drawChar %c %d %d", curChar, posX, posY); // CHECKME: Quick hacked display, may require rework + + // Note: The original is making of a variable which is set to _textColor & 0x3FFF + // It seems _textColor is always set to a small value and thus this variable + // has been removed. + uint8 *destPtr = (uint8 *)_mainSurface->getBasePtr(posX, posY); int16 charId = curChar - 0x20; From 144819e53f0bc7d4a872d7ff8e02ded652f940ea Mon Sep 17 00:00:00 2001 From: Strangerke Date: Thu, 2 Jun 2022 22:06:20 +0100 Subject: [PATCH 136/412] EFH: Fix moonwalk occurring when getting close to the left and top border of the maps --- engines/efh/efh.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 94fe69a1ad17..d37ea2ea4ccf 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -1177,12 +1177,12 @@ void EfhEngine::drawMap(bool largeMapFl, int16 mapPosX, int16 mapPosY, int16 map int16 minY = mapPosY - 4; if (minX < 0) { - unkPosX -= minX; + unkPosX += minX; minX = 0; } if (minY < 0) { - unkPosY -= minY; + unkPosY += minY; minY = 0; } From 309f10be4d05a71e268d7bba56c9b3e2fd870d3a Mon Sep 17 00:00:00 2001 From: Strangerke Date: Thu, 2 Jun 2022 22:41:36 +0100 Subject: [PATCH 137/412] EFH: Some renaming in drawMap --- engines/efh/efh.cpp | 52 ++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index d37ea2ea4ccf..4d74f76b2ae3 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -1168,21 +1168,18 @@ void EfhEngine::drawGameScreenAndTempText(bool flag) { void EfhEngine::drawMap(bool largeMapFl, int16 mapPosX, int16 mapPosY, int16 mapSize, bool drawHeroFl, bool drawMonstersFl) { debugC(6, kDebugEngine, "drawMap %s %d-%d %d %s %s", largeMapFl ? "True" : "False", mapPosX, mapPosY, mapSize, drawHeroFl ? "True" : "False", drawMonstersFl ? "True" : "False"); - int16 unkPosX = 5; - int16 unkPosY = 4; - int16 posX = 0; - int16 posY = 0; - int16 var6 = 0; + int16 shiftPosX = 5; + int16 shiftPosY = 4; int16 minX = mapPosX - 5; int16 minY = mapPosY - 4; if (minX < 0) { - unkPosX += minX; + shiftPosX += minX; minX = 0; } if (minY < 0) { - unkPosY += minY; + shiftPosY += minY; minY = 0; } @@ -1190,45 +1187,46 @@ void EfhEngine::drawMap(bool largeMapFl, int16 mapPosX, int16 mapPosY, int16 map int16 maxY = minY + 7; if (maxX > mapSize) { - unkPosX += (maxX - mapSize); + shiftPosX += (maxX - mapSize); maxX = mapSize; minX = mapSize - 10; } if (maxY > mapSize) { - unkPosY += (maxY - mapSize); + shiftPosY += (maxY - mapSize); maxY = mapSize; minY = mapSize - 7; } - int16 var10 = 8; + int16 drawPosY = 8; for (int16 counterY = minY; counterY <= maxY; ++counterY) { - int16 var12 = 128; - for (int16 var16 = minX; var16 <= maxX; ++var16) { + int16 drawPosX = 128; + for (int16 counterX = minX; counterX <= maxX; ++counterX) { if (largeMapFl) { - int16 idx = _mapGameMap[var16][counterY]; - displayRawDataAtPos(_imageSetSubFilesArray[idx], var12, var10); + int16 idx = _mapGameMap[counterX][counterY]; + displayRawDataAtPos(_imageSetSubFilesArray[idx], drawPosX, drawPosY); } else { - int16 idx = _curPlace[var16][counterY]; - displayRawDataAtPos(_imageSetSubFilesArray[idx], var12, var10); + int16 idx = _curPlace[counterX][counterY]; + displayRawDataAtPos(_imageSetSubFilesArray[idx], drawPosX, drawPosY); } - var12 += 16; + drawPosX += 16; } - var10 += 16; + drawPosY += 16; } if (drawHeroFl) { - int16 var12 = 128 + unkPosX * 16; - var10 = 8 + unkPosY * 16; - displayRawDataAtPos(_imageSetSubFilesArray[_imageSetSubFilesIdx], var12, var10); + // Draw hero + int16 drawPosX = 128 + shiftPosX * 16; + drawPosY = 8 + shiftPosY * 16; + displayRawDataAtPos(_imageSetSubFilesArray[_imageSetSubFilesIdx], drawPosX, drawPosY); } if (drawMonstersFl) { for (int16 var16 = 0; var16 < 64; ++var16) { if ((_largeMapFlag && _mapMonsters[var16]._guess_fullPlaceId == 0xFE) || (!_largeMapFlag && _mapMonsters[var16]._guess_fullPlaceId == _fullPlaceId)){ bool var4 = false; - posX = _mapMonsters[var16]._posX; - posY = _mapMonsters[var16]._posY; + int16 posX = _mapMonsters[var16]._posX; + int16 posY = _mapMonsters[var16]._posY; if (posX < minX || posX > maxX || posY < minY || posY > maxY) continue; @@ -1241,15 +1239,15 @@ void EfhEngine::drawMap(bool largeMapFl, int16 mapPosX, int16 mapPosY, int16 map if (!var4) continue; - var6 = 148 + kEncounters[_mapMonsters[var16]._monsterRef]._animId; + int16 var6 = 148 + kEncounters[_mapMonsters[var16]._monsterRef]._animId; int16 var1 = _mapMonsters[var16]._possessivePronounSHL6 & 0x3F; if (var1 == 0x3F && isCharacterATeamMember(_mapMonsters[var16]._field_1)) continue; - int16 var12 = 128 + (posX - minX) * 16; - var10 = 8 + (posY - minY) * 16; - displayRawDataAtPos(_imageSetSubFilesArray[var6], var12, var10); + int16 drawPosX = 128 + (posX - minX) * 16; + drawPosY = 8 + (posY - minY) * 16; + displayRawDataAtPos(_imageSetSubFilesArray[var6], drawPosX, drawPosY); } } } From 1071de9f8b45aa94af42a2c4f954fe9457c41427 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Thu, 2 Jun 2022 23:57:45 +0100 Subject: [PATCH 138/412] EFH: Add some comments in the script parser, fix the display of conditional dialogs --- engines/efh/efh.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 4d74f76b2ae3..a11a9f8d7342 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -718,7 +718,7 @@ void EfhEngine::loadPlacesFile(uint16 fullPlaceId, bool forceReloadFl) { readFileToBuffer(fileName, _hiResImageBuf); uncompressBuffer(_hiResImageBuf, _places); } - copyCurrentPlaceToBuffer(_fullPlaceId / 20); + copyCurrentPlaceToBuffer(_fullPlaceId % 20); } void EfhEngine::readTileFact() { @@ -1684,6 +1684,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int16 posX, int16 posY, int16 switch (opCode) { case 0x00: + // Enter room { full Place Id, posX, posY } buffer = script_readNumberArray(buffer, 3, scriptNumberArray); if (flag) { if (_largeMapFlag) { @@ -1699,6 +1700,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int16 posX, int16 posY, int16 } break; case 0x01: + // Exit room { } if (flag) { _largeMapFlag = true; _oldMapPosX = _mapPosX = _techDataId_MapPosX; @@ -1708,6 +1710,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int16 posX, int16 posY, int16 } break; case 0x02: + // Change map. { map number, posX, posY } buffer = script_readNumberArray(buffer, 3, scriptNumberArray); if (flag) { if (_word2C8D7) @@ -1825,6 +1828,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int16 posX, int16 posY, int16 } break; case 0x0D: + // Put item in inventory { objectId } buffer = script_readNumberArray(buffer, 1, scriptNumberArray); if (flag) { int16 var110 = scriptNumberArray[0]; @@ -1875,6 +1879,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int16 posX, int16 posY, int16 _unkArray2C8AA[0] = 0; break; case 0x12: + // Guess : disable special tile { } if (flag) { int16 var110 = sub151FD(_mapPosX, _mapPosY); if (var110 != -1) @@ -2012,6 +2017,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int16 posX, int16 posY, int16 } break; case 0x1E: + // Dialog with condition { historyId, dialogId1, dialogId2 } buffer = script_readNumberArray(buffer, 3, scriptNumberArray); if (flag) { if (_history[scriptNumberArray[0]] == 0) @@ -3266,6 +3272,10 @@ void EfhEngine::sub22AA8(int16 arg0) { } } while (varA == 0 && var4 != -1); + + varA = 0; + if (var4 == 0xFF || var4 == -1) + break; } } From 272b688b72981484bb9f89d2f5b1423350bbb3dc Mon Sep 17 00:00:00 2001 From: Strangerke Date: Fri, 3 Jun 2022 08:16:33 +0100 Subject: [PATCH 139/412] EFH: Fix crash when interacting with a special character --- engines/efh/efh.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index a11a9f8d7342..baa2a90a2aa2 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -6719,7 +6719,8 @@ bool EfhEngine::checkMonsterCollision() { } else if (var1 == 0x3E) { strcpy(buffer, "(NOT DEFINED)"); } else if (var1 == 0x3F) { // Useless check, it's the last possible value - copyString(_npcBuf[_mapMonsters[monsterId]._monsterRef]._name, dest); + // Special character name + copyString(_npcBuf[_mapMonsters[monsterId]._field_1]._name, dest); sprintf(buffer, "with %s", dest); } From 164b5825e9f2c998035f50da2e49858947183c8a Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sat, 4 Jun 2022 00:32:17 +0100 Subject: [PATCH 140/412] EFH: Fix double execution of opcodes, start fixing encounter of special characters --- engines/efh/efh.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index baa2a90a2aa2..e532af339fc2 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -2211,7 +2211,7 @@ int16 EfhEngine::sub1C219(uint8 *str, int16 menuType, int16 arg4, bool displayTe else { drawColoredRect(minX, minY, maxX, maxY, 0); if (str) - int16 varC = script_parse(str, minX, minY, maxX, maxY, true); + int16 varC = script_parse(str, minX, minY, maxX, maxY, false); } if (displayTeamWindowFl) @@ -3002,7 +3002,7 @@ bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { char buffer[80]; memset(buffer, 0, 80); - int8 var51 = _mapMonsters[monsterId]._possessivePronounSHL6; + uint8 var51 = _mapMonsters[monsterId]._possessivePronounSHL6 & 0x3F; if (_mapMonsters[monsterId]._guess_fullPlaceId == 0xFF) return false; @@ -5617,7 +5617,7 @@ int16 EfhEngine::displayString_3(const char *str, bool animFl, int16 charId, int displayWindow(_windowWithBorderBuf, 19, 113, _hiResImageBuf); if (counter == 0) { - script_parse((uint8 *)str, 28, 122, 105, 166, 0); + script_parse((uint8 *)str, 28, 122, 105, 166, false); displayFctFullScreen(); } else { retVal = script_parse((uint8 *)str, 28, 122, 105, 166, true); From 024ba4e02df65de614a7abb08f50ebf73c0fa463 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sat, 4 Jun 2022 00:43:06 +0100 Subject: [PATCH 141/412] EFH: Fix another issue in sub21820 --- engines/efh/efh.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index e532af339fc2..cae0cde1ad95 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -3028,7 +3028,7 @@ bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { if (isCharacterATeamMember(_mapMonsters[monsterId]._field_1)) return false; - int16 var58 = isCharacterATeamMember(_mapMonsters[monsterId]._field_1); + int16 var58 = _mapMonsters[monsterId]._field_1; switch (_npcBuf[var58].field_10 - 0xEE) { case 0: if (arg2 == 4 && _npcBuf[var58].field_11 == itemId) { @@ -3149,6 +3149,7 @@ bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { displayAnimFrames(0xFE, true); return true; default: + break; } From f1d9b538c491e15f897b1673d98b9a4ff6390a2e Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sun, 5 Jun 2022 00:13:04 +0100 Subject: [PATCH 142/412] EFH: Fix a couple of issues in the Y/N check related to save/load games, move some debug strings to debugC --- engines/efh/efh.cpp | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index cae0cde1ad95..a57e5a322649 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -481,7 +481,7 @@ Common::Error EfhEngine::run() { displayFctFullScreen(); } Common::KeyCode input = waitForKey(); - if (input = Common::KEYCODE_y) { + if (input == Common::KEYCODE_y) { displayMenuAnswerString("-> Yes <-", 24, 296, 169); getInput(2); saveEfhGame(); @@ -496,7 +496,7 @@ Common::Error EfhEngine::run() { } break; - case Common::KEYCODE_F7: { // Original is using CTRL-S + case Common::KEYCODE_F7: { // Original is using CTRL-L for (int16 counter = 0; counter < 2; ++counter) { clearBottomTextZone(0); displayCenteredString("Are You Sure You Want To Load?", 24, 296, 160); @@ -504,7 +504,7 @@ Common::Error EfhEngine::run() { displayFctFullScreen(); } Common::KeyCode input = waitForKey(); - if (input = Common::KEYCODE_y) { + if (input == Common::KEYCODE_y) { displayMenuAnswerString("-> Yes <-", 24, 296, 169); getInput(2); loadEfhGame(); @@ -621,7 +621,7 @@ void EfhEngine::readAnimInfo() { } void EfhEngine::findMapFile(int16 mapId) { - debug("findMapFile %d", mapId); + debugC(7, kDebugEngine, "findMapFile %d", mapId); if (!_word31E9E) return; @@ -636,7 +636,7 @@ void EfhEngine::findMapFile(int16 mapId) { } void EfhEngine::loadNewPortrait() { - debug("loadNewPortrait"); + debugC(7, kDebugEngine, "loadNewPortrait"); static int16 const unkConstRelatedToAnimImageSetId[19] = {0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2}; _unkRelatedToAnimImageSetId = unkConstRelatedToAnimImageSetId[_techId]; @@ -722,7 +722,7 @@ void EfhEngine::loadPlacesFile(uint16 fullPlaceId, bool forceReloadFl) { } void EfhEngine::readTileFact() { - debug("readTileFact"); + debugC(7, kDebugEngine, "readTileFact"); Common::String fileName = "tilefact"; uint8 tileFactBuff[864]; @@ -735,7 +735,7 @@ void EfhEngine::readTileFact() { } void EfhEngine::readItems() { - debug("readItems"); + debugC(7, kDebugEngine, "readItems"); Common::String fileName = "items"; uint8 itemBuff[8100]; @@ -760,12 +760,12 @@ void EfhEngine::readItems() { _items[i].field_19 = *curPtr++; _items[i].field_1A = *curPtr++; -// warning("%s\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x", _items[i]._name, _items[i]._damage, _items[i]._defense, _items[i]._attacks, _items[i]._uses, _items[i].field_13, _items[i]._range, _items[i]._attackType, _items[i].field_16, _items[i].field17_attackTypeDefense, _items[i].field_18, _items[i].field_19, _items[i].field_1A); + debugC(7, kDebugEngine, "%s\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x", _items[i]._name, _items[i]._damage, _items[i]._defense, _items[i]._attacks, _items[i]._uses, _items[i].field_13, _items[i]._range, _items[i]._attackType, _items[i].field_16, _items[i].field17_attackTypeDefense, _items[i].field_18, _items[i].field_19, _items[i].field_1A); } } void EfhEngine::loadNPCS() { - debug("loadNPCS"); + debugC(7, kDebugEngine, "loadNPCS"); Common::String fileName = "npcs"; uint8 npcLoading[13400]; @@ -874,6 +874,7 @@ void EfhEngine::playIntro() { displayFctFullScreen(); displayRawDataAtPos(_circleImageSubFileArray[0], 0, 144); drawText(_imp2PtrArray[0], 6, 150, 268, 186, false); + lastInput = getLastCharAfterAnimCount(80); if (lastInput == Common::KEYCODE_ESCAPE) return; @@ -1897,6 +1898,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int16 posX, int16 posY, int16 } break; case 0x14: + // Add character to team { charId } buffer = script_readNumberArray(buffer, 1, scriptNumberArray); if (flag) { int16 var110 = scriptNumberArray[0]; @@ -2058,7 +2060,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int16 posX, int16 posY, int16 } void EfhEngine::drawText(uint8 *srcPtr, int16 posX, int16 posY, int16 maxX, int16 maxY, bool flag) { - debug("drawText %d-%d %d-%d %s", posX, posY, maxX, maxY, flag ? "True" : "False"); + debugC(7, kDebugEngine, "drawText %d-%d %d-%d %s", posX, posY, maxX, maxY, flag ? "True" : "False"); uint16 stringIdx = 0; uint8 *impPtr = srcPtr; From 8082c472fe3cee2d53098f552059c3e59bfe6c3d Mon Sep 17 00:00:00 2001 From: Strangerke Date: Mon, 6 Jun 2022 23:51:09 +0100 Subject: [PATCH 143/412] EFH: Change the safeguard in getRandom to make it more robust, change debug to debugC after proofreading the code, add some TODOs --- engines/efh/efh.cpp | 19 +++++++++++-------- engines/efh/utils.cpp | 2 +- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index a57e5a322649..523363f3c60f 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -1088,7 +1088,8 @@ void EfhEngine::saveAnimImageSetId() { } int16 EfhEngine::getEquipmentDefense(int16 charId, bool flag) { - debug("getEquipmentDefense %d %s", charId, flag ? "True" : "False"); + debugC(2, kDebugGraphics, "getEquipmentDefense %d %s", charId, flag ? "True" : "False"); + // TODO: flag is always false, remove it when refactoring int16 altDef = 0; int16 totalDef = 0; @@ -1117,7 +1118,7 @@ int16 EfhEngine::getEquipmentDefense(int16 charId, bool flag) { } uint16 EfhEngine::sub1C80A(int16 charId, int16 field18, bool flag) { - debug("sub1C80A %d %d %s", charId, field18, flag ? "True" : "False"); + debugC(2, kDebugEngine, "sub1C80A %d %d %s", charId, field18, flag ? "True" : "False"); for (int i = 0; i < 10; ++i) { if ((_npcBuf[charId]._inventory[i]._stat1 & 0x80) == 0) @@ -1270,7 +1271,7 @@ void EfhEngine::displayLargeMap(int16 posX, int16 posY) { } void EfhEngine::drawScreen() { - debug("drawScreen"); + debugC(2, kDebugEngine, "drawScreen"); for (int16 counter = 0; counter < 2; ++counter) { _redrawNeededFl = false; @@ -1278,12 +1279,14 @@ void EfhEngine::drawScreen() { if (_fullPlaceId != 0xFF) displaySmallMap(_mapPosX, _mapPosY); + // TODO: When refactoring : Always false, to be removed if (_dbgForceDisplayUpperRightBorder) drawUpperRightBorders(); } else { if (_techId != 0xFF) displayLargeMap(_mapPosX, _mapPosY); - + + // TODO: When refactoring : Always false, to be removed if (_dbgForceDisplayUpperRightBorder) drawUpperRightBorders(); } @@ -2465,7 +2468,7 @@ bool EfhEngine::handleDeathMenu() { _oldMapPosX = _mapPosX = 31; _oldMapPosY = _mapPosY = 31; _unkRelatedToAnimImageSetId = 0; - *_unkArray2C8AA = 0; + _unkArray2C8AA[0] = 0; found = true; break; case Common::KEYCODE_x: @@ -2681,7 +2684,7 @@ bool EfhEngine::moveMonsterGroupOther(int16 monsterId, int16 direction) { } bool EfhEngine::moveMonsterGroup(int16 monsterId) { - debug("moveMonsterGroup %d", monsterId); + debugC(2, kDebugEngine, "moveMonsterGroup %d", monsterId); int16 rand100 = getRandom(100); @@ -2696,7 +2699,7 @@ bool EfhEngine::moveMonsterGroup(int16 monsterId) { } int16 EfhEngine::computeMonsterGroupDistance(int16 monsterId) { - debug("computeMonsterGroupDistance %d", monsterId); + debugC(2, kDebugEngine, "computeMonsterGroupDistance %d", monsterId); int16 monsterPosX = _mapMonsters[monsterId]._posX; int16 monsterPosY = _mapMonsters[monsterId]._posY; @@ -4669,7 +4672,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { int16 var5C; if (unkFct_checkMonsterField8(groupId, true)) { sub1E028(groupId, 9, true); - *_unkArray2C8AA += 500; + _unkArray2C8AA[0] += 500; var5C = -1; } else var5C = 0; diff --git a/engines/efh/utils.cpp b/engines/efh/utils.cpp index 58721a564592..f7f152064f34 100644 --- a/engines/efh/utils.cpp +++ b/engines/efh/utils.cpp @@ -173,7 +173,7 @@ uint32 EfhEngine::uncompressBuffer(uint8 *compressedBuf, uint8 *destBuf) { int16 EfhEngine::getRandom(int16 maxVal) { debugC(1, kDebugUtils, "getRandom %d", maxVal); - if (maxVal == 0) + if (maxVal <= 0) return 0; return 1 + _rnd->getRandomNumber(maxVal - 1); From 73fabe7176a2bea09c0bb81647c89373564ec2fe Mon Sep 17 00:00:00 2001 From: Strangerke Date: Wed, 8 Jun 2022 22:06:34 +0100 Subject: [PATCH 144/412] EFH: Fix a bug in the fight system, change the type of an argument to bool --- engines/efh/efh.cpp | 10 +++++----- engines/efh/efh.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 523363f3c60f..20cca5a946c5 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -3566,7 +3566,7 @@ int16 EfhEngine::selectMonsterGroup() { return retVal; } -int16 EfhEngine::sub1C956(int16 charId, int16 unkFied18Val, int16 arg4) { +int16 EfhEngine::sub1C956(int16 charId, int16 unkFied18Val, bool arg4) { debug("sub1C956 %d %d %d", charId, unkFied18Val, arg4); int16 varE = -1; @@ -3606,8 +3606,8 @@ int16 EfhEngine::sub1C956(int16 charId, int16 unkFied18Val, int16 arg4) { else varE = selectMonsterGroup(); - if (arg4 == 0) { - if (varE == 27) + if (!arg4) { + if (varE == 27) // Esc varE = 0; } else if (varE != 27) { int16 monsterGroupDistance = computeMonsterGroupDistance(_teamMonsterIdArray[varE]); @@ -3615,7 +3615,7 @@ int16 EfhEngine::sub1C956(int16 charId, int16 unkFied18Val, int16 arg4) { varE = 27; } } - } while (varE != -1); + } while (varE == -1); if (varE == 27) varE = -1; @@ -6941,7 +6941,7 @@ void EfhEngine::setTextPos(int16 textPosX, int16 textPosY) { } void EfhEngine::copyCurrentPlaceToBuffer(int16 id) { - debug("copyCurrentPlaceToBuffer %d", id); + debugC(2, kDebugEngine, "copyCurrentPlaceToBuffer %d", id); // Note that 576 = 24 * 24 uint8 *placesPtr = &_places[576 * id]; diff --git a/engines/efh/efh.h b/engines/efh/efh.h index f67c48ce14a8..8e5490ca840e 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -374,7 +374,7 @@ class EfhEngine : public Engine { void sub1CDFA(); void redrawScreenForced(); int16 selectMonsterGroup(); - int16 sub1C956(int16 charId, int16 unkFied18Val, int16 arg4); + int16 sub1C956(int16 charId, int16 unkFied18Val, bool arg4); void sub1CAB6(int16 charId); bool sub1CB27(); void sub1BE9A(int16 monsterId); From d88b4bce4dcca22c7587fdb702682700b907b31c Mon Sep 17 00:00:00 2001 From: Strangerke Date: Thu, 9 Jun 2022 21:40:22 +0100 Subject: [PATCH 145/412] EFH: Add comments, fix a bug in handleFight_lastAction_A --- engines/efh/efh.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 20cca5a946c5..110d7a56075a 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -3495,7 +3495,7 @@ bool EfhEngine::isTeamMemberStatusNormal(int16 teamMemberId) { } void EfhEngine::sub1CDFA() { - debug("sub1CDFA"); + debug("sub1CDFA"); // Initiatives for (int16 counter = 0; counter < 3; ++counter) { if (_teamCharId[counter] != -1 && counter < _teamSize) { @@ -3649,24 +3649,24 @@ bool EfhEngine::sub1CB27() { drawCombatScreen(_teamCharId[counter1], false, true); Common::KeyCode var1 = handleAndMapInput(true); switch (var1) { - case Common::KEYCODE_a: + case Common::KEYCODE_a: // Attack _teamLastAction[counter1] = 'A'; _word3267A[counter1] = sub1C956(_teamCharId[counter1], 9, true); if (_word3267A[counter1] == -1) _teamLastAction[counter1] = 0; break; - case Common::KEYCODE_d: + case Common::KEYCODE_d: // Defend _teamLastAction[counter1] = 'D'; break; - case Common::KEYCODE_h: + case Common::KEYCODE_h: // Hide _teamLastAction[counter1] = 'H'; break; - case Common::KEYCODE_r: + case Common::KEYCODE_r: // Run for (int16 counter2 = 0; counter2 < _teamSize; ++counter2) { _teamLastAction[counter2] = 'R'; } return true; - case Common::KEYCODE_s: { + case Common::KEYCODE_s: { // Status int16 var8 = handleStatusMenu(2, _teamCharId[counter1]); sub1CAB6(_teamCharId[counter1]); if (var8 > 999) { @@ -3726,7 +3726,7 @@ bool EfhEngine::sub1CB27() { } break; - case Common::KEYCODE_t: + case Common::KEYCODE_t: // Terrain redrawScreenForced(); getInputBlocking(); drawCombatScreen(_teamCharId[counter1], false, true); @@ -4715,7 +4715,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { hitPoints = originalDamage + damagePointsAbsorbed; - if (checkSpecialItemsOnCurrentPlace(unk_monsterField5_itemId)) + if (!checkSpecialItemsOnCurrentPlace(unk_monsterField5_itemId)) var62 = 0; if (var62 > 0) { @@ -5033,7 +5033,7 @@ bool EfhEngine::handleFight(int16 monsterId) { int16 monsterGroupIdOrMonsterId = _stru3244C[counter]._field0; if (monsterGroupIdOrMonsterId == -1) continue; - if (monsterGroupIdOrMonsterId > 999) { + if (monsterGroupIdOrMonsterId > 999) { // Team Member monsterGroupIdOrMonsterId -= 1000; if (!isTeamMemberStatusNormal(monsterGroupIdOrMonsterId)) { handleFight_checkEndEffect(monsterGroupIdOrMonsterId); From 654b6ad17748828ea4d2f937f39ad87db4d10232 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Tue, 21 Jun 2022 00:22:40 +0100 Subject: [PATCH 146/412] EFH: some renaming, fix a debug message --- engines/efh/efh.cpp | 22 +++++++++++----------- engines/efh/efh.h | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 110d7a56075a..726be2fe7ce3 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -264,7 +264,7 @@ EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst) _unkArray2C8AA[i] = 0; _word32680[i] = 0; _word32482[i] = 0; - _word3267A[i] = -1; + _teamNextAttack[i] = -1; _word31780[i] = 0; _teamLastAction[i] = 0; } @@ -3417,7 +3417,7 @@ void EfhEngine::sub1BCA7(int16 monsterTeamId) { debug("sub1BCA7 %d", monsterTeamId); int16 counter = 0; - if (monsterTeamId != -1 && countPictureRef(monsterTeamId, false)) { + if (monsterTeamId != -1 && countPictureRef(monsterTeamId, false) > 0) { counter = 1; _teamMonsterIdArray[0] = monsterTeamId; } @@ -3651,8 +3651,8 @@ bool EfhEngine::sub1CB27() { switch (var1) { case Common::KEYCODE_a: // Attack _teamLastAction[counter1] = 'A'; - _word3267A[counter1] = sub1C956(_teamCharId[counter1], 9, true); - if (_word3267A[counter1] == -1) + _teamNextAttack[counter1] = sub1C956(_teamCharId[counter1], 9, true); + if (_teamNextAttack[counter1] == -1) _teamLastAction[counter1] = 0; break; case Common::KEYCODE_d: // Defend @@ -3689,7 +3689,7 @@ bool EfhEngine::sub1CB27() { case 10: case 12: case 13: - _word3267A[counter1] = sub1C956(_teamCharId[counter1], 9, false); + _teamNextAttack[counter1] = sub1C956(_teamCharId[counter1], 9, false); break; case 9: @@ -3704,13 +3704,13 @@ bool EfhEngine::sub1CB27() { case 29: case 30: sub1C219((uint8 *)"Select Character:", 3, 1, false); - _word3267A[counter1] = selectOtherCharFromTeam(); + _teamNextAttack[counter1] = selectOtherCharFromTeam(); break; case 16: case 17: case 26: - _word3267A[counter1] = 0xC8; + _teamNextAttack[counter1] = 0xC8; break; case 19: @@ -4639,7 +4639,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { int16 unk_monsterField5_itemId = sub1C80A(_teamCharId[teamCharId], 9, true); if (unk_monsterField5_itemId == 0x7FFF) unk_monsterField5_itemId = 0x3F; - int16 monsterGroupNumber = _word3267A[teamCharId]; + int16 monsterGroupNumber = _teamNextAttack[teamCharId]; if (monsterGroupNumber == 0x64) monsterGroupNumber = 0; @@ -5614,7 +5614,7 @@ void EfhEngine::sub18E80(int16 charId, int16 windowId, int16 menuId, int16 curMe } int16 EfhEngine::displayString_3(const char *str, bool animFl, int16 charId, int16 windowId, int16 menuId, int16 curMenuLine) { - debug("displayString_3 % %s %d %d %d %d", str, animFl ? "True" : "False", charId, windowId, menuId, curMenuLine); + debug("displayString_3 %s %s %d %d %d %d", str, animFl ? "True" : "False", charId, windowId, menuId, curMenuLine); int16 retVal = 0; @@ -5648,7 +5648,7 @@ bool EfhEngine::isItemCursed(int16 itemId) { } bool EfhEngine::hasObjectEquipped(int16 charId, int16 objectId) { - debug("hasObjectEquipped %d %d", charId, objectId); + debugC(6, kDebugEngine, "hasObjectEquipped %d %d", charId, objectId); if ((_npcBuf[charId]._inventory[objectId]._stat1 & 0x80) == 0) return false; @@ -5703,7 +5703,7 @@ void EfhEngine::sub1E028(int16 id, uint8 mask, int16 groupFl) { } bool EfhEngine::isMonsterActive(int16 groupId, int16 id) { - debug("isMonsterActive %d %d", groupId, id); + debugC(5, kDebugEngine, "isMonsterActive %d %d", groupId, id); if (_mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[id] > 0 && _stru32686[groupId]._field0[id] == 0) return true; diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 8e5490ca840e..fd289b17f1b1 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -577,7 +577,7 @@ class EfhEngine : public Engine { int16 _word2D0BA; int16 _word32680[3]; int16 _word32482[3]; - int16 _word3267A[3]; + int16 _teamNextAttack[3]; int16 _word31780[3]; int16 _word3273A[15]; From b8f84a33f5d17c8ce6f8b8a0dd372b581ba1019c Mon Sep 17 00:00:00 2001 From: Strangerke Date: Thu, 30 Jun 2022 22:33:04 +0100 Subject: [PATCH 147/412] EFH: Implement animFl in handleAndMapInput, fix a check in sub191FF, some renaming --- engines/efh/efh.cpp | 75 +++++++++++++++++++++---------------------- engines/efh/efh.h | 2 +- engines/efh/utils.cpp | 23 ++++++++++--- 3 files changed, 56 insertions(+), 44 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 726be2fe7ce3..abd0c4e35310 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -301,7 +301,7 @@ EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst) _ongoingFightFl = false; _statusMenuActive = false; _menuDepth = 0; - _word2D0BA = 0; + _menuItemCounter = 0; for (int i = 0; i < 15; ++i) { _word3273A[i] = 0; @@ -5336,7 +5336,7 @@ void EfhEngine::countRightWindowItems(int16 menuId, int16 charId) { int16 var2 = 0; int16 var4 = 0; - _word2D0BA = 0; + _menuItemCounter = 0; switch (menuId) { case 0: @@ -5361,20 +5361,20 @@ void EfhEngine::countRightWindowItems(int16 menuId, int16 charId) { break; default: // Case 8 + Default var4 = -1; - _word2D0BA = 0; + _menuItemCounter = 0; break; } if (var4 == -1) { for (int16 counter = 0; counter < 10; ++counter) { if (_npcBuf[charId]._inventory[counter]._ref != 0x7FFF) { - _word3273A[_word2D0BA++] = counter; + _word3273A[_menuItemCounter++] = counter; } } } else { for (int16 counter = var4; counter < var2; ++counter) { if (_npcBuf[charId]._activeScore[counter] != 0) { - _word3273A[_word2D0BA++] = counter; + _word3273A[_menuItemCounter++] = counter; } } } @@ -5434,7 +5434,7 @@ void EfhEngine::displayCharacterSummary(int16 curMenuLine, int16 npcId) { displayStringAtTextPos(buffer1); displayCenteredString("Inventory", 144, 310, 72); - if (_word2D0BA == 0) { + if (_menuItemCounter == 0) { if (curMenuLine != -1) setTextColorWhite(); @@ -5443,7 +5443,7 @@ void EfhEngine::displayCharacterSummary(int16 curMenuLine, int16 npcId) { return; } - for (int16 counter = 0; counter < _word2D0BA; ++counter) { + for (int16 counter = 0; counter < _menuItemCounter; ++counter) { if (_menuDepth == 0) setTextColorGrey(); else { @@ -5513,7 +5513,7 @@ void EfhEngine::displayCharacterInformationOrSkills(int16 curMenuLine, int16 cha setTextPos(146, 27); displayStringAtTextPos("Name: "); displayStringAtTextPos(buffer); - if (_word2D0BA <= 0) { + if (_menuItemCounter <= 0) { if (curMenuLine != -1) setTextColorWhite(); displayCenteredString("No Skills To Select", 144, 310, 96); @@ -5521,7 +5521,7 @@ void EfhEngine::displayCharacterInformationOrSkills(int16 curMenuLine, int16 cha return; } - for (int16 counter = 0; counter < _word2D0BA; ++counter) { + for (int16 counter = 0; counter < _menuItemCounter; ++counter) { if (counter == curMenuLine) setTextColorWhite(); int16 textPosY = 38 + counter * 9; @@ -5679,7 +5679,7 @@ void EfhEngine::sub191FF(int16 charId, int16 objectId, int16 windowId, int16 men int16 var2 = _items[itemId].field_18; if (var2 != 4) { for (int16 counter = 0; counter < 10; ++counter) { - if (var2 != _items[_npcBuf[charId]._inventory[counter]._ref].field_18) + if (var2 == _items[_npcBuf[charId]._inventory[counter]._ref].field_18) equipCursedItem(charId, objectId, windowId, menuId, curMenuLine); } } @@ -6317,7 +6317,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { debug("handleStatusMenu %d %d", gameMode, charId); int16 menuId = 9; - int16 var16 = -1; + int16 selectedLine = -1; int16 windowId = -1; int16 curMenuLine = -1; bool var10 = false; @@ -6341,10 +6341,8 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { if (_menuDepth == 0) { switch (var19) { case Common::KEYCODE_ESCAPE: - if (_menuDepth == 0) { // ?? Useless case ? - windowId = 8; - var19 = Common::KEYCODE_RETURN; - } + windowId = 8; + var19 = Common::KEYCODE_RETURN; break; case Common::KEYCODE_a: windowId = 7; @@ -6388,9 +6386,10 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { break; } } else if (_menuDepth == 1) { + // in the sub-menus, only a list of selectable items is displayed if (var19 >= Common::KEYCODE_a && var19 <= Common::KEYCODE_z) { int16 var8 = var19 - Common::KEYCODE_a; - if (var8 < _word2D0BA) { + if (var8 < _menuItemCounter) { curMenuLine = var8; var19 = Common::KEYCODE_RETURN; } @@ -6410,13 +6409,13 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { curMenuLine = 0; } } else if (_menuDepth == 1) { - if (_word2D0BA == 0) { + if (_menuItemCounter == 0) { _menuDepth = 0; curMenuLine = -1; menuId = 9; unk_StatusMenu(windowId, menuId, curMenuLine, charId, true, true); } else { - var16 = curMenuLine; + selectedLine = curMenuLine; var10 = true; } } @@ -6439,9 +6438,9 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { if (++windowId > 8) windowId = 0; } else if (_menuDepth == 1) { - if (_word2D0BA != 0) { + if (_menuItemCounter != 0) { ++curMenuLine; - if (curMenuLine > _word2D0BA - 1) + if (curMenuLine > _menuItemCounter - 1) curMenuLine = 0; } } @@ -6458,10 +6457,10 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { if (--windowId < 0) windowId = 8; } else if (_menuDepth == 1) { - if (_word2D0BA != 0) { + if (_menuItemCounter != 0) { --curMenuLine; if (curMenuLine < 0) - curMenuLine = _word2D0BA - 1; + curMenuLine = _menuItemCounter - 1; } } break; @@ -6482,7 +6481,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { int16 itemId; switch (menuId) { case 0: - objectId = _word3273A[var16]; + objectId = _word3273A[selectedLine]; itemId = _npcBuf[charId]._inventory[objectId]._ref; sub191FF(charId, objectId, windowId, menuId, curMenuLine); if (gameMode == 2) { @@ -6492,23 +6491,23 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { } break; case 1: - objectId = _word3273A[var16]; + objectId = _word3273A[selectedLine]; itemId = _npcBuf[charId]._inventory[objectId]._ref; if (gameMode == 2) { restoreAnimImageSetId(); _statusMenuActive = false; return objectId; - } else { - if (sub22293(_mapPosX, _mapPosY, charId, itemId, 2, -1)) { - _statusMenuActive = false; - return -1; - } else { - sub19E2E(charId, objectId, windowId, menuId, curMenuLine, 2); - } } + + if (sub22293(_mapPosX, _mapPosY, charId, itemId, 2, -1)) { + _statusMenuActive = false; + return -1; + } + + sub19E2E(charId, objectId, windowId, menuId, curMenuLine, 2); break; case 2: - objectId = _word3273A[var16]; + objectId = _word3273A[selectedLine]; itemId = _npcBuf[charId]._inventory[objectId]._ref; if (hasObjectEquipped(charId, objectId) && isItemCursed(itemId)) { displayString_3("The item is cursed! IT IS EVIL!!!!!!!!", true, charId, windowId, menuId, curMenuLine); @@ -6534,7 +6533,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { break; case 3: - objectId = _word3273A[var16]; + objectId = _word3273A[selectedLine]; itemId = _npcBuf[charId]._inventory[objectId]._ref; if (hasObjectEquipped(charId, objectId) && isItemCursed(itemId)) { displayString_3("The item is cursed! IT IS EVIL!!!!!!!!", true, charId, windowId, menuId, curMenuLine); @@ -6592,7 +6591,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { } break; case 4: - objectId = _word3273A[var16]; + objectId = _word3273A[selectedLine]; itemId = _npcBuf[charId]._inventory[objectId]._ref; if (hasObjectEquipped(charId, objectId) && isItemCursed(itemId)) { displayString_3("The item is cursed! IT IS EVIL!!!!!!!!", true, charId, windowId, menuId, curMenuLine); @@ -6619,7 +6618,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { } break; case 5: - objectId = _word3273A[var16]; + objectId = _word3273A[selectedLine]; if (gameMode == 2) { displayString_3("Not a Combat Option!", true, charId, windowId, menuId, curMenuLine); } else { @@ -6631,7 +6630,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { } break; case 6: // Identical to case 5? - objectId = _word3273A[var16]; + objectId = _word3273A[selectedLine]; if (gameMode == 2) { displayString_3("Not a Combat Option!", true, charId, windowId, menuId, curMenuLine); } else { @@ -6643,7 +6642,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { } break; case 7: // Identical to case 5? - objectId = _word3273A[var16]; + objectId = _word3273A[selectedLine]; if (gameMode == 2) { displayString_3("Not a Combat Option!", true, charId, windowId, menuId, curMenuLine); } else { @@ -6662,7 +6661,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { var10 = false; _menuDepth = 0; menuId = 9; - var16 = -1; + selectedLine = -1; curMenuLine = -1; } diff --git a/engines/efh/efh.h b/engines/efh/efh.h index fd289b17f1b1..aeabc75f3175 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -574,7 +574,7 @@ class EfhEngine : public Engine { bool _ongoingFightFl; bool _statusMenuActive; int16 _menuDepth; - int16 _word2D0BA; + int16 _menuItemCounter; int16 _word32680[3]; int16 _word32482[3]; int16 _teamNextAttack[3]; diff --git a/engines/efh/utils.cpp b/engines/efh/utils.cpp index f7f152064f34..ee23a0679e72 100644 --- a/engines/efh/utils.cpp +++ b/engines/efh/utils.cpp @@ -270,12 +270,25 @@ Common::KeyCode EfhEngine::handleAndMapInput(bool animFl) { Common::Event event; _system->getEventManager()->pollEvent(event); Common::KeyCode retVal = Common::KEYCODE_INVALID; - if (event.type == Common::EVENT_KEYUP) { - retVal = event.kbd.keycode; - } - if (animFl) { - warning("STUB - handleAndMapInput - animFl"); + uint32 lastMs = _system->getMillis(); + while (retVal == Common::KEYCODE_INVALID) { + _system->getEventManager()->pollEvent(event); + + if (event.type == Common::EVENT_KEYUP) { + retVal = event.kbd.keycode; + } + + if (animFl) { + _system->delayMillis(20); + uint32 newMs = _system->getMillis(); + + if (newMs - lastMs >= 200) { + lastMs = newMs; + unkFct_anim(); + } + } else + break; } return retVal; } From 36a6700abf89fc8d992e6486ec7110890f0e0caf Mon Sep 17 00:00:00 2001 From: Strangerke Date: Fri, 1 Jul 2022 00:04:37 +0100 Subject: [PATCH 148/412] EFH: Fix bug in combat system --- engines/efh/efh.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index abd0c4e35310..4d510eee043f 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -3801,7 +3801,7 @@ void EfhEngine::sub1BE9A(int16 monsterId) { if (!var6) continue; - if (var2 > computeMonsterGroupDistance(counter1)) + if (computeMonsterGroupDistance(counter1) > var2) continue; if (sub1BC74(counter1, var4)) From 43d189fd566dedc1a2ae8a6036ba265a933e97a2 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Fri, 1 Jul 2022 23:15:54 +0100 Subject: [PATCH 149/412] EFH: Fix typo in the message about armor effect --- engines/efh/efh.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 4d510eee043f..79526ad33883 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -5195,7 +5195,7 @@ bool EfhEngine::handleFight(int16 monsterId) { if (damagePointsAbsorbed <= 1) sprintf(buffer, " %s%s's armor absorbs 1 point!", _characterNamePt1, _characterNamePt2); else - sprintf(buffer, " %s%s',27h,'s armor absorbs %d points!", _characterNamePt1, _characterNamePt2, damagePointsAbsorbed); + sprintf(buffer, " %s%s's armor absorbs %d points!", _characterNamePt1, _characterNamePt2, damagePointsAbsorbed); strcat((char *)_messageToBePrinted, buffer); varInt = (originalDamage + damagePointsAbsorbed) / 10; From c4c96555b48001f8f0f19c2729d1ffeb038c69af Mon Sep 17 00:00:00 2001 From: Strangerke Date: Tue, 8 Nov 2022 21:56:02 +0100 Subject: [PATCH 150/412] EFH: Add stubs for sound generation --- engines/efh/efh.cpp | 56 ++++++++++++++++++++++++++++++++++++++++++++- engines/efh/efh.h | 6 +++++ 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 79526ad33883..fa7445db21fc 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -836,6 +836,9 @@ void EfhEngine::loadNPCS() { Common::KeyCode EfhEngine::playSong(uint8 *buffer) { warning("STUB: playSong"); + + + _system->delayMillis(1000); return Common::KEYCODE_INVALID; @@ -4162,8 +4165,59 @@ bool EfhEngine::checkSpecialItemsOnCurrentPlace(int16 itemId) { } } +void EfhEngine::generateSound1(int arg0, int arg2, int duration) { + warning("STUB: generateSound1 %d %d %d", arg0, arg2, duration); +} + +void EfhEngine::generateSound2(int startFreq, int endFreq, int arg4) { + warning("STUB: generateSound2 %d %d %d", startFreq, endFreq, arg4); + + // Arg4 doesn't seem to be used. +} + +void EfhEngine::generateSound3() { + warning("STUB: generateSound3"); +} + +void EfhEngine::generateSound4(int arg0) { + warning("STUB: generateSound4 %d", arg0); +} + +void EfhEngine::generateSound5(int arg0) { + warning("STUB: generateSound5 %d", arg0); +} + void EfhEngine::generateSound(int16 soundType) { - warning("STUB: generateSound"); + switch (soundType) { + case 5: + generateSound3(); + break; + case 9: + generateSound1(20, 888, 3000); + generateSound1(20, 888, 3000); + break; + case 10: + generateSound5(1); + break; + case 13: + generateSound2(256, 4096, 18); + break; + case 14: + generateSound2(20, 400, 100); + break; + case 15: + generateSound2(100, 888, 88); + break; + case 16: + generateSound1(2000, 6096, 1500); + break; + case 17: + generateSound4(1); + break; + default: + // Not implemented because not used by the engine + break; + } } void EfhEngine::genericGenerateSound(int16 soundType, int16 repeatCount) { diff --git a/engines/efh/efh.h b/engines/efh/efh.h index aeabc75f3175..40307895f4c7 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -387,6 +387,11 @@ class EfhEngine : public Engine { int16 sub1DEC8(int16 groupNumber); int16 getCharacterScore(int16 charId, int16 itemId); bool checkSpecialItemsOnCurrentPlace(int16 itemId); + void generateSound1(int arg0, int arg2, int duration); + void generateSound2(int startFreq, int endFreq, int arg4); + void generateSound3(); + void generateSound4(int arg0); + void generateSound5(int arg0); void generateSound(int16 soundType); void genericGenerateSound(int16 soundType, int16 repeatCount); bool hasAdequateDefense(int16 monsterId, uint8 attackType); @@ -585,6 +590,7 @@ class EfhEngine : public Engine { Stru3244C _stru3244C[8]; }; + } // End of namespace Efh #endif From 7f2c54998323c6db150aac50c7ec1cbf769e15d5 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Thu, 10 Nov 2022 00:41:47 +0100 Subject: [PATCH 151/412] EFH: Fix compilation --- engines/efh/detection.cpp | 6 +- engines/efh/efh.cpp | 494 ++++++++++++++++++++------------------ 2 files changed, 263 insertions(+), 237 deletions(-) diff --git a/engines/efh/detection.cpp b/engines/efh/detection.cpp index 439f8c54b4dc..e58602b5e1c5 100644 --- a/engines/efh/detection.cpp +++ b/engines/efh/detection.cpp @@ -69,12 +69,12 @@ class EfhMetaEngineDetection : public AdvancedMetaEngineDetection { EfhMetaEngineDetection() : AdvancedMetaEngineDetection(gameDescriptions, sizeof(EfhGameDescription), efhGames) { } - const char *getEngineId() const override { - return "efh"; + const char *getEngineName() const override { + return "Efh"; } const char *getName() const override { - return "Efh"; + return "efh"; } const char *getOriginalCopyright() const override { diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index fa7445db21fc..a63e613305ed 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -1330,11 +1330,11 @@ void EfhEngine::displayLowStatusScreen(bool flag) { copyString(_npcBuf[charId]._name, buffer); setTextPos(16, textPosY); displayStringAtTextPos(buffer); - sprintf(buffer, "%d", getEquipmentDefense(charId, false)); + snprintf(buffer, 80, "%d", getEquipmentDefense(charId, false)); displayCenteredString(buffer, 104, 128, textPosY); - sprintf(buffer, "%d", _npcBuf[charId]._hitPoints); + snprintf(buffer, 80, "%d", _npcBuf[charId]._hitPoints); displayCenteredString(buffer, 144, 176, textPosY); - sprintf(buffer, "%d", _npcBuf[charId]._maxHP); + snprintf(buffer, 80, "%d", _npcBuf[charId]._maxHP); displayCenteredString(buffer, 192, 224, textPosY); if (_npcBuf[charId]._hitPoints <= 0) { @@ -1346,19 +1346,19 @@ void EfhEngine::displayLowStatusScreen(bool flag) { case 0: { uint16 var4 = sub1C80A(charId, 9, true); if (var4 == 0x7FFF) - strcpy(_nameBuffer, "(NONE)"); + strncpy(_nameBuffer, "(NONE)", 20); else copyString(_items[var4]._name, _nameBuffer); } break; case 1: - strcpy(_nameBuffer, "* ASLEEP *"); + strncpy(_nameBuffer, "* ASLEEP *", 20); break; case 2: - strcpy(_nameBuffer, "* FROZEN *"); + strncpy(_nameBuffer, "* FROZEN *", 20); break; default: - strcpy(_nameBuffer, "* DISABLED *"); + strncpy(_nameBuffer, "* DISABLED *", 20); break; } @@ -1667,15 +1667,15 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int16 posX, int16 posY, int16 displayStringAtTextPos(curLine); *curLine = 0; - strcpy(curLine, nextWord); - strcat(curLine, " "); + strncpy(curLine, nextWord, 80); + strncat(curLine, " ",2); ++curLineNb; setTextPos(posX, posY + curLineNb * 9); curWordPos = 0; } } else { - strcat(curLine, nextWord); - strcat(curLine, " "); + strncat(curLine, nextWord, 80); + strncat(curLine, " ", 2); curWordPos = 0; } ++buffer; @@ -1967,7 +1967,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int16 posX, int16 posY, int16 } else { copyString(_npcBuf[_teamCharId[counter]]._name, _enemyNamePt2); copyString(_items[var110]._name, _nameBuffer); - sprintf(curLine, "%s finds a %s!", _enemyNamePt2, _nameBuffer); + snprintf(curLine, 150, "%s finds a %s!", _enemyNamePt2, _nameBuffer); drawMapWindow(); displayFctFullScreen(); drawMapWindow(); @@ -3120,7 +3120,7 @@ bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { displayMonsterAnim(monsterId); copyString(_npcBuf[var58]._name, _enemyNamePt2); copyString(_npcBuf[_teamCharId[counter]]._name, _characterNamePt2); - sprintf(buffer, "%s asks that %s leave your party.", _enemyNamePt2, _characterNamePt2); + snprintf(buffer, 80, "%s asks that %s leave your party.", _enemyNamePt2, _characterNamePt2); for (int16 i = 0; i < 2; ++i) { clearBottomTextZone(0); _textColor = 0xE; @@ -3894,12 +3894,12 @@ void EfhEngine::sub1C4CA(bool whiteFl) { setTextPos(129, textPosY); char buffer[80]; - sprintf(buffer, "%c)", 'A' + counter); + snprintf(buffer, 80, "%c)", 'A' + counter); displayStringAtTextPos(buffer); setTextColorRed(); int16 var1 = _mapMonsters[_teamMonsterIdArray[counter]]._possessivePronounSHL6 & 0x3F; if (var1 <= 0x3D) { - sprintf(buffer, "%d %s", var6E, kEncounters[_mapMonsters[_teamMonsterIdArray[counter]]._monsterRef]._name); + snprintf(buffer, 80, "%d %s", var6E, kEncounters[_mapMonsters[_teamMonsterIdArray[counter]]._monsterRef]._name); displayStringAtTextPos(buffer); if (var6E > 1) displayStringAtTextPos("s"); @@ -3945,7 +3945,7 @@ void EfhEngine::displayCombatMenu(int16 charId) { char buffer[80]; copyString(_npcBuf[charId]._name, buffer); - strcat(buffer, ":"); + strncat(buffer, ":", 2); setTextColorWhite(); setTextPos(144, 7); displayStringAtTextPos(buffer); @@ -4008,7 +4008,7 @@ void EfhEngine::handleFight_checkEndEffect(int16 charId) { // At this point : The status is different to 0 (normal) and the effect duration is finally 0 (end of effect) copyString(_npcBuf[_teamCharId[charId]]._name, _enemyNamePt2); if ((_npcBuf[_teamCharId[charId]]._possessivePronounSHL6 >> 6) == 2) { - strcpy(_enemyNamePt1, "The "); + strncpy(_enemyNamePt1, "The ", 5); } else { _enemyNamePt1[0] = 0; } @@ -4016,13 +4016,13 @@ void EfhEngine::handleFight_checkEndEffect(int16 charId) { // End of effect message depends on the type of effect switch (_teamCharStatus[charId]._status) { case 1: - sprintf((char *)_messageToBePrinted, "%s%s wakes up!", _enemyNamePt1, _enemyNamePt2); + snprintf((char *)_messageToBePrinted, 400, "%s%s wakes up!", _enemyNamePt1, _enemyNamePt2); break; case 2: - sprintf((char *)_messageToBePrinted, "%s%s thaws out!", _enemyNamePt1, _enemyNamePt2); + snprintf((char *)_messageToBePrinted, 400, "%s%s thaws out!", _enemyNamePt1, _enemyNamePt2); break; default: - sprintf((char *)_messageToBePrinted, "%s%s recovers!", _enemyNamePt1, _enemyNamePt2); + snprintf((char *)_messageToBePrinted, 400, "%s%s recovers!", _enemyNamePt1, _enemyNamePt2); break; } @@ -4334,70 +4334,80 @@ void EfhEngine::getDeathTypeDescription(int16 attackerId, int16 victimId) { int16 rndDescrForDeathType = getRandom((3)) - 1; char buffer[80]; memset(buffer, 0, 80); - sprintf(buffer, "DUDE IS TOAST!"); + snprintf(buffer, 80, "DUDE IS TOAST!"); switch (deathType) { case 0: switch (rndDescrForDeathType) { case 0: - sprintf(buffer, ", killing %s!", kPersonal[possessivePronoun]); + snprintf(buffer, 80, ", killing %s!", kPersonal[possessivePronoun]); break; case 1: - sprintf(buffer, ", slaughtering %s!", kPersonal[possessivePronoun]); + snprintf(buffer, 80, ", slaughtering %s!", kPersonal[possessivePronoun]); break; case 2: - sprintf(buffer, ", annihilating %s!", kPersonal[possessivePronoun]); + snprintf(buffer, 80, ", annihilating %s!", kPersonal[possessivePronoun]); + break; + default: break; } break; case 1: switch (rndDescrForDeathType) { case 0: - sprintf(buffer, ", cutting %s in two!", kPersonal[possessivePronoun]); + snprintf(buffer, 80, ", cutting %s in two!", kPersonal[possessivePronoun]); break; case 1: - sprintf(buffer, ", dicing %s into small cubes!", kPersonal[possessivePronoun]); + snprintf(buffer, 80, ", dicing %s into small cubes!", kPersonal[possessivePronoun]); break; case 2: - sprintf(buffer, ", butchering %s into lamb chops!", kPersonal[possessivePronoun]); + snprintf(buffer, 80, ", butchering %s into lamb chops!", kPersonal[possessivePronoun]); + break; + default: break; } break; case 2: switch (rndDescrForDeathType) { case 0: - sprintf(buffer, ", piercing %s heart!", kPersonal[possessivePronoun]); + snprintf(buffer, 80, ", piercing %s heart!", kPersonal[possessivePronoun]); break; case 1: - sprintf(buffer, ", leaving %s a spouting mass of blood!", kPersonal[possessivePronoun]); + snprintf(buffer, 80, ", leaving %s a spouting mass of blood!", kPersonal[possessivePronoun]); break; case 2: - sprintf(buffer, ", popping %s like a zit!", kPersonal[possessivePronoun]); + snprintf(buffer, 80, ", popping %s like a zit!", kPersonal[possessivePronoun]); + break; + default: break; } break; case 3: switch (rndDescrForDeathType) { case 0: - sprintf(buffer, ", pulping %s head over a wide area!", kPersonal[possessivePronoun]); + snprintf(buffer, 80, ", pulping %s head over a wide area!", kPersonal[possessivePronoun]); break; case 1: - sprintf(buffer, ", smashing %s into a meat patty!", kPersonal[possessivePronoun]); + snprintf(buffer, 80, ", smashing %s into a meat patty!", kPersonal[possessivePronoun]); break; case 2: - sprintf(buffer, ", squashing %s like a ripe tomato!", kPersonal[possessivePronoun]); + snprintf(buffer, 80, ", squashing %s like a ripe tomato!", kPersonal[possessivePronoun]); + break; + default: break; } break; case 4: switch (rndDescrForDeathType) { case 0: - sprintf(buffer, ", totally incinerating %s!", kPersonal[possessivePronoun]); + snprintf(buffer, 80, ", totally incinerating %s!", kPersonal[possessivePronoun]); break; case 1: - sprintf(buffer, ", reducing %s to a pile of ash!", kPersonal[possessivePronoun]); + snprintf(buffer, 80, ", reducing %s to a pile of ash!", kPersonal[possessivePronoun]); break; case 2: - sprintf(buffer, ", leaving a blistered mass of flesh behind!"); + snprintf(buffer, 80, ", leaving a blistered mass of flesh behind!"); + break; + default: break; } break; @@ -4405,52 +4415,60 @@ void EfhEngine::getDeathTypeDescription(int16 attackerId, int16 victimId) { switch (rndDescrForDeathType) { case 0: // The original has a typo: popscicle - sprintf(buffer, ", turning %s into a popsicle!", kPersonal[possessivePronoun]); + snprintf(buffer, 80, ", turning %s into a popsicle!", kPersonal[possessivePronoun]); break; case 1: - sprintf(buffer, ", encasing %s in a block of ice!", kPersonal[possessivePronoun]); + snprintf(buffer, 80, ", encasing %s in a block of ice!", kPersonal[possessivePronoun]); break; case 2: - sprintf(buffer, ", shattering %s into shards!", kPersonal[possessivePronoun]); + snprintf(buffer, 80, ", shattering %s into shards!", kPersonal[possessivePronoun]); + break; + default: break; } break; case 6: switch (rndDescrForDeathType) { case 0: - sprintf(buffer, ", leaving pudding for brains"); + snprintf(buffer, 80, ", leaving pudding for brains"); break; case 1: - sprintf(buffer, ", bursting %s head like a bubble!", kPersonal[possessivePronoun]); + snprintf(buffer, 80, ", bursting %s head like a bubble!", kPersonal[possessivePronoun]); break; case 2: - sprintf(buffer, ", turning %s into a mindless vegetable", kPersonal[possessivePronoun]); + snprintf(buffer, 80, ", turning %s into a mindless vegetable", kPersonal[possessivePronoun]); + break; + default: break; } break; case 7: switch (rndDescrForDeathType) { case 0: - sprintf(buffer, ", reducing %s to an oozing pile of flesh!", kPersonal[possessivePronoun]); + snprintf(buffer, 80, ", reducing %s to an oozing pile of flesh!", kPersonal[possessivePronoun]); break; case 1: - sprintf(buffer, ", melting %s like an ice cube in hot coffee!", kPersonal[possessivePronoun]); + snprintf(buffer, 80, ", melting %s like an ice cube in hot coffee!", kPersonal[possessivePronoun]); break; case 2: - sprintf(buffer, ", vaporizing %s into a steaming cloud!", kPersonal[possessivePronoun]); + snprintf(buffer, 80, ", vaporizing %s into a steaming cloud!", kPersonal[possessivePronoun]); + break; + default: break; } break; case 8: switch (rndDescrForDeathType) { case 0: - sprintf(buffer, ", engulfing %s in black smoke puffs!", kPersonal[possessivePronoun]); + snprintf(buffer, 80, ", engulfing %s in black smoke puffs!", kPersonal[possessivePronoun]); break; case 1: - sprintf(buffer, ", sucking %s into eternity!", kPersonal[possessivePronoun]); + snprintf(buffer, 80, ", sucking %s into eternity!", kPersonal[possessivePronoun]); break; case 2: - sprintf(buffer, ", turning %s into a mindless zombie!", kPersonal[possessivePronoun]); + snprintf(buffer, 80, ", turning %s into a mindless zombie!", kPersonal[possessivePronoun]); + break; + default: break; } break; @@ -4459,13 +4477,15 @@ void EfhEngine::getDeathTypeDescription(int16 attackerId, int16 victimId) { case 11: switch (rndDescrForDeathType) { case 0: - sprintf(buffer, ", completely disintegrating %s!", kPersonal[possessivePronoun]); + snprintf(buffer, 80, ", completely disintegrating %s!", kPersonal[possessivePronoun]); break; case 1: - sprintf(buffer, ", spreading %s into a fine mist!", kPersonal[possessivePronoun]); + snprintf(buffer, 80, ", spreading %s into a fine mist!", kPersonal[possessivePronoun]); break; case 2: - sprintf(buffer, ", leaving a smoking crater in %s place!", kPersonal[possessivePronoun]); + snprintf(buffer, 80, ", leaving a smoking crater in %s place!", kPersonal[possessivePronoun]); + break; + default: break; } break; @@ -4474,39 +4494,45 @@ void EfhEngine::getDeathTypeDescription(int16 attackerId, int16 victimId) { case 14: switch (rndDescrForDeathType) { case 0: - sprintf(buffer, ", tearing a chunk out of %s back!", kPersonal[possessivePronoun]); + snprintf(buffer, 80, ", tearing a chunk out of %s back!", kPersonal[possessivePronoun]); break; case 1: - sprintf(buffer, ", blowing %s brains out!", kPersonal[possessivePronoun]); + snprintf(buffer, 80, ", blowing %s brains out!", kPersonal[possessivePronoun]); break; case 2: - sprintf(buffer, ", exploding %s entire chest!", kPersonal[possessivePronoun]); + snprintf(buffer, 80, ", exploding %s entire chest!", kPersonal[possessivePronoun]); + break; + default: break; } break; case 15: switch (rndDescrForDeathType) { case 0: - sprintf(buffer, ", choking %s to death!", kPersonal[possessivePronoun]); + snprintf(buffer, 80, ", choking %s to death!", kPersonal[possessivePronoun]); break; case 1: - sprintf(buffer, ", melting %s lungs!", kPersonal[possessivePronoun]); + snprintf(buffer, 80, ", melting %s lungs!", kPersonal[possessivePronoun]); break; case 2: - sprintf(buffer, ", leaving %s gasping for air as %s collapses!", kPersonal[possessivePronoun], kPersonal[possessivePronoun]); + snprintf(buffer, 80, ", leaving %s gasping for air as %s collapses!", kPersonal[possessivePronoun], kPersonal[possessivePronoun]); + break; + default: break; } break; case 16: switch (rndDescrForDeathType) { case 0: - sprintf(buffer, ", tearing a chunk out of %s back!", kPersonal[possessivePronoun]); + snprintf(buffer, 80, ", tearing a chunk out of %s back!", kPersonal[possessivePronoun]); break; case 1: - sprintf(buffer, ", piercing %s heart!", kPersonal[possessivePronoun]); + snprintf(buffer, 80, ", piercing %s heart!", kPersonal[possessivePronoun]); break; case 2: - sprintf(buffer, ", impaling %s brain!", kPersonal[possessivePronoun]); + snprintf(buffer, 80, ", impaling %s brain!", kPersonal[possessivePronoun]); + break; + default: break; } break; @@ -4514,7 +4540,7 @@ void EfhEngine::getDeathTypeDescription(int16 attackerId, int16 victimId) { break; } - strcat((char *)_messageToBePrinted, buffer); + strncat((char *)_messageToBePrinted, buffer, 80); } bool EfhEngine::characterSearchesMonsterCorpse(int16 charId, int16 monsterId) { @@ -4535,8 +4561,8 @@ bool EfhEngine::characterSearchesMonsterCorpse(int16 charId, int16 monsterId) { char tmpString[20]; copyString(_items[itemId]._name, tmpString); char buffer[80]; - sprintf(buffer, " and finds a %s!", tmpString); - strcat((char *)_messageToBePrinted, buffer); + snprintf(buffer, 80, " and finds a %s!", tmpString); + strncat((char *)_messageToBePrinted, buffer, 80); return true; } @@ -4546,7 +4572,7 @@ void EfhEngine::getXPAndSearchCorpse(int16 charId, char *namePt1, char *namePt2, int16 xpLevel = getXPLevel(_npcBuf[charId]._xp); _npcBuf[charId]._xp += kEncounters[_mapMonsters[monsterId]._monsterRef]._xpGiven; char buffer[80]; - sprintf(buffer, " %s%s gains %d experience", namePt1, namePt2, kEncounters[_mapMonsters[monsterId]._monsterRef]._xpGiven); + snprintf(buffer, 80, " %s%s gains %d experience", namePt1, namePt2, kEncounters[_mapMonsters[monsterId]._monsterRef]._xpGiven); if (getXPLevel(_npcBuf[charId]._xp) > xpLevel) { generateSound(15); int16 var2 = getRandom(20) + getRandom(_npcBuf[charId]._infoScore[4]); @@ -4558,9 +4584,9 @@ void EfhEngine::getXPAndSearchCorpse(int16 charId, char *namePt1, char *namePt2, _npcBuf[charId]._infoScore[3] += getRandom(3) - 1; _npcBuf[charId]._infoScore[4] += getRandom(3) - 1; } - strcat((char *)_messageToBePrinted, buffer); + strncat((char *)_messageToBePrinted, buffer, 80); if (!characterSearchesMonsterCorpse(charId, monsterId)) - strcat((char *)_messageToBePrinted, "!"); + strncat((char *)_messageToBePrinted, "!", 2); } @@ -4575,13 +4601,13 @@ void EfhEngine::addReactionText(int16 id) { case 0: switch (rand3) { case 1: - sprintf(buffer, " %s%s reels from the blow!", _characterNamePt1, _characterNamePt2); + snprintf(buffer, 80, " %s%s reels from the blow!", _characterNamePt1, _characterNamePt2); break; case 2: - sprintf(buffer, " %s%s sways from the attack!", _characterNamePt1, _characterNamePt2); + snprintf(buffer, 80, " %s%s sways from the attack!", _characterNamePt1, _characterNamePt2); break; case 3: - sprintf(buffer, " %s%s looks dazed!", _characterNamePt1, _characterNamePt2); + snprintf(buffer, 80, " %s%s looks dazed!", _characterNamePt1, _characterNamePt2); break; default: break; @@ -4590,13 +4616,13 @@ void EfhEngine::addReactionText(int16 id) { case 1: switch (rand3) { case 1: - sprintf(buffer, " %s%s cries out in agony!", _characterNamePt1, _characterNamePt2); + snprintf(buffer, 80, " %s%s cries out in agony!", _characterNamePt1, _characterNamePt2); break; case 2: - sprintf(buffer, " %s%s screams from the abuse!", _characterNamePt1, _characterNamePt2); + snprintf(buffer, 80, " %s%s screams from the abuse!", _characterNamePt1, _characterNamePt2); break; case 3: - sprintf(buffer, " %s%s wails terribly!", _characterNamePt1, _characterNamePt2); + snprintf(buffer, 80, " %s%s wails terribly!", _characterNamePt1, _characterNamePt2); break; default: break; @@ -4605,13 +4631,13 @@ void EfhEngine::addReactionText(int16 id) { case 2: switch (rand3) { case 1: - sprintf(buffer, " %s%s is staggering!", _characterNamePt1, _characterNamePt2); + snprintf(buffer, 80, " %s%s is staggering!", _characterNamePt1, _characterNamePt2); break; case 2: - sprintf(buffer, " %s%s falters for a moment!", _characterNamePt1, _characterNamePt2); + snprintf(buffer, 80, " %s%s falters for a moment!", _characterNamePt1, _characterNamePt2); break; case 3: - sprintf(buffer, " %s%s is stumbling about!", _characterNamePt1, _characterNamePt2); + snprintf(buffer, 80, " %s%s is stumbling about!", _characterNamePt1, _characterNamePt2); break; default: break; @@ -4620,13 +4646,13 @@ void EfhEngine::addReactionText(int16 id) { case 3: switch (rand3) { case 1: - sprintf(buffer, " %s%s winces from the pain!", _characterNamePt1, _characterNamePt2); + snprintf(buffer, 80, " %s%s winces from the pain!", _characterNamePt1, _characterNamePt2); break; case 2: - sprintf(buffer, " %s%s cringes from the damage!", _characterNamePt1, _characterNamePt2); + snprintf(buffer, 80, " %s%s cringes from the damage!", _characterNamePt1, _characterNamePt2); break; case 3: - sprintf(buffer, " %s%s shrinks from the wound!", _characterNamePt1, _characterNamePt2); + snprintf(buffer, 80, " %s%s shrinks from the wound!", _characterNamePt1, _characterNamePt2); break; default: break; @@ -4635,13 +4661,13 @@ void EfhEngine::addReactionText(int16 id) { case 4: switch (rand3) { case 1: - sprintf(buffer, " %s%s screams!", _characterNamePt1, _characterNamePt2); + snprintf(buffer, 80, " %s%s screams!", _characterNamePt1, _characterNamePt2); break; case 2: - sprintf(buffer, " %s%s bellows!", _characterNamePt1, _characterNamePt2); + snprintf(buffer, 80, " %s%s bellows!", _characterNamePt1, _characterNamePt2); break; case 3: - sprintf(buffer, " %s%s shrills!", _characterNamePt1, _characterNamePt2); + snprintf(buffer, 80, " %s%s shrills!", _characterNamePt1, _characterNamePt2); break; default: break; @@ -4650,13 +4676,13 @@ void EfhEngine::addReactionText(int16 id) { case 5: switch (rand3) { case 1: - sprintf(buffer, " %s%s chortles!", _characterNamePt1, _characterNamePt2); + snprintf(buffer, 80, " %s%s chortles!", _characterNamePt1, _characterNamePt2); break; case 2: - sprintf(buffer, " %s%s seems amused!", _characterNamePt1, _characterNamePt2); + snprintf(buffer, 80, " %s%s seems amused!", _characterNamePt1, _characterNamePt2); break; case 3: - sprintf(buffer, " %s%s looks concerned!", _characterNamePt1, _characterNamePt2); + snprintf(buffer, 80, " %s%s looks concerned!", _characterNamePt1, _characterNamePt2); break; default: break; @@ -4665,13 +4691,13 @@ void EfhEngine::addReactionText(int16 id) { case 6: switch (rand3) { case 1: - sprintf(buffer, " %s%s laughs at the feeble attack!", _characterNamePt1, _characterNamePt2); + snprintf(buffer, 80, " %s%s laughs at the feeble attack!", _characterNamePt1, _characterNamePt2); break; case 2: - sprintf(buffer, " %s%s smiles at the pathetic attack!", _characterNamePt1, _characterNamePt2); + snprintf(buffer, 80, " %s%s smiles at the pathetic attack!", _characterNamePt1, _characterNamePt2); break; case 3: - sprintf(buffer, " %s%s laughs at the ineffective assault!", _characterNamePt1, _characterNamePt2); + snprintf(buffer, 80, " %s%s laughs at the ineffective assault!", _characterNamePt1, _characterNamePt2); break; default: break; @@ -4681,7 +4707,7 @@ void EfhEngine::addReactionText(int16 id) { break; } - strcat((char *)_messageToBePrinted, buffer); + strncat((char *)_messageToBePrinted, buffer, 80); } void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { @@ -4775,7 +4801,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { if (var62 > 0) { _mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] -= originalDamage; if (var62 > 1) { - sprintf(_attackBuffer, "%d times ", var62); + snprintf(_attackBuffer, 20, "%d times ", var62); } else { *_attackBuffer = 0; } @@ -4783,41 +4809,41 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { int16 var68 = _items[unk_monsterField5_itemId]._attackType + 1; int16 var6A = getRandom(3) - 1; if (var5E == 2) { - strcpy(_characterNamePt1, "The "); + strncpy(_characterNamePt1, "The ", 5); } else { *_characterNamePt1 = 0; } if (var70 == 2) { - strcpy(_enemyNamePt1, "The "); + strncpy(_enemyNamePt1, "The ", 5); } else { *_enemyNamePt1 = 0; } - strcpy(_characterNamePt2, kEncounters[_mapMonsters[_teamMonsterIdArray[groupId]]._monsterRef]._name); + strncpy(_characterNamePt2, kEncounters[_mapMonsters[_teamMonsterIdArray[groupId]]._monsterRef]._name, 14); copyString(_npcBuf[_teamCharId[teamCharId]]._name, _enemyNamePt2); copyString(_items[unk_monsterField5_itemId]._name, _nameBuffer); if (checkSpecialItemsOnCurrentPlace(unk_monsterField5_itemId)) { // Action A - Check damages - Start if (var62 == 0) { - sprintf((char *)_messageToBePrinted, "%s%s %s at %s%s with %s %s, but misses!", _enemyNamePt1, _enemyNamePt2, kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2, kPossessive[var70], _nameBuffer); + snprintf((char *)_messageToBePrinted, 400, "%s%s %s at %s%s with %s %s, but misses!", _enemyNamePt1, _enemyNamePt2, kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2, kPossessive[var70], _nameBuffer); } else if (hitPoints <= 0){ - sprintf((char *)_messageToBePrinted, "%s%s %s %s%s %swith %s %s, but does no damage!", _enemyNamePt1, _enemyNamePt2, kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2, _attackBuffer, kPossessive[var70], _nameBuffer); + snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s, but does no damage!", _enemyNamePt1, _enemyNamePt2, kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2, _attackBuffer, kPossessive[var70], _nameBuffer); } else if (hitPoints == 1) { - sprintf((char *)_messageToBePrinted, "%s%s %s %s%s %swith %s %s for 1 point", _enemyNamePt1, _enemyNamePt2, kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2, _attackBuffer, kPossessive[var70], _nameBuffer); + snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s for 1 point", _enemyNamePt1, _enemyNamePt2, kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2, _attackBuffer, kPossessive[var70], _nameBuffer); if (_mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] <= 0) { getDeathTypeDescription(groupId, teamCharId + 1000); getXPAndSearchCorpse(_teamCharId[teamCharId], _enemyNamePt1, _enemyNamePt2, _teamMonsterIdArray[groupId]); } else { - strcat((char *)_messageToBePrinted, "!"); + strncat((char *)_messageToBePrinted, "!", 2); } } else { - sprintf((char *)_messageToBePrinted, "%s%s %s %s%s %swith %s %s for %d points", _enemyNamePt1, _enemyNamePt2, kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2, _attackBuffer, kPossessive[var70], _nameBuffer, hitPoints); + snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s for %d points", _enemyNamePt1, _enemyNamePt2, kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2, _attackBuffer, kPossessive[var70], _nameBuffer, hitPoints); if (_mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] <= 0) { getDeathTypeDescription(groupId, teamCharId + 1000); getXPAndSearchCorpse(_teamCharId[teamCharId], _enemyNamePt1, _enemyNamePt2, _teamMonsterIdArray[groupId]); } else { - strcat((char *)_messageToBePrinted, "!"); + strncat((char *)_messageToBePrinted, "!", 2); } } // Action A - Check damages - End @@ -4848,16 +4874,16 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { char buffer[80]; memset(buffer, 0, 80); if (damagePointsAbsorbed <= 1) - sprintf(buffer, " %s%s's armor absorbs 1 point!", _characterNamePt1, _characterNamePt2); + snprintf(buffer, 80, " %s%s's armor absorbs 1 point!", _characterNamePt1, _characterNamePt2); else - sprintf(buffer, " %s%s',27h,'s armor absorbs %d points!", _characterNamePt1, _characterNamePt2, damagePointsAbsorbed); + snprintf(buffer, 80, " %s%s',27h,'s armor absorbs %d points!", _characterNamePt1, _characterNamePt2, damagePointsAbsorbed); - strcat((char *)_messageToBePrinted, buffer); + strncat((char *)_messageToBePrinted, buffer, 80); } // Action A - Add armor absorb text - End if (var5C) - strcat((char *)_messageToBePrinted, " Your actions do not go un-noticed..."); + strncat((char *)_messageToBePrinted, " Your actions do not go un-noticed...", 400); // Action A - Check item durability - Start varInt = _teamCharId[teamCharId]; @@ -4868,8 +4894,8 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { if (var51 <= 0) { char buffer[80]; memset(buffer, 0, 80); - sprintf(buffer, " * %s%s's %s breaks!", _enemyNamePt1, _enemyNamePt2, _nameBuffer); - strcat((char *)_messageToBePrinted, buffer); + snprintf(buffer, 80, " * %s%s's %s breaks!", _enemyNamePt1, _enemyNamePt2, _nameBuffer); + strncat((char *)_messageToBePrinted, buffer, 80); setCharacterObjectToBroken(varInt, var64); var6E = false; } else { @@ -4885,20 +4911,20 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { _stru32686[var7E]._field2[groupId] = getRandom(10); char buffer[80]; memset(buffer, 0, 80); - sprintf(buffer, " %s%s falls asleep!", _characterNamePt1, _characterNamePt2); - strcat((char *)_messageToBePrinted, buffer); + snprintf(buffer, 80, " %s%s falls asleep!", _characterNamePt1, _characterNamePt2); + strncat((char *)_messageToBePrinted, buffer, 80); } } else if (_items[unk_monsterField5_itemId].field_16 == 2 && _mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] > 0) { _stru32686[var7E]._field0[groupId] = 2; _stru32686[var7E]._field2[groupId] = getRandom(10); char buffer[80]; memset(buffer, 0, 80); - sprintf(buffer, " %s%s is frozen!", _characterNamePt1, _characterNamePt2); - strcat((char *)_messageToBePrinted, buffer); + snprintf(buffer, 80, " %s%s is frozen!", _characterNamePt1, _characterNamePt2); + strncat((char *)_messageToBePrinted, buffer, 80); } // Action A - Check effect - End } else { - sprintf((char *)_messageToBePrinted, "%s%s tries to use %s %s, but it doesn't work!", _enemyNamePt1, _enemyNamePt2, kPossessive[var70], _nameBuffer); + snprintf((char *)_messageToBePrinted, 400, "%s%s tries to use %s %s, but it doesn't work!", _enemyNamePt1, _enemyNamePt2, kPossessive[var70], _nameBuffer); } genericGenerateSound(_items[unk_monsterField5_itemId]._attackType, var62); @@ -4917,11 +4943,11 @@ void EfhEngine::handleFight_lastAction_D(int16 teamCharId) { int16 var70 = _npcBuf[_teamCharId[teamCharId]]._possessivePronounSHL6 >> 6; if (var70 == 2) - strcpy(_enemyNamePt1, "The "); + strncpy(_enemyNamePt1, "The ", 5); else *_enemyNamePt1 = 0; - sprintf((char *)_messageToBePrinted, "%s%s prepares to defend %sself!", _enemyNamePt1, _enemyNamePt2, kPersonal[var70]); + snprintf((char *)_messageToBePrinted, 400, "%s%s prepares to defend %sself!", _enemyNamePt1, _enemyNamePt2, kPersonal[var70]); sub1C219(_messageToBePrinted, 1, 2, true); } @@ -4936,11 +4962,11 @@ void EfhEngine::handleFight_lastAction_H(int16 teamCharId) { int16 var70 = _npcBuf[_teamCharId[teamCharId]]._possessivePronounSHL6 >> 6; if (var70 == 2) - strcpy(_enemyNamePt1, "The "); + strncpy(_enemyNamePt1, "The ", 5); else *_enemyNamePt1 = 0; - sprintf((char *)_messageToBePrinted, "%s%s attempts to hide %sself!", _enemyNamePt1, _enemyNamePt2, kPersonal[var70]); + snprintf((char *)_messageToBePrinted, 400, "%s%s attempts to hide %sself!", _enemyNamePt1, _enemyNamePt2, kPersonal[var70]); sub1C219(_messageToBePrinted, 1, 2, true); } @@ -4954,11 +4980,11 @@ void EfhEngine::handleFight_lastAction_U(int16 teamCharId) { copyString(_items[unk_monsterField5_itemId]._name, _nameBuffer); int16 var70 = _npcBuf[_teamCharId[teamCharId]]._possessivePronounSHL6 >> 6; if (var70 == 2) - strcpy(_enemyNamePt1, "The "); + strncpy(_enemyNamePt1, "The ", 5); else *_enemyNamePt1 = 0; - sprintf((char *)_messageToBePrinted, "%s%s uses %s %s! ", _enemyNamePt1, _enemyNamePt2, kPossessive[var70], _nameBuffer); + snprintf((char *)_messageToBePrinted, 400, "%s%s uses %s %s! ", _enemyNamePt1, _enemyNamePt2, kPossessive[var70], _nameBuffer); sub1C219(_messageToBePrinted, 1, 2, true); } @@ -5006,12 +5032,12 @@ void EfhEngine::sub1D8C2(int16 charId, int16 damage) { if (var42 == 0) { var42 = 1; - sprintf(buffer, ", but %s %s", kPossessive[var40], buffer2); - strcat((char *)_messageToBePrinted, buffer); + snprintf(buffer, 40, ", but %s %s", kPossessive[var40], buffer2); + strncat((char *)_messageToBePrinted, buffer, 40); } else { ++var42; - sprintf(buffer, ", %s", buffer2); - strcat((char *)_messageToBePrinted, buffer); + snprintf(buffer, 40, ", %s", buffer2); + strncat((char *)_messageToBePrinted, buffer, 40); } } @@ -5020,11 +5046,11 @@ void EfhEngine::sub1D8C2(int16 charId, int16 damage) { } if (var42 == 0) { - strcat((char *)_messageToBePrinted, "!"); + strncat((char *)_messageToBePrinted, "!", 2); } else if (var42 > 1 || getFightMessageLastCharacter((char *)_messageToBePrinted) == 's' || getFightMessageLastCharacter((char *)_messageToBePrinted) == 'S') { - strcat((char *)_messageToBePrinted, " are destroyed!"); + strncat((char *)_messageToBePrinted, " are destroyed!", 17); } else { - strcat((char *)_messageToBePrinted, " is destroyed!"); + strncat((char *)_messageToBePrinted, " is destroyed!", 16); } } @@ -5180,7 +5206,7 @@ bool EfhEngine::handleFight(int16 monsterId) { if (var62 > 0) { _npcBuf[_teamCharId[var7E]]._hitPoints -= originalDamage; if (var62 > 1) - sprintf(_attackBuffer, "%d times ", var62); + snprintf(_attackBuffer, 20, "%d times ", var62); else *_attackBuffer = 0; } @@ -5188,36 +5214,36 @@ bool EfhEngine::handleFight(int16 monsterId) { int16 var68 = _items[unk_monsterField5_itemId]._attackType + 1; int16 var6A = getRandom(3); if (var5E == 2) - sprintf(_characterNamePt1, "The "); + snprintf(_characterNamePt1, 5, "The "); else *_characterNamePt1 = 0; if (var7E == 2) - sprintf(_enemyNamePt1, "The "); + snprintf(_enemyNamePt1, 5, "The "); else *_enemyNamePt1 = 0; - strcpy(_enemyNamePt2, kEncounters[_mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._monsterRef]._name); + strncpy(_enemyNamePt2, kEncounters[_mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._monsterRef]._name, 20); copyString(_npcBuf[_teamCharId[var7E]]._name, _characterNamePt2); copyString(_items[unk_monsterField5_itemId]._name, _nameBuffer); if (checkSpecialItemsOnCurrentPlace(unk_monsterField5_itemId)) { // handleFight - check damages - Start if (var62 == 0) { - sprintf((char *)_messageToBePrinted, "%s%s %s at %s%s with %s %s, but misses!", _enemyNamePt1, _enemyNamePt2, kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2, kPossessive[var70], _nameBuffer); + snprintf((char *)_messageToBePrinted, 400, "%s%s %s at %s%s with %s %s, but misses!", _enemyNamePt1, _enemyNamePt2, kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2, kPossessive[var70], _nameBuffer); } else if (hitPoints <= 0) { - sprintf((char *)_messageToBePrinted, "%s%s %s %s%s %swith %s %s, but does no damage!", _enemyNamePt1, _enemyNamePt2, kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2, _attackBuffer, kPossessive[var70], _nameBuffer); + snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s, but does no damage!", _enemyNamePt1, _enemyNamePt2, kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2, _attackBuffer, kPossessive[var70], _nameBuffer); } else if (hitPoints == 1) { - sprintf((char *)_messageToBePrinted, "%s%s %s %s%s %swith %s %s for 1 point", _enemyNamePt1, _enemyNamePt2, kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2, _attackBuffer, kPossessive[var70], _nameBuffer); + snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s for 1 point", _enemyNamePt1, _enemyNamePt2, kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2, _attackBuffer, kPossessive[var70], _nameBuffer); if (_npcBuf[_teamCharId[var7E]]._hitPoints <= 0) getDeathTypeDescription(var7E + 1000, monsterGroupIdOrMonsterId); else - strcat((char *)_messageToBePrinted, "!"); + strncat((char *)_messageToBePrinted, "!", 2); } else { - sprintf((char *)_messageToBePrinted, "%s%s %s %s%s %swith %s %s for %d points", _enemyNamePt1, _enemyNamePt2, kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2, _attackBuffer, kPossessive[var70], _nameBuffer, hitPoints); + snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s for %d points", _enemyNamePt1, _enemyNamePt2, kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2, _attackBuffer, kPossessive[var70], _nameBuffer, hitPoints); if (_npcBuf[_teamCharId[var7E]]._hitPoints <= 0) getDeathTypeDescription(var7E + 1000, monsterGroupIdOrMonsterId); else - strcat((char *)_messageToBePrinted, "!"); + strncat((char *)_messageToBePrinted, "!", 2); } // handleFight - check damages - End @@ -5247,11 +5273,11 @@ bool EfhEngine::handleFight(int16 monsterId) { char buffer[80]; memset(buffer, 0, 80); if (damagePointsAbsorbed <= 1) - sprintf(buffer, " %s%s's armor absorbs 1 point!", _characterNamePt1, _characterNamePt2); + snprintf(buffer, 80, " %s%s's armor absorbs 1 point!", _characterNamePt1, _characterNamePt2); else - sprintf(buffer, " %s%s's armor absorbs %d points!", _characterNamePt1, _characterNamePt2, damagePointsAbsorbed); + snprintf(buffer, 80, " %s%s's armor absorbs %d points!", _characterNamePt1, _characterNamePt2, damagePointsAbsorbed); - strcat((char *)_messageToBePrinted, buffer); + strncat((char *)_messageToBePrinted, buffer, 80); varInt = (originalDamage + damagePointsAbsorbed) / 10; sub1D8C2(_teamCharId[var7E], varInt); } @@ -5265,23 +5291,23 @@ bool EfhEngine::handleFight(int16 monsterId) { if (getRandom(100) < 20) { _teamCharStatus[var7E]._status = 1; _teamCharStatus[var7E]._duration = getRandom(10); - sprintf(buffer, " %s%s falls asleep!", _characterNamePt1, _characterNamePt2); - strcat((char *)_messageToBePrinted, buffer); + snprintf(buffer, 80, " %s%s falls asleep!", _characterNamePt1, _characterNamePt2); + strncat((char *)_messageToBePrinted, buffer, 80); } break; case 2: if (getRandom(100) < 20) { _teamCharStatus[var7E]._status = 2; _teamCharStatus[var7E]._duration = getRandom(10); - sprintf(buffer, " %s%s is frozen!", _characterNamePt1, _characterNamePt2); - strcat((char *)_messageToBePrinted, buffer); + snprintf(buffer, 80, " %s%s is frozen!", _characterNamePt1, _characterNamePt2); + strncat((char *)_messageToBePrinted, buffer, 80); } break; case 5: case 6: if (getRandom(100) < 20) { - sprintf(buffer, " %s%s's life energy is gone!", _characterNamePt1, _characterNamePt2); - strcat((char *)_messageToBePrinted, buffer); + snprintf(buffer, 80, " %s%s's life energy is gone!", _characterNamePt1, _characterNamePt2); + strncat((char *)_messageToBePrinted, buffer, 80); _npcBuf[_teamCharId[var7E]]._hitPoints = 0; } break; @@ -5290,7 +5316,7 @@ bool EfhEngine::handleFight(int16 monsterId) { } // handleFight - Check effect - end } else { - sprintf((char *)_messageToBePrinted, "%s%s tries to use %s %s, but it doesn't work!", _enemyNamePt1, _enemyNamePt2, kPossessive[var70], _nameBuffer); + snprintf((char *)_messageToBePrinted, 400, "%s%s tries to use %s %s, but it doesn't work!", _enemyNamePt1, _enemyNamePt2, kPossessive[var70], _nameBuffer); } genericGenerateSound(_items[unk_monsterField5_itemId]._attackType, var62); sub1C219(_messageToBePrinted, 1, 2, true); @@ -5300,22 +5326,22 @@ bool EfhEngine::handleFight(int16 monsterId) { } else if (_mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._pictureRef[var86] > 0 && _stru32686[monsterGroupIdOrMonsterId]._field0[var86]) { --_stru32686[monsterGroupIdOrMonsterId]._field2[var86]; if (_stru32686[monsterGroupIdOrMonsterId]._field2[var86] <= 0) { - strcpy(_enemyNamePt2, kEncounters[_mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._monsterRef]._name); + strncpy(_enemyNamePt2, kEncounters[_mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._monsterRef]._name, 20); int16 var70 = kEncounters[_mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._monsterRef]._nameArticle; if (var70 == 2) - strcpy(_enemyNamePt1, "The "); + strncpy(_enemyNamePt1, "The ", 5); else *_enemyNamePt1 = 0; switch (_stru32686[monsterGroupIdOrMonsterId]._field0[var86]) { case 1: - sprintf((char *)_messageToBePrinted, "%s%s wakes up!", _enemyNamePt1, _enemyNamePt2); + snprintf((char *)_messageToBePrinted, 400, "%s%s wakes up!", _enemyNamePt1, _enemyNamePt2); break; case 2: - sprintf((char *)_messageToBePrinted, "%s%s thaws out!", _enemyNamePt1, _enemyNamePt2); + snprintf((char *)_messageToBePrinted, 400, "%s%s thaws out!", _enemyNamePt1, _enemyNamePt2); break; default: - sprintf((char *)_messageToBePrinted, "%s%s recovers!", _enemyNamePt1, _enemyNamePt2); + snprintf((char *)_messageToBePrinted, 400, "%s%s recovers!", _enemyNamePt1, _enemyNamePt2); break; } _stru32686[monsterGroupIdOrMonsterId]._field0[var86] = 0; @@ -5349,7 +5375,7 @@ void EfhEngine::displayMenuItemString(int16 menuBoxId, int16 thisBoxId, int16 mi else setTextColorGrey(); - sprintf(buffer, "> %s <", str); + snprintf(buffer, 20,"> %s <", str); displayCenteredString(buffer, minX, maxX, minY); setTextColorRed(); } else { @@ -5468,22 +5494,22 @@ void EfhEngine::displayCharacterSummary(int16 curMenuLine, int16 npcId) { setTextPos(146, 27); displayStringAtTextPos("Name: "); displayStringAtTextPos(buffer1); - sprintf(buffer1, "Level: %d", getXPLevel(_npcBuf[npcId]._xp)); + snprintf(buffer1, 40, "Level: %d", getXPLevel(_npcBuf[npcId]._xp)); setTextPos(146, 36); displayStringAtTextPos(buffer1); - sprintf(buffer1, "XP: %lu", _npcBuf[npcId]._xp); + snprintf(buffer1, 40, "XP: %lu", _npcBuf[npcId]._xp); setTextPos(227, 36); displayStringAtTextPos(buffer1); - sprintf(buffer1, "Speed: %d", _npcBuf[npcId]._speed); + snprintf(buffer1, 40, "Speed: %d", _npcBuf[npcId]._speed); setTextPos(146, 45); displayStringAtTextPos(buffer1); - sprintf(buffer1, "Defense: %d", getEquipmentDefense(npcId, false)); + snprintf(buffer1, 40, "Defense: %d", getEquipmentDefense(npcId, false)); setTextPos(146, 54); displayStringAtTextPos(buffer1); - sprintf(buffer1, "Hit Points: %d", _npcBuf[npcId]._hitPoints); + snprintf(buffer1, 40, "Hit Points: %d", _npcBuf[npcId]._hitPoints); setTextPos(146, 63); displayStringAtTextPos(buffer1); - sprintf(buffer1, "Max HP: %d", _npcBuf[npcId]._maxHP); + snprintf(buffer1, 40, "Max HP: %d", _npcBuf[npcId]._maxHP); setTextPos(227, 63); displayStringAtTextPos(buffer1); displayCenteredString("Inventory", 144, 310, 72); @@ -5515,16 +5541,16 @@ void EfhEngine::displayCharacterSummary(int16 curMenuLine, int16 npcId) { setTextPos(152, textPosY); if (counter == curMenuLine) { - sprintf(buffer1, "%c>", 'A' + counter); + snprintf(buffer1, 40, "%c>", 'A' + counter); } else { - sprintf(buffer1, "%c)", 'A' + counter); + snprintf(buffer1, 40, "%c)", 'A' + counter); } displayStringAtTextPos(buffer1); if (itemId != 0x7FFF) { setTextPos(168, textPosY); copyString(_items[itemId]._name, buffer2); - sprintf(buffer1, " %s", buffer2); + snprintf(buffer1, 40, " %s", buffer2); displayStringAtTextPos(buffer1); setTextPos(262, textPosY); @@ -5534,7 +5560,7 @@ void EfhEngine::displayCharacterSummary(int16 curMenuLine, int16 npcId) { // useless? var54 = _items[_npcBuf[npcId]._inventory[_word3273A[counter]]._ref]._defense; } else { - sprintf(buffer1, "%d", 1 + var54 / 8); + snprintf(buffer1, 40, "%d", 1 + var54 / 8); displayStringAtTextPos(buffer1); setTextPos(286, textPosY); displayStringAtTextPos("Def"); @@ -5542,7 +5568,7 @@ void EfhEngine::displayCharacterSummary(int16 curMenuLine, int16 npcId) { } else if (_items[itemId]._uses != 0x7F) { int16 var52 = _npcBuf[npcId]._inventory[_word3273A[counter]]._stat1; if (var52 != 0x7F) { - sprintf(buffer1, "%d", var52); + snprintf(buffer1, 40, "%d", var52); displayStringAtTextPos(buffer1); setTextPos(286, textPosY); if (var52 == 1) @@ -5581,15 +5607,15 @@ void EfhEngine::displayCharacterInformationOrSkills(int16 curMenuLine, int16 cha int16 textPosY = 38 + counter * 9; setTextPos(146, textPosY); if (counter == curMenuLine) { - sprintf(buffer, "%c>", 'A' + counter); + snprintf(buffer, 40, "%c>", 'A' + counter); } else { - sprintf(buffer, "%c)", 'A' + counter); + snprintf(buffer, 40, "%c)", 'A' + counter); } displayStringAtTextPos(buffer); setTextPos(163, textPosY); displayStringAtTextPos(kSkillArray[_word3273A[counter]]); - sprintf(buffer, "%d", _npcBuf[charId]._activeScore[_word3273A[counter]]); + snprintf(buffer, 40, "%d", _npcBuf[charId]._activeScore[_word3273A[counter]]); setTextPos(278, textPosY); displayStringAtTextPos(buffer); setTextColorRed(); @@ -5812,7 +5838,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me displayString_3("The item emits a low droning hum...", false, charId, windowId, menuId, curMenuLine); } else { int16 victims = 0; - strcat((char *)_messageToBePrinted, " The item emits a low droning hum..."); + strncat((char *)_messageToBePrinted, " The item emits a low droning hum...", 400); if (getRandom(100) < 50) { for (int16 counter = 0; counter < 9; ++counter) { if (isMonsterActive(windowId, counter)) { @@ -5837,11 +5863,11 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me } // The original was duplicating this code in each branch of the previous random check. if (victims > 1) { - sprintf(buffer1, "%d %ss fall asleep!", victims, kEncounters[_mapMonsters[_teamMonsterIdArray[windowId]]._monsterRef]._name); + snprintf(buffer1, 80, "%d %ss fall asleep!", victims, kEncounters[_mapMonsters[_teamMonsterIdArray[windowId]]._monsterRef]._name); } else { - sprintf(buffer1, "%d %s falls asleep!", victims, kEncounters[_mapMonsters[_teamMonsterIdArray[windowId]]._monsterRef]._name); + snprintf(buffer1, 80, "%d %s falls asleep!", victims, kEncounters[_mapMonsters[_teamMonsterIdArray[windowId]]._monsterRef]._name); } - strcat((char *)_messageToBePrinted, buffer1); + strncat((char *)_messageToBePrinted, buffer1, 400); } varA6 = true; @@ -5850,7 +5876,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me if (argA == 2) { displayString_3("The item grows very cold for a moment...", false, charId, windowId, menuId, curMenuLine); } else { - strcat((char *)_messageToBePrinted, " The item emits a blue beam..."); + strncat((char *)_messageToBePrinted, " The item emits a blue beam...", 400); int16 victim = 0; if (getRandom(100) < 50) { for (int16 varA8 = 0; varA8 < 9; ++varA8) { @@ -5877,11 +5903,11 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me // : This part is only present in the original in the case < 50, but for me // it's missing in the other case as there's an effect (frozen enemies) but no feedback to the player if (victim > 1) { - sprintf(buffer1, "%d %ss are frozen in place!", victim, kEncounters[_mapMonsters[_teamMonsterIdArray[windowId]]._monsterRef]._name); + snprintf(buffer1, 80, "%d %ss are frozen in place!", victim, kEncounters[_mapMonsters[_teamMonsterIdArray[windowId]]._monsterRef]._name); } else { - sprintf(buffer1, "%d %s is frozen in place!", victim, kEncounters[_mapMonsters[_teamMonsterIdArray[windowId]]._monsterRef]._name); + snprintf(buffer1, 80, "%d %s is frozen in place!", victim, kEncounters[_mapMonsters[_teamMonsterIdArray[windowId]]._monsterRef]._name); } - strcat((char *)_messageToBePrinted, buffer1); + strncat((char *)_messageToBePrinted, buffer1, 80); // } @@ -5891,7 +5917,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me if (argA == 2) { displayString_3("A serene feeling passes through the air...", false, charId, windowId, menuId, curMenuLine); } else { - strcat((char *)_messageToBePrinted, " The combat pauses...as there is a moment of forgiveness..."); + strncat((char *)_messageToBePrinted, " The combat pauses...as there is a moment of forgiveness...", 400); _unkArray2C8AA[0] = 0; } @@ -5901,7 +5927,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me if (argA == 2) { displayString_3("A dark sense fills your soul...then fades!", false, charId, windowId, menuId, curMenuLine); } else { - strcat((char *)_messageToBePrinted, " A dark gray fiery whirlwind surrounds the poor victim...the power fades and death abounds!"); + strncat((char *)_messageToBePrinted, " A dark gray fiery whirlwind surrounds the poor victim...the power fades and death abounds!", 400); if (getRandom(100) < 50) { for (int16 counter = 0; counter < 9; ++counter) { if (getRandom(100) < 50) { @@ -5926,12 +5952,12 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me displayString_3("A dark sense fills your soul...then fades!", false, charId, windowId, menuId, curMenuLine); } else { if (getRandom(100) < 50) { - strcat((char *)_messageToBePrinted, " A dark fiery whirlwind surrounds the poor victim...the power fades and all targeted die!"); + strncat((char *)_messageToBePrinted, " A dark fiery whirlwind surrounds the poor victim...the power fades and all targeted die!", 400); for (int16 counter = 0; counter < 9; ++counter) { _mapMonsters[_teamMonsterIdArray[windowId]]._pictureRef[counter] = 0; } } else { - strcat((char *)_messageToBePrinted, " A dark fiery whirlwind surrounds the poor victim...the power fades and one victim dies!"); + strncat((char *)_messageToBePrinted, " A dark fiery whirlwind surrounds the poor victim...the power fades and one victim dies!", 400); for (int16 counter = 0; counter < 9; ++counter) { if (isMonsterActive(windowId, counter)) { _mapMonsters[_teamMonsterIdArray[windowId]]._pictureRef[counter] = 0; @@ -5946,7 +5972,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me if (argA == 2) { displayString_3("There is no apparent affect!", false, charId, windowId, menuId, curMenuLine); } else { - strcat((char *)_messageToBePrinted, " The magic sparkles brilliant hues in the air!"); + strncat((char *)_messageToBePrinted, " The magic sparkles brilliant hues in the air!", 400); sub1E028(windowId, _items[itemId].field17_attackTypeDefense, true); } varA6 = true; @@ -5961,11 +5987,11 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me } if (varAA != 0x1B) { - strcpy(buffer1, " The magic makes the user as quick and agile as a bird!"); + strncpy(buffer1, " The magic makes the user as quick and agile as a bird!", 80); if (argA == 2) { displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); } else { - strcat((char *)_messageToBePrinted, buffer1); + strncat((char *)_messageToBePrinted, buffer1, 80); } _word32482[varAA] -= 50; if (_word32482[varAA] < 0) @@ -5985,11 +6011,11 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me } if (teamCharId != 0x1B) { - strcpy(buffer1, " The magic makes the user invisible!"); + strncpy(buffer1, " The magic makes the user invisible!", 80); if (argA == 2) { displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); } else { - strcat((char *)_messageToBePrinted, buffer1); + strncat((char *)_messageToBePrinted, buffer1, 80); } _word32680[teamCharId] -= 50; @@ -6009,29 +6035,29 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me if (_tileFact[varAE]._field0 == 0) { totalPartyKill(); - strcpy(buffer1, "The entire party vanishes in a flash... only to appear in stone !"); + strncpy(buffer1, "The entire party vanishes in a flash... only to appear in stone !", 80); if (argA == 2) { displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); } else { - strcat((char *)_messageToBePrinted, buffer1); + strncat((char *)_messageToBePrinted, buffer1, 80); retVal = true; } // emptyFunction(2); } else { if (varAE == 0 || varAE == 0x48) { - strcpy(buffer1, "The entire party vanishes in a flash...but re-appears, as if nothing happened!"); + strncpy(buffer1, "The entire party vanishes in a flash...but re-appears, as if nothing happened!", 80); if (argA == 2) { displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); } else { - strcat((char *)_messageToBePrinted, buffer1); + strncat((char *)_messageToBePrinted, buffer1, 80); retVal = true; } } else { - strcpy(buffer1, "The entire party vanishes in a flash...only to appear elsewhere!"); + strncpy(buffer1, "The entire party vanishes in a flash...only to appear elsewhere!", 80); if (argA == 2) { displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); } else { - strcat((char *)_messageToBePrinted, buffer1); + strncat((char *)_messageToBePrinted, buffer1, 80); retVal = true; } } @@ -6046,29 +6072,29 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me int16 varAE = sub15538(_mapPosX, _mapPosY); if (_tileFact[varAE]._field0 == 0) { totalPartyKill(); - strcpy(buffer1, "The entire party vanishes in a flash... only to appear in stone !"); + strncpy(buffer1, "The entire party vanishes in a flash... only to appear in stone !", 80); if (argA == 2) { displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); } else { - strcat((char *)_messageToBePrinted, buffer1); + strncat((char *)_messageToBePrinted, buffer1, 80); retVal = true; } // emptyFunction(2); } else { if (varAE == 0 || varAE == 0x48) { - strcpy(buffer1, "The entire party vanishes in a flash...but re-appears, as if nothing happened!"); + strncpy(buffer1, "The entire party vanishes in a flash...but re-appears, as if nothing happened!", 80); if (argA == 2) { displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); } else { - strcat((char *)_messageToBePrinted, buffer1); + strncat((char *)_messageToBePrinted, buffer1, 80); retVal = true; } } else { - strcpy(buffer1, "The entire party vanishes in a flash...only to appear elsewhere!"); + strncpy(buffer1, "The entire party vanishes in a flash...only to appear elsewhere!",80); if (argA == 2) { displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); } else { - strcat((char *)_messageToBePrinted, buffer1); + strncat((char *)_messageToBePrinted, buffer1, 80); retVal = true; } } @@ -6084,11 +6110,11 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me int16 teamCharId = windowId; if (teamCharId != 0x1B) { if (_teamCharStatus[teamCharId]._status == 2) { // frozen - strcat((char *)_messageToBePrinted, " The item makes a loud noise, awakening the character!"); + strncat((char *)_messageToBePrinted, " The item makes a loud noise, awakening the character!", 80); _teamCharStatus[teamCharId]._status = 0; _teamCharStatus[teamCharId]._duration = 0; } else { - strcat((char *)_messageToBePrinted, " The item makes a loud noise, but has no effect!"); + strncat((char *)_messageToBePrinted, " The item makes a loud noise, but has no effect!", 80); } } } @@ -6096,48 +6122,48 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me varA6 = true; break; case 19: // "Junk" - strcpy(buffer1, " * The item breaks!"); + strncpy(buffer1, " * The item breaks!", 80); if (argA == 2) { displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); } else { - strcat((char *)_messageToBePrinted, buffer1); + strncat((char *)_messageToBePrinted, buffer1, 80); } setCharacterObjectToBroken(charId, objectId); varA6 = true; break; case 23: // "Divining Rod" copyString(_items[itemId]._name, buffer2); - sprintf(buffer1, "The %s says, '", buffer2); + snprintf(buffer1, 80, "The %s says, '", buffer2); if (_items[itemId].field_19 < _mapPosX) { if (_items[itemId].field_1A < _mapPosY) { - strcat(buffer1, "North West!"); + strncat(buffer1, "North West!", 80); } else if (_items[itemId].field_1A > _mapPosY) { - strcat(buffer1, "South West!"); + strncat(buffer1, "South West!", 80); } else { - strcat(buffer1, "West!"); + strncat(buffer1, "West!", 80); } } else if (_items[itemId].field_19 > _mapPosX) { if (_items[itemId].field_1A < _mapPosY) { - strcat(buffer1, "North East!"); + strncat(buffer1, "North East!", 80); } else if (_items[itemId].field_1A > _mapPosY) { - strcat(buffer1, "South East!"); + strncat(buffer1, "South East!", 80); } else { - strcat(buffer1, "East!"); + strncat(buffer1, "East!", 80); } } else { // equals _mapPosX if (_items[itemId].field_1A < _mapPosY) { - strcat(buffer1, "North!"); + strncat(buffer1, "North!", 80); } else if (_items[itemId].field_1A > _mapPosY) { - strcat(buffer1, "South!"); + strncat(buffer1, "South!", 80); } else { - strcat(buffer1, "Here!!!"); + strncat(buffer1, "Here!!!",80); } } - strcat(buffer1, "'"); + strncat(buffer1, "'", 2); if (argA == 2) { displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); } else { - strcat((char *)_messageToBePrinted, buffer1); + strncat((char *)_messageToBePrinted, buffer1, 80); retVal = true; } @@ -6159,14 +6185,14 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me _npcBuf[_teamCharId[teamCharId]]._activeScore[varAE] = 20; } if (effectPoints > 1) - sprintf(buffer1, "%s increased %d points!", kSkillArray[varAE], effectPoints); + snprintf(buffer1, 80, "%s increased %d points!", kSkillArray[varAE], effectPoints); else - sprintf(buffer1, "%s increased 1 point!", kSkillArray[varAE]); + snprintf(buffer1, 80, "%s increased 1 point!", kSkillArray[varAE]); if (argA == 2) { displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); } else { - strcat((char *)_messageToBePrinted, buffer1); + strncat((char *)_messageToBePrinted, buffer1, 80); retVal = true; } } @@ -6190,14 +6216,14 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me _npcBuf[_teamCharId[teamCharId]]._activeScore[varAE] = 1; } if (effectPoints > 1) - sprintf(buffer1, "%s lowered %d points!", kSkillArray[varAE], effectPoints); + snprintf(buffer1, 80, "%s lowered %d points!", kSkillArray[varAE], effectPoints); else - sprintf(buffer1, "%s lowered 1 point!", kSkillArray[varAE]); + snprintf(buffer1, 80, "%s lowered 1 point!", kSkillArray[varAE]); if (argA == 2) { displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); } else { - strcat((char *)_messageToBePrinted, buffer1); + strncat((char *)_messageToBePrinted, buffer1, 80); retVal = true; } } @@ -6206,11 +6232,11 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me } break; case 26: // "Black Sphere" - strcpy(buffer1, "The entire party collapses, dead!!!"); + strncpy(buffer1, "The entire party collapses, dead!!!", 80); if (argA == 2) { displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); } else { - strcat((char *)_messageToBePrinted, buffer1); + strncat((char *)_messageToBePrinted, buffer1, 80); retVal = true; } totalPartyKill(); @@ -6229,11 +6255,11 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me if (teamCharId != 0x1B) { _npcBuf[_teamCharId[teamCharId]]._hitPoints = 0; copyString(_npcBuf[_teamCharId[teamCharId]]._name, buffer2); - sprintf(buffer1, "%s collapses, dead!!!", buffer2); + snprintf(buffer1, 80, "%s collapses, dead!!!", buffer2); if (argA == 2) { displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); } else { - strcat((char *)_messageToBePrinted, buffer1); + strncat((char *)_messageToBePrinted, buffer1, 80); retVal = true; } // emptyFunction(2); @@ -6249,11 +6275,11 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me int16 teamCharId = windowId; if (teamCharId != 0x1B) { if (_teamCharStatus[teamCharId]._status == 0) { - strcat((char *)_messageToBePrinted, " The item makes a loud noise, awakening the character!"); + strncat((char *)_messageToBePrinted, " The item makes a loud noise, awakening the character!", 80); _teamCharStatus[teamCharId]._status = 0; _teamCharStatus[teamCharId]._duration = 0; } else { - strcat((char *)_messageToBePrinted, " The item makes a loud noise, but has no effect!"); + strncat((char *)_messageToBePrinted, " The item makes a loud noise, but has no effect!", 80); } } } @@ -6277,15 +6303,15 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me copyString(_npcBuf[_teamCharId[teamCharId]]._name, buffer2); if (varAE > 1) - sprintf(buffer1, "%s is healed %d points!", buffer2, varAE); + snprintf(buffer1, 80, "%s is healed %d points!", buffer2, varAE); else - sprintf(buffer1, "%s is healed 1 point!", buffer2); + snprintf(buffer1, 80, "%s is healed 1 point!", buffer2); } if (argA == 2) { displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); } else { - strcat((char *)_messageToBePrinted, buffer1); + strncat((char *)_messageToBePrinted, buffer1, 80); retVal = true; } @@ -6309,15 +6335,15 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me copyString(_npcBuf[_teamCharId[teamCharId]]._name, buffer2); if (varAE > 1) - sprintf(buffer1, "%s is harmed for %d points!", buffer2, varAE); + snprintf(buffer1, 80, "%s is harmed for %d points!", buffer2, varAE); else - sprintf(buffer1, "%s is harmed for 1 point!", buffer2); + snprintf(buffer1, 80, "%s is harmed for 1 point!", buffer2); } if (argA == 2) { displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); } else { - strcat((char *)_messageToBePrinted, buffer1); + strncat((char *)_messageToBePrinted, buffer1, 80); retVal = true; } @@ -6344,12 +6370,12 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me if ((_npcBuf[charId]._inventory[objectId]._stat1 & 0x7F) != 0x7F) { int8 varA1 = (_npcBuf[charId]._inventory[objectId]._stat1 & 0x7F) - 1; if (varA1 <= 0) { - strcpy(buffer1, " * The item breaks!"); + strncpy(buffer1, " * The item breaks!", 80); if (argA == 2) { Common::KeyCode varAE = getLastCharAfterAnimCount(_guessAnimationAmount); displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); } else { - strcat((char *)_messageToBePrinted, buffer1); + strncat((char *)_messageToBePrinted, buffer1, 80); } setCharacterObjectToBroken(charId, objectId); } else { @@ -6770,17 +6796,17 @@ bool EfhEngine::checkMonsterCollision() { for (int16 var6C = 0; var6C < 2; ++var6C) { int16 var1 = _mapMonsters[monsterId]._possessivePronounSHL6 & 0x3F; if (var1 <= 0x3D) { - strcpy(dest, kEncounters[_mapMonsters[monsterId]._monsterRef]._name); + strncpy(dest, kEncounters[_mapMonsters[monsterId]._monsterRef]._name, 80); if (var6A > 1) - strcat(dest, " "); + strncat(dest, " ", 2); - sprintf(buffer, "with %d %s", var6A, dest); + snprintf(buffer, 80, "with %d %s", var6A, dest); } else if (var1 == 0x3E) { - strcpy(buffer, "(NOT DEFINED)"); + strncpy(buffer, "(NOT DEFINED)", 80); } else if (var1 == 0x3F) { // Useless check, it's the last possible value // Special character name copyString(_npcBuf[_mapMonsters[monsterId]._field_1]._name, dest); - sprintf(buffer, "with %s", dest); + snprintf(buffer, 80, "with %s", dest); } clearBottomTextZone(0); @@ -6791,13 +6817,13 @@ bool EfhEngine::checkMonsterCollision() { setTextColorWhite(); displayStringAtTextPos("T"); setTextColorRed(); - sprintf(buffer, "alk to the %s", dest); + snprintf(buffer, 80, "alk to the %s", dest); displayStringAtTextPos(buffer); setTextPos(24, 178); setTextColorWhite(); displayStringAtTextPos("A"); setTextColorRed(); - sprintf(buffer, "ttack the %s", dest); + snprintf(buffer, 80, "ttack the %s", dest); displayStringAtTextPos(buffer); setTextPos(198, 169); setTextColorWhite(); From 1043a315a9c86fec58063d3214df96bd37305937 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Thu, 10 Nov 2022 09:07:42 +0100 Subject: [PATCH 152/412] EFH: Turn _nameBuffer into a Common::String --- engines/efh/efh.cpp | 64 ++++++++++++++++++++++----------------------- engines/efh/efh.h | 2 +- 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index a63e613305ed..6f02e819b021 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -235,7 +235,7 @@ EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst) memset(_characterNamePt2, 0, 20); memset(_enemyNamePt1, 0, 5); memset(_enemyNamePt2, 0, 20); - memset(_nameBuffer, 0, 20); + _nameBuffer = ""; memset(_attackBuffer, 0, 20); for (int i = 0; i < 100; ++i) { @@ -1346,23 +1346,23 @@ void EfhEngine::displayLowStatusScreen(bool flag) { case 0: { uint16 var4 = sub1C80A(charId, 9, true); if (var4 == 0x7FFF) - strncpy(_nameBuffer, "(NONE)", 20); + _nameBuffer = "(NONE)"; else - copyString(_items[var4]._name, _nameBuffer); + snprintf(_items[var4]._name, 15, "%s", _nameBuffer.c_str()); } break; case 1: - strncpy(_nameBuffer, "* ASLEEP *", 20); + _nameBuffer = "* ASLEEP *"; break; case 2: - strncpy(_nameBuffer, "* FROZEN *", 20); + _nameBuffer = "* FROZEN *"; break; default: - strncpy(_nameBuffer, "* DISABLED *", 20); + _nameBuffer = "* DISABLED *"; break; } - displayCenteredString(_nameBuffer, 225, 302, textPosY); + displayCenteredString(_nameBuffer.c_str(), 225, 302, textPosY); } } @@ -1965,9 +1965,9 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int16 posX, int16 posY, int16 var110 = sub1C219((uint8 *)"Nothing...", 1, 2, true); displayFctFullScreen(); } else { - copyString(_npcBuf[_teamCharId[counter]]._name, _enemyNamePt2); - copyString(_items[var110]._name, _nameBuffer); - snprintf(curLine, 150, "%s finds a %s!", _enemyNamePt2, _nameBuffer); + snprintf(_npcBuf[_teamCharId[counter]]._name, 11, "%s", _enemyNamePt2); + snprintf(_items[var110]._name, 15, "%s", _nameBuffer.c_str()); + snprintf(curLine, 150, "%s finds a %s!", _enemyNamePt2, _nameBuffer.c_str()); drawMapWindow(); displayFctFullScreen(); drawMapWindow(); @@ -4809,28 +4809,28 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { int16 var68 = _items[unk_monsterField5_itemId]._attackType + 1; int16 var6A = getRandom(3) - 1; if (var5E == 2) { - strncpy(_characterNamePt1, "The ", 5); + snprintf(_characterNamePt1, 5, "The "); } else { *_characterNamePt1 = 0; } if (var70 == 2) { - strncpy(_enemyNamePt1, "The ", 5); + snprintf(_enemyNamePt1, 5, "The "); } else { *_enemyNamePt1 = 0; } - strncpy(_characterNamePt2, kEncounters[_mapMonsters[_teamMonsterIdArray[groupId]]._monsterRef]._name, 14); - copyString(_npcBuf[_teamCharId[teamCharId]]._name, _enemyNamePt2); - copyString(_items[unk_monsterField5_itemId]._name, _nameBuffer); + snprintf(_characterNamePt2, 20, "%s", kEncounters[_mapMonsters[_teamMonsterIdArray[groupId]]._monsterRef]._name); + snprintf(_npcBuf[_teamCharId[teamCharId]]._name, 11, "%s", _enemyNamePt2); + snprintf(_items[unk_monsterField5_itemId]._name, 15, "%s", _nameBuffer.c_str()); if (checkSpecialItemsOnCurrentPlace(unk_monsterField5_itemId)) { // Action A - Check damages - Start if (var62 == 0) { - snprintf((char *)_messageToBePrinted, 400, "%s%s %s at %s%s with %s %s, but misses!", _enemyNamePt1, _enemyNamePt2, kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2, kPossessive[var70], _nameBuffer); + snprintf((char *)_messageToBePrinted, 400, "%s%s %s at %s%s with %s %s, but misses!", _enemyNamePt1, _enemyNamePt2, kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2, kPossessive[var70], _nameBuffer.c_str()); } else if (hitPoints <= 0){ - snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s, but does no damage!", _enemyNamePt1, _enemyNamePt2, kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2, _attackBuffer, kPossessive[var70], _nameBuffer); + snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s, but does no damage!", _enemyNamePt1, _enemyNamePt2, kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2, _attackBuffer, kPossessive[var70], _nameBuffer.c_str()); } else if (hitPoints == 1) { - snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s for 1 point", _enemyNamePt1, _enemyNamePt2, kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2, _attackBuffer, kPossessive[var70], _nameBuffer); + snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s for 1 point", _enemyNamePt1, _enemyNamePt2, kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2, _attackBuffer, kPossessive[var70], _nameBuffer.c_str()); if (_mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] <= 0) { getDeathTypeDescription(groupId, teamCharId + 1000); getXPAndSearchCorpse(_teamCharId[teamCharId], _enemyNamePt1, _enemyNamePt2, _teamMonsterIdArray[groupId]); @@ -4838,7 +4838,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { strncat((char *)_messageToBePrinted, "!", 2); } } else { - snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s for %d points", _enemyNamePt1, _enemyNamePt2, kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2, _attackBuffer, kPossessive[var70], _nameBuffer, hitPoints); + snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s for %d points", _enemyNamePt1, _enemyNamePt2, kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2, _attackBuffer, kPossessive[var70], _nameBuffer.c_str(), hitPoints); if (_mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] <= 0) { getDeathTypeDescription(groupId, teamCharId + 1000); getXPAndSearchCorpse(_teamCharId[teamCharId], _enemyNamePt1, _enemyNamePt2, _teamMonsterIdArray[groupId]); @@ -4894,7 +4894,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { if (var51 <= 0) { char buffer[80]; memset(buffer, 0, 80); - snprintf(buffer, 80, " * %s%s's %s breaks!", _enemyNamePt1, _enemyNamePt2, _nameBuffer); + snprintf(buffer, 80, " * %s%s's %s breaks!", _enemyNamePt1, _enemyNamePt2, _nameBuffer.c_str()); strncat((char *)_messageToBePrinted, buffer, 80); setCharacterObjectToBroken(varInt, var64); var6E = false; @@ -4924,7 +4924,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { } // Action A - Check effect - End } else { - snprintf((char *)_messageToBePrinted, 400, "%s%s tries to use %s %s, but it doesn't work!", _enemyNamePt1, _enemyNamePt2, kPossessive[var70], _nameBuffer); + snprintf((char *)_messageToBePrinted, 400, "%s%s tries to use %s %s, but it doesn't work!", _enemyNamePt1, _enemyNamePt2, kPossessive[var70], _nameBuffer.c_str()); } genericGenerateSound(_items[unk_monsterField5_itemId]._attackType, var62); @@ -4976,15 +4976,15 @@ void EfhEngine::handleFight_lastAction_U(int16 teamCharId) { // In the original, this function is part of handleFight. // It has been split for readability purposes. int16 unk_monsterField5_itemId = _npcBuf[_teamCharId[teamCharId]]._inventory[_word31780[teamCharId]]._ref; - copyString(_npcBuf[_teamCharId[teamCharId]]._name, _enemyNamePt2); - copyString(_items[unk_monsterField5_itemId]._name, _nameBuffer); + snprintf(_npcBuf[_teamCharId[teamCharId]]._name, 11, "%s", _enemyNamePt2); + snprintf(_items[unk_monsterField5_itemId]._name, 15, "%s", _nameBuffer.c_str()); int16 var70 = _npcBuf[_teamCharId[teamCharId]]._possessivePronounSHL6 >> 6; if (var70 == 2) - strncpy(_enemyNamePt1, "The ", 5); + snprintf(_enemyNamePt1, 5, "The "); else *_enemyNamePt1 = 0; - snprintf((char *)_messageToBePrinted, 400, "%s%s uses %s %s! ", _enemyNamePt1, _enemyNamePt2, kPossessive[var70], _nameBuffer); + snprintf((char *)_messageToBePrinted, 400, "%s%s uses %s %s! ", _enemyNamePt1, _enemyNamePt2, kPossessive[var70], _nameBuffer.c_str()); sub1C219(_messageToBePrinted, 1, 2, true); } @@ -5224,22 +5224,22 @@ bool EfhEngine::handleFight(int16 monsterId) { *_enemyNamePt1 = 0; strncpy(_enemyNamePt2, kEncounters[_mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._monsterRef]._name, 20); - copyString(_npcBuf[_teamCharId[var7E]]._name, _characterNamePt2); - copyString(_items[unk_monsterField5_itemId]._name, _nameBuffer); + snprintf(_npcBuf[_teamCharId[var7E]]._name, 11, "%s", _characterNamePt2); + snprintf(_items[unk_monsterField5_itemId]._name, 15, "%s", _nameBuffer.c_str()); if (checkSpecialItemsOnCurrentPlace(unk_monsterField5_itemId)) { // handleFight - check damages - Start if (var62 == 0) { - snprintf((char *)_messageToBePrinted, 400, "%s%s %s at %s%s with %s %s, but misses!", _enemyNamePt1, _enemyNamePt2, kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2, kPossessive[var70], _nameBuffer); + snprintf((char *)_messageToBePrinted, 400, "%s%s %s at %s%s with %s %s, but misses!", _enemyNamePt1, _enemyNamePt2, kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2, kPossessive[var70], _nameBuffer.c_str()); } else if (hitPoints <= 0) { - snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s, but does no damage!", _enemyNamePt1, _enemyNamePt2, kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2, _attackBuffer, kPossessive[var70], _nameBuffer); + snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s, but does no damage!", _enemyNamePt1, _enemyNamePt2, kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2, _attackBuffer, kPossessive[var70], _nameBuffer.c_str()); } else if (hitPoints == 1) { - snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s for 1 point", _enemyNamePt1, _enemyNamePt2, kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2, _attackBuffer, kPossessive[var70], _nameBuffer); + snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s for 1 point", _enemyNamePt1, _enemyNamePt2, kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2, _attackBuffer, kPossessive[var70], _nameBuffer.c_str()); if (_npcBuf[_teamCharId[var7E]]._hitPoints <= 0) getDeathTypeDescription(var7E + 1000, monsterGroupIdOrMonsterId); else strncat((char *)_messageToBePrinted, "!", 2); } else { - snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s for %d points", _enemyNamePt1, _enemyNamePt2, kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2, _attackBuffer, kPossessive[var70], _nameBuffer, hitPoints); + snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s for %d points", _enemyNamePt1, _enemyNamePt2, kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2, _attackBuffer, kPossessive[var70], _nameBuffer.c_str(), hitPoints); if (_npcBuf[_teamCharId[var7E]]._hitPoints <= 0) getDeathTypeDescription(var7E + 1000, monsterGroupIdOrMonsterId); else @@ -5316,7 +5316,7 @@ bool EfhEngine::handleFight(int16 monsterId) { } // handleFight - Check effect - end } else { - snprintf((char *)_messageToBePrinted, 400, "%s%s tries to use %s %s, but it doesn't work!", _enemyNamePt1, _enemyNamePt2, kPossessive[var70], _nameBuffer); + snprintf((char *)_messageToBePrinted, 400, "%s%s tries to use %s %s, but it doesn't work!", _enemyNamePt1, _enemyNamePt2, kPossessive[var70], _nameBuffer.c_str()); } genericGenerateSound(_items[unk_monsterField5_itemId]._attackType, var62); sub1C219(_messageToBePrinted, 1, 2, true); diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 40307895f4c7..80941c2b3fba 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -511,7 +511,7 @@ class EfhEngine : public Engine { char _enemyNamePt2[20]; char _characterNamePt1[5]; char _characterNamePt2[20]; - char _nameBuffer[20]; + Common::String _nameBuffer; char _attackBuffer[20]; uint8 _messageToBePrinted[400]; From 27b7beae68adb5b0428daa93fe0d209a9183f5fc Mon Sep 17 00:00:00 2001 From: Strangerke Date: Fri, 11 Nov 2022 11:14:18 +0100 Subject: [PATCH 153/412] EFH: Fixa couple of previously usages of "copystring" --- engines/efh/efh.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 6f02e819b021..d519e0ef4e54 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -1348,7 +1348,7 @@ void EfhEngine::displayLowStatusScreen(bool flag) { if (var4 == 0x7FFF) _nameBuffer = "(NONE)"; else - snprintf(_items[var4]._name, 15, "%s", _nameBuffer.c_str()); + _nameBuffer = _items[var4]._name; } break; case 1: @@ -1965,8 +1965,8 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int16 posX, int16 posY, int16 var110 = sub1C219((uint8 *)"Nothing...", 1, 2, true); displayFctFullScreen(); } else { - snprintf(_npcBuf[_teamCharId[counter]]._name, 11, "%s", _enemyNamePt2); - snprintf(_items[var110]._name, 15, "%s", _nameBuffer.c_str()); + snprintf(_enemyNamePt2, 11, "%s", _npcBuf[_teamCharId[counter]]._name); + _nameBuffer = _items[var110]._name; snprintf(curLine, 150, "%s finds a %s!", _enemyNamePt2, _nameBuffer.c_str()); drawMapWindow(); displayFctFullScreen(); @@ -4821,8 +4821,8 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { } snprintf(_characterNamePt2, 20, "%s", kEncounters[_mapMonsters[_teamMonsterIdArray[groupId]]._monsterRef]._name); - snprintf(_npcBuf[_teamCharId[teamCharId]]._name, 11, "%s", _enemyNamePt2); - snprintf(_items[unk_monsterField5_itemId]._name, 15, "%s", _nameBuffer.c_str()); + snprintf(_enemyNamePt2, 11, "%s", _npcBuf[_teamCharId[teamCharId]]._name); + _nameBuffer = _items[unk_monsterField5_itemId]._name; if (checkSpecialItemsOnCurrentPlace(unk_monsterField5_itemId)) { // Action A - Check damages - Start if (var62 == 0) { @@ -4976,8 +4976,8 @@ void EfhEngine::handleFight_lastAction_U(int16 teamCharId) { // In the original, this function is part of handleFight. // It has been split for readability purposes. int16 unk_monsterField5_itemId = _npcBuf[_teamCharId[teamCharId]]._inventory[_word31780[teamCharId]]._ref; - snprintf(_npcBuf[_teamCharId[teamCharId]]._name, 11, "%s", _enemyNamePt2); - snprintf(_items[unk_monsterField5_itemId]._name, 15, "%s", _nameBuffer.c_str()); + snprintf(_enemyNamePt2, 11, "%s", _npcBuf[_teamCharId[teamCharId]]._name); + _nameBuffer = _items[unk_monsterField5_itemId]._name; int16 var70 = _npcBuf[_teamCharId[teamCharId]]._possessivePronounSHL6 >> 6; if (var70 == 2) snprintf(_enemyNamePt1, 5, "The "); @@ -5224,8 +5224,8 @@ bool EfhEngine::handleFight(int16 monsterId) { *_enemyNamePt1 = 0; strncpy(_enemyNamePt2, kEncounters[_mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._monsterRef]._name, 20); - snprintf(_npcBuf[_teamCharId[var7E]]._name, 11, "%s", _characterNamePt2); - snprintf(_items[unk_monsterField5_itemId]._name, 15, "%s", _nameBuffer.c_str()); + snprintf(_characterNamePt2, 11, "%s", _npcBuf[_teamCharId[var7E]]._name); + _nameBuffer = _items[unk_monsterField5_itemId]._name; if (checkSpecialItemsOnCurrentPlace(unk_monsterField5_itemId)) { // handleFight - check damages - Start if (var62 == 0) { From c6bd02fb8ee86aaa79ff5a9bb1765c7324ef6b06 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Fri, 11 Nov 2022 19:51:23 +0100 Subject: [PATCH 154/412] EFH: Turn _enemyNamePt2 into a Common::String --- engines/efh/efh.cpp | 68 ++++++++++++++++++++++----------------------- engines/efh/efh.h | 6 ++-- 2 files changed, 38 insertions(+), 36 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index d519e0ef4e54..aa99d22aa677 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -234,7 +234,7 @@ EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst) memset(_characterNamePt1, 0, 5); memset(_characterNamePt2, 0, 20); memset(_enemyNamePt1, 0, 5); - memset(_enemyNamePt2, 0, 20); + _enemyNamePt2= ""; _nameBuffer = ""; memset(_attackBuffer, 0, 20); @@ -1327,7 +1327,7 @@ void EfhEngine::displayLowStatusScreen(bool flag) { continue; int16 charId = _teamCharId[i]; int16 textPosY = 161 + 9 * i; - copyString(_npcBuf[charId]._name, buffer); + snprintf(buffer, 11, "%s", _npcBuf[charId]._name); setTextPos(16, textPosY); displayStringAtTextPos(buffer); snprintf(buffer, 80, "%d", getEquipmentDefense(charId, false)); @@ -1965,9 +1965,9 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int16 posX, int16 posY, int16 var110 = sub1C219((uint8 *)"Nothing...", 1, 2, true); displayFctFullScreen(); } else { - snprintf(_enemyNamePt2, 11, "%s", _npcBuf[_teamCharId[counter]]._name); + _enemyNamePt2 = _npcBuf[_teamCharId[counter]]._name; _nameBuffer = _items[var110]._name; - snprintf(curLine, 150, "%s finds a %s!", _enemyNamePt2, _nameBuffer.c_str()); + snprintf(curLine, 150, "%s finds a %s!", _enemyNamePt2.c_str(), _nameBuffer.c_str()); drawMapWindow(); displayFctFullScreen(); drawMapWindow(); @@ -3118,9 +3118,9 @@ bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { for (int16 counter = 0; counter < _teamSize; ++counter) { if (_npcBuf[var58].field_11 == _teamCharId[counter]) { displayMonsterAnim(monsterId); - copyString(_npcBuf[var58]._name, _enemyNamePt2); + _enemyNamePt2 = _npcBuf[var58]._name; copyString(_npcBuf[_teamCharId[counter]]._name, _characterNamePt2); - snprintf(buffer, 80, "%s asks that %s leave your party.", _enemyNamePt2, _characterNamePt2); + snprintf(buffer, 80, "%s asks that %s leave your party.", _enemyNamePt2.c_str(), _characterNamePt2); for (int16 i = 0; i < 2; ++i) { clearBottomTextZone(0); _textColor = 0xE; @@ -4006,7 +4006,7 @@ void EfhEngine::handleFight_checkEndEffect(int16 charId) { return; // At this point : The status is different to 0 (normal) and the effect duration is finally 0 (end of effect) - copyString(_npcBuf[_teamCharId[charId]]._name, _enemyNamePt2); + _enemyNamePt2 = _npcBuf[_teamCharId[charId]]._name; if ((_npcBuf[_teamCharId[charId]]._possessivePronounSHL6 >> 6) == 2) { strncpy(_enemyNamePt1, "The ", 5); } else { @@ -4016,13 +4016,13 @@ void EfhEngine::handleFight_checkEndEffect(int16 charId) { // End of effect message depends on the type of effect switch (_teamCharStatus[charId]._status) { case 1: - snprintf((char *)_messageToBePrinted, 400, "%s%s wakes up!", _enemyNamePt1, _enemyNamePt2); + snprintf((char *)_messageToBePrinted, 400, "%s%s wakes up!", _enemyNamePt1, _enemyNamePt2.c_str()); break; case 2: - snprintf((char *)_messageToBePrinted, 400, "%s%s thaws out!", _enemyNamePt1, _enemyNamePt2); + snprintf((char *)_messageToBePrinted, 400, "%s%s thaws out!", _enemyNamePt1, _enemyNamePt2.c_str()); break; default: - snprintf((char *)_messageToBePrinted, 400, "%s%s recovers!", _enemyNamePt1, _enemyNamePt2); + snprintf((char *)_messageToBePrinted, 400, "%s%s recovers!", _enemyNamePt1, _enemyNamePt2.c_str()); break; } @@ -4821,19 +4821,19 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { } snprintf(_characterNamePt2, 20, "%s", kEncounters[_mapMonsters[_teamMonsterIdArray[groupId]]._monsterRef]._name); - snprintf(_enemyNamePt2, 11, "%s", _npcBuf[_teamCharId[teamCharId]]._name); + _enemyNamePt2 = _npcBuf[_teamCharId[teamCharId]]._name; _nameBuffer = _items[unk_monsterField5_itemId]._name; if (checkSpecialItemsOnCurrentPlace(unk_monsterField5_itemId)) { // Action A - Check damages - Start if (var62 == 0) { - snprintf((char *)_messageToBePrinted, 400, "%s%s %s at %s%s with %s %s, but misses!", _enemyNamePt1, _enemyNamePt2, kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2, kPossessive[var70], _nameBuffer.c_str()); + snprintf((char *)_messageToBePrinted, 400, "%s%s %s at %s%s with %s %s, but misses!", _enemyNamePt1, _enemyNamePt2.c_str(), kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2, kPossessive[var70], _nameBuffer.c_str()); } else if (hitPoints <= 0){ - snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s, but does no damage!", _enemyNamePt1, _enemyNamePt2, kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2, _attackBuffer, kPossessive[var70], _nameBuffer.c_str()); + snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s, but does no damage!", _enemyNamePt1, _enemyNamePt2.c_str(), kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2, _attackBuffer, kPossessive[var70], _nameBuffer.c_str()); } else if (hitPoints == 1) { - snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s for 1 point", _enemyNamePt1, _enemyNamePt2, kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2, _attackBuffer, kPossessive[var70], _nameBuffer.c_str()); + snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s for 1 point", _enemyNamePt1, _enemyNamePt2.c_str(), kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2, _attackBuffer, kPossessive[var70], _nameBuffer.c_str()); if (_mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] <= 0) { getDeathTypeDescription(groupId, teamCharId + 1000); - getXPAndSearchCorpse(_teamCharId[teamCharId], _enemyNamePt1, _enemyNamePt2, _teamMonsterIdArray[groupId]); + getXPAndSearchCorpse(_teamCharId[teamCharId], _enemyNamePt1, (char *)_enemyNamePt2.c_str(), _teamMonsterIdArray[groupId]); } else { strncat((char *)_messageToBePrinted, "!", 2); } @@ -4841,7 +4841,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s for %d points", _enemyNamePt1, _enemyNamePt2, kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2, _attackBuffer, kPossessive[var70], _nameBuffer.c_str(), hitPoints); if (_mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] <= 0) { getDeathTypeDescription(groupId, teamCharId + 1000); - getXPAndSearchCorpse(_teamCharId[teamCharId], _enemyNamePt1, _enemyNamePt2, _teamMonsterIdArray[groupId]); + getXPAndSearchCorpse(_teamCharId[teamCharId], _enemyNamePt1, (char *)_enemyNamePt2.c_str(), _teamMonsterIdArray[groupId]); } else { strncat((char *)_messageToBePrinted, "!", 2); } @@ -4894,7 +4894,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { if (var51 <= 0) { char buffer[80]; memset(buffer, 0, 80); - snprintf(buffer, 80, " * %s%s's %s breaks!", _enemyNamePt1, _enemyNamePt2, _nameBuffer.c_str()); + snprintf(buffer, 80, " * %s%s's %s breaks!", _enemyNamePt1, _enemyNamePt2.c_str(), _nameBuffer.c_str()); strncat((char *)_messageToBePrinted, buffer, 80); setCharacterObjectToBroken(varInt, var64); var6E = false; @@ -4924,7 +4924,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { } // Action A - Check effect - End } else { - snprintf((char *)_messageToBePrinted, 400, "%s%s tries to use %s %s, but it doesn't work!", _enemyNamePt1, _enemyNamePt2, kPossessive[var70], _nameBuffer.c_str()); + snprintf((char *)_messageToBePrinted, 400, "%s%s tries to use %s %s, but it doesn't work!", _enemyNamePt1, _enemyNamePt2.c_str(), kPossessive[var70], _nameBuffer.c_str()); } genericGenerateSound(_items[unk_monsterField5_itemId]._attackType, var62); @@ -4939,7 +4939,7 @@ void EfhEngine::handleFight_lastAction_D(int16 teamCharId) { debug("handleFight_lastAction_D %d", teamCharId); _word32482[teamCharId] -= 40; - copyString(_npcBuf[_teamCharId[teamCharId]]._name, _enemyNamePt2); + _enemyNamePt2 = _npcBuf[_teamCharId[teamCharId]]._name; int16 var70 = _npcBuf[_teamCharId[teamCharId]]._possessivePronounSHL6 >> 6; if (var70 == 2) @@ -4947,7 +4947,7 @@ void EfhEngine::handleFight_lastAction_D(int16 teamCharId) { else *_enemyNamePt1 = 0; - snprintf((char *)_messageToBePrinted, 400, "%s%s prepares to defend %sself!", _enemyNamePt1, _enemyNamePt2, kPersonal[var70]); + snprintf((char *)_messageToBePrinted, 400, "%s%s prepares to defend %sself!", _enemyNamePt1, _enemyNamePt2.c_str(), kPersonal[var70]); sub1C219(_messageToBePrinted, 1, 2, true); } @@ -4958,7 +4958,7 @@ void EfhEngine::handleFight_lastAction_H(int16 teamCharId) { // It has been split for readability purposes. _word32680[teamCharId] -= 50; - copyString(_npcBuf[_teamCharId[teamCharId]]._name, _enemyNamePt2); + _enemyNamePt2 = _npcBuf[_teamCharId[teamCharId]]._name; int16 var70 = _npcBuf[_teamCharId[teamCharId]]._possessivePronounSHL6 >> 6; if (var70 == 2) @@ -4966,7 +4966,7 @@ void EfhEngine::handleFight_lastAction_H(int16 teamCharId) { else *_enemyNamePt1 = 0; - snprintf((char *)_messageToBePrinted, 400, "%s%s attempts to hide %sself!", _enemyNamePt1, _enemyNamePt2, kPersonal[var70]); + snprintf((char *)_messageToBePrinted, 400, "%s%s attempts to hide %sself!", _enemyNamePt1, _enemyNamePt2.c_str(), kPersonal[var70]); sub1C219(_messageToBePrinted, 1, 2, true); } @@ -4976,7 +4976,7 @@ void EfhEngine::handleFight_lastAction_U(int16 teamCharId) { // In the original, this function is part of handleFight. // It has been split for readability purposes. int16 unk_monsterField5_itemId = _npcBuf[_teamCharId[teamCharId]]._inventory[_word31780[teamCharId]]._ref; - snprintf(_enemyNamePt2, 11, "%s", _npcBuf[_teamCharId[teamCharId]]._name); + _enemyNamePt2 = _npcBuf[_teamCharId[teamCharId]]._name; _nameBuffer = _items[unk_monsterField5_itemId]._name; int16 var70 = _npcBuf[_teamCharId[teamCharId]]._possessivePronounSHL6 >> 6; if (var70 == 2) @@ -4984,7 +4984,7 @@ void EfhEngine::handleFight_lastAction_U(int16 teamCharId) { else *_enemyNamePt1 = 0; - snprintf((char *)_messageToBePrinted, 400, "%s%s uses %s %s! ", _enemyNamePt1, _enemyNamePt2, kPossessive[var70], _nameBuffer.c_str()); + snprintf((char *)_messageToBePrinted, 400, "%s%s uses %s %s! ", _enemyNamePt1, _enemyNamePt2.c_str(), kPossessive[var70], _nameBuffer.c_str()); sub1C219(_messageToBePrinted, 1, 2, true); } @@ -5223,23 +5223,23 @@ bool EfhEngine::handleFight(int16 monsterId) { else *_enemyNamePt1 = 0; - strncpy(_enemyNamePt2, kEncounters[_mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._monsterRef]._name, 20); + _enemyNamePt2 = kEncounters[_mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._monsterRef]._name; snprintf(_characterNamePt2, 11, "%s", _npcBuf[_teamCharId[var7E]]._name); _nameBuffer = _items[unk_monsterField5_itemId]._name; if (checkSpecialItemsOnCurrentPlace(unk_monsterField5_itemId)) { // handleFight - check damages - Start if (var62 == 0) { - snprintf((char *)_messageToBePrinted, 400, "%s%s %s at %s%s with %s %s, but misses!", _enemyNamePt1, _enemyNamePt2, kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2, kPossessive[var70], _nameBuffer.c_str()); + snprintf((char *)_messageToBePrinted, 400, "%s%s %s at %s%s with %s %s, but misses!", _enemyNamePt1, _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2, kPossessive[var70], _nameBuffer.c_str()); } else if (hitPoints <= 0) { - snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s, but does no damage!", _enemyNamePt1, _enemyNamePt2, kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2, _attackBuffer, kPossessive[var70], _nameBuffer.c_str()); + snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s, but does no damage!", _enemyNamePt1, _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2, _attackBuffer, kPossessive[var70], _nameBuffer.c_str()); } else if (hitPoints == 1) { - snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s for 1 point", _enemyNamePt1, _enemyNamePt2, kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2, _attackBuffer, kPossessive[var70], _nameBuffer.c_str()); + snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s for 1 point", _enemyNamePt1, _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2, _attackBuffer, kPossessive[var70], _nameBuffer.c_str()); if (_npcBuf[_teamCharId[var7E]]._hitPoints <= 0) getDeathTypeDescription(var7E + 1000, monsterGroupIdOrMonsterId); else strncat((char *)_messageToBePrinted, "!", 2); } else { - snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s for %d points", _enemyNamePt1, _enemyNamePt2, kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2, _attackBuffer, kPossessive[var70], _nameBuffer.c_str(), hitPoints); + snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s for %d points", _enemyNamePt1, _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2, _attackBuffer, kPossessive[var70], _nameBuffer.c_str(), hitPoints); if (_npcBuf[_teamCharId[var7E]]._hitPoints <= 0) getDeathTypeDescription(var7E + 1000, monsterGroupIdOrMonsterId); else @@ -5316,7 +5316,7 @@ bool EfhEngine::handleFight(int16 monsterId) { } // handleFight - Check effect - end } else { - snprintf((char *)_messageToBePrinted, 400, "%s%s tries to use %s %s, but it doesn't work!", _enemyNamePt1, _enemyNamePt2, kPossessive[var70], _nameBuffer.c_str()); + snprintf((char *)_messageToBePrinted, 400, "%s%s tries to use %s %s, but it doesn't work!", _enemyNamePt1, _enemyNamePt2.c_str(), kPossessive[var70], _nameBuffer.c_str()); } genericGenerateSound(_items[unk_monsterField5_itemId]._attackType, var62); sub1C219(_messageToBePrinted, 1, 2, true); @@ -5326,7 +5326,7 @@ bool EfhEngine::handleFight(int16 monsterId) { } else if (_mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._pictureRef[var86] > 0 && _stru32686[monsterGroupIdOrMonsterId]._field0[var86]) { --_stru32686[monsterGroupIdOrMonsterId]._field2[var86]; if (_stru32686[monsterGroupIdOrMonsterId]._field2[var86] <= 0) { - strncpy(_enemyNamePt2, kEncounters[_mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._monsterRef]._name, 20); + _enemyNamePt2 = kEncounters[_mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._monsterRef]._name; int16 var70 = kEncounters[_mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._monsterRef]._nameArticle; if (var70 == 2) strncpy(_enemyNamePt1, "The ", 5); @@ -5335,13 +5335,13 @@ bool EfhEngine::handleFight(int16 monsterId) { switch (_stru32686[monsterGroupIdOrMonsterId]._field0[var86]) { case 1: - snprintf((char *)_messageToBePrinted, 400, "%s%s wakes up!", _enemyNamePt1, _enemyNamePt2); + snprintf((char *)_messageToBePrinted, 400, "%s%s wakes up!", _enemyNamePt1, _enemyNamePt2.c_str()); break; case 2: - snprintf((char *)_messageToBePrinted, 400, "%s%s thaws out!", _enemyNamePt1, _enemyNamePt2); + snprintf((char *)_messageToBePrinted, 400, "%s%s thaws out!", _enemyNamePt1, _enemyNamePt2.c_str()); break; default: - snprintf((char *)_messageToBePrinted, 400, "%s%s recovers!", _enemyNamePt1, _enemyNamePt2); + snprintf((char *)_messageToBePrinted, 400, "%s%s recovers!", _enemyNamePt1, _enemyNamePt2.c_str()); break; } _stru32686[monsterGroupIdOrMonsterId]._field0[var86] = 0; diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 80941c2b3fba..77bcf1b1e710 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -464,6 +464,9 @@ class EfhEngine : public Engine { void displayColoredMenuBox(int16 minX, int16 minY, int16 maxX, int16 maxY, int16 color); // Utils + #if true + void copyString(char *srcStr, char *destStr); + #endif int32 readFileToBuffer(Common::String &filename, uint8 *destBuffer); void setDefaultNoteDuration(); void decryptImpFile(bool techMapFl); @@ -478,7 +481,6 @@ class EfhEngine : public Engine { Common::KeyCode handleAndMapInput(bool animFl); Common::KeyCode getInputBlocking(); void setNumLock(); - void copyString(char *srcStr, char *destStr); bool getValidationFromUser(); @@ -508,7 +510,7 @@ class EfhEngine : public Engine { uint8 _history[256]; uint8 _techData[4096]; char _enemyNamePt1[5]; - char _enemyNamePt2[20]; + Common::String _enemyNamePt2; char _characterNamePt1[5]; char _characterNamePt2[20]; Common::String _nameBuffer; From 3ca7a67c1ea82302825d0b6cd4578c3dd5b0ca7b Mon Sep 17 00:00:00 2001 From: Strangerke Date: Fri, 11 Nov 2022 23:29:54 +0100 Subject: [PATCH 155/412] EFH: Turn _characterNamePt2 into a Common::String --- engines/efh/efh.cpp | 86 ++++++++++++++++++++++----------------------- engines/efh/efh.h | 2 +- 2 files changed, 44 insertions(+), 44 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index aa99d22aa677..b0690260577e 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -232,7 +232,7 @@ EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst) } memset(_characterNamePt1, 0, 5); - memset(_characterNamePt2, 0, 20); + _characterNamePt2 = ""; memset(_enemyNamePt1, 0, 5); _enemyNamePt2= ""; _nameBuffer = ""; @@ -3119,8 +3119,8 @@ bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { if (_npcBuf[var58].field_11 == _teamCharId[counter]) { displayMonsterAnim(monsterId); _enemyNamePt2 = _npcBuf[var58]._name; - copyString(_npcBuf[_teamCharId[counter]]._name, _characterNamePt2); - snprintf(buffer, 80, "%s asks that %s leave your party.", _enemyNamePt2.c_str(), _characterNamePt2); + _characterNamePt2 = _npcBuf[_teamCharId[counter]]._name; + snprintf(buffer, 80, "%s asks that %s leave your party.", _enemyNamePt2.c_str(), _characterNamePt2.c_str()); for (int16 i = 0; i < 2; ++i) { clearBottomTextZone(0); _textColor = 0xE; @@ -4601,13 +4601,13 @@ void EfhEngine::addReactionText(int16 id) { case 0: switch (rand3) { case 1: - snprintf(buffer, 80, " %s%s reels from the blow!", _characterNamePt1, _characterNamePt2); + snprintf(buffer, 80, " %s%s reels from the blow!", _characterNamePt1, _characterNamePt2.c_str()); break; case 2: - snprintf(buffer, 80, " %s%s sways from the attack!", _characterNamePt1, _characterNamePt2); + snprintf(buffer, 80, " %s%s sways from the attack!", _characterNamePt1, _characterNamePt2.c_str()); break; case 3: - snprintf(buffer, 80, " %s%s looks dazed!", _characterNamePt1, _characterNamePt2); + snprintf(buffer, 80, " %s%s looks dazed!", _characterNamePt1, _characterNamePt2.c_str()); break; default: break; @@ -4616,13 +4616,13 @@ void EfhEngine::addReactionText(int16 id) { case 1: switch (rand3) { case 1: - snprintf(buffer, 80, " %s%s cries out in agony!", _characterNamePt1, _characterNamePt2); + snprintf(buffer, 80, " %s%s cries out in agony!", _characterNamePt1, _characterNamePt2.c_str()); break; case 2: - snprintf(buffer, 80, " %s%s screams from the abuse!", _characterNamePt1, _characterNamePt2); + snprintf(buffer, 80, " %s%s screams from the abuse!", _characterNamePt1, _characterNamePt2.c_str()); break; case 3: - snprintf(buffer, 80, " %s%s wails terribly!", _characterNamePt1, _characterNamePt2); + snprintf(buffer, 80, " %s%s wails terribly!", _characterNamePt1, _characterNamePt2.c_str()); break; default: break; @@ -4631,13 +4631,13 @@ void EfhEngine::addReactionText(int16 id) { case 2: switch (rand3) { case 1: - snprintf(buffer, 80, " %s%s is staggering!", _characterNamePt1, _characterNamePt2); + snprintf(buffer, 80, " %s%s is staggering!", _characterNamePt1, _characterNamePt2.c_str()); break; case 2: - snprintf(buffer, 80, " %s%s falters for a moment!", _characterNamePt1, _characterNamePt2); + snprintf(buffer, 80, " %s%s falters for a moment!", _characterNamePt1, _characterNamePt2.c_str()); break; case 3: - snprintf(buffer, 80, " %s%s is stumbling about!", _characterNamePt1, _characterNamePt2); + snprintf(buffer, 80, " %s%s is stumbling about!", _characterNamePt1, _characterNamePt2.c_str()); break; default: break; @@ -4646,13 +4646,13 @@ void EfhEngine::addReactionText(int16 id) { case 3: switch (rand3) { case 1: - snprintf(buffer, 80, " %s%s winces from the pain!", _characterNamePt1, _characterNamePt2); + snprintf(buffer, 80, " %s%s winces from the pain!", _characterNamePt1, _characterNamePt2.c_str()); break; case 2: - snprintf(buffer, 80, " %s%s cringes from the damage!", _characterNamePt1, _characterNamePt2); + snprintf(buffer, 80, " %s%s cringes from the damage!", _characterNamePt1, _characterNamePt2.c_str()); break; case 3: - snprintf(buffer, 80, " %s%s shrinks from the wound!", _characterNamePt1, _characterNamePt2); + snprintf(buffer, 80, " %s%s shrinks from the wound!", _characterNamePt1, _characterNamePt2.c_str()); break; default: break; @@ -4661,13 +4661,13 @@ void EfhEngine::addReactionText(int16 id) { case 4: switch (rand3) { case 1: - snprintf(buffer, 80, " %s%s screams!", _characterNamePt1, _characterNamePt2); + snprintf(buffer, 80, " %s%s screams!", _characterNamePt1, _characterNamePt2.c_str()); break; case 2: - snprintf(buffer, 80, " %s%s bellows!", _characterNamePt1, _characterNamePt2); + snprintf(buffer, 80, " %s%s bellows!", _characterNamePt1, _characterNamePt2.c_str()); break; case 3: - snprintf(buffer, 80, " %s%s shrills!", _characterNamePt1, _characterNamePt2); + snprintf(buffer, 80, " %s%s shrills!", _characterNamePt1, _characterNamePt2.c_str()); break; default: break; @@ -4676,13 +4676,13 @@ void EfhEngine::addReactionText(int16 id) { case 5: switch (rand3) { case 1: - snprintf(buffer, 80, " %s%s chortles!", _characterNamePt1, _characterNamePt2); + snprintf(buffer, 80, " %s%s chortles!", _characterNamePt1, _characterNamePt2.c_str()); break; case 2: - snprintf(buffer, 80, " %s%s seems amused!", _characterNamePt1, _characterNamePt2); + snprintf(buffer, 80, " %s%s seems amused!", _characterNamePt1, _characterNamePt2.c_str()); break; case 3: - snprintf(buffer, 80, " %s%s looks concerned!", _characterNamePt1, _characterNamePt2); + snprintf(buffer, 80, " %s%s looks concerned!", _characterNamePt1, _characterNamePt2.c_str()); break; default: break; @@ -4691,13 +4691,13 @@ void EfhEngine::addReactionText(int16 id) { case 6: switch (rand3) { case 1: - snprintf(buffer, 80, " %s%s laughs at the feeble attack!", _characterNamePt1, _characterNamePt2); + snprintf(buffer, 80, " %s%s laughs at the feeble attack!", _characterNamePt1, _characterNamePt2.c_str()); break; case 2: - snprintf(buffer, 80, " %s%s smiles at the pathetic attack!", _characterNamePt1, _characterNamePt2); + snprintf(buffer, 80, " %s%s smiles at the pathetic attack!", _characterNamePt1, _characterNamePt2.c_str()); break; case 3: - snprintf(buffer, 80, " %s%s laughs at the ineffective assault!", _characterNamePt1, _characterNamePt2); + snprintf(buffer, 80, " %s%s laughs at the ineffective assault!", _characterNamePt1, _characterNamePt2.c_str()); break; default: break; @@ -4820,17 +4820,17 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { *_enemyNamePt1 = 0; } - snprintf(_characterNamePt2, 20, "%s", kEncounters[_mapMonsters[_teamMonsterIdArray[groupId]]._monsterRef]._name); + _characterNamePt2 = kEncounters[_mapMonsters[_teamMonsterIdArray[groupId]]._monsterRef]._name; _enemyNamePt2 = _npcBuf[_teamCharId[teamCharId]]._name; _nameBuffer = _items[unk_monsterField5_itemId]._name; if (checkSpecialItemsOnCurrentPlace(unk_monsterField5_itemId)) { // Action A - Check damages - Start if (var62 == 0) { - snprintf((char *)_messageToBePrinted, 400, "%s%s %s at %s%s with %s %s, but misses!", _enemyNamePt1, _enemyNamePt2.c_str(), kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2, kPossessive[var70], _nameBuffer.c_str()); + snprintf((char *)_messageToBePrinted, 400, "%s%s %s at %s%s with %s %s, but misses!", _enemyNamePt1, _enemyNamePt2.c_str(), kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2.c_str(), kPossessive[var70], _nameBuffer.c_str()); } else if (hitPoints <= 0){ - snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s, but does no damage!", _enemyNamePt1, _enemyNamePt2.c_str(), kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2, _attackBuffer, kPossessive[var70], _nameBuffer.c_str()); + snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s, but does no damage!", _enemyNamePt1, _enemyNamePt2.c_str(), kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2.c_str(), _attackBuffer, kPossessive[var70], _nameBuffer.c_str()); } else if (hitPoints == 1) { - snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s for 1 point", _enemyNamePt1, _enemyNamePt2.c_str(), kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2, _attackBuffer, kPossessive[var70], _nameBuffer.c_str()); + snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s for 1 point", _enemyNamePt1, _enemyNamePt2.c_str(), kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2.c_str(), _attackBuffer, kPossessive[var70], _nameBuffer.c_str()); if (_mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] <= 0) { getDeathTypeDescription(groupId, teamCharId + 1000); getXPAndSearchCorpse(_teamCharId[teamCharId], _enemyNamePt1, (char *)_enemyNamePt2.c_str(), _teamMonsterIdArray[groupId]); @@ -4838,7 +4838,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { strncat((char *)_messageToBePrinted, "!", 2); } } else { - snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s for %d points", _enemyNamePt1, _enemyNamePt2, kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2, _attackBuffer, kPossessive[var70], _nameBuffer.c_str(), hitPoints); + snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s for %d points", _enemyNamePt1, _enemyNamePt2.c_str(), kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2.c_str(), _attackBuffer, kPossessive[var70], _nameBuffer.c_str(), hitPoints); if (_mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] <= 0) { getDeathTypeDescription(groupId, teamCharId + 1000); getXPAndSearchCorpse(_teamCharId[teamCharId], _enemyNamePt1, (char *)_enemyNamePt2.c_str(), _teamMonsterIdArray[groupId]); @@ -4874,9 +4874,9 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { char buffer[80]; memset(buffer, 0, 80); if (damagePointsAbsorbed <= 1) - snprintf(buffer, 80, " %s%s's armor absorbs 1 point!", _characterNamePt1, _characterNamePt2); + snprintf(buffer, 80, " %s%s's armor absorbs 1 point!", _characterNamePt1, _characterNamePt2.c_str()); else - snprintf(buffer, 80, " %s%s',27h,'s armor absorbs %d points!", _characterNamePt1, _characterNamePt2, damagePointsAbsorbed); + snprintf(buffer, 80, " %s%s',27h,'s armor absorbs %d points!", _characterNamePt1, _characterNamePt2.c_str(), damagePointsAbsorbed); strncat((char *)_messageToBePrinted, buffer, 80); } @@ -4911,7 +4911,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { _stru32686[var7E]._field2[groupId] = getRandom(10); char buffer[80]; memset(buffer, 0, 80); - snprintf(buffer, 80, " %s%s falls asleep!", _characterNamePt1, _characterNamePt2); + snprintf(buffer, 80, " %s%s falls asleep!", _characterNamePt1, _characterNamePt2.c_str()); strncat((char *)_messageToBePrinted, buffer, 80); } } else if (_items[unk_monsterField5_itemId].field_16 == 2 && _mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] > 0) { @@ -4919,7 +4919,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { _stru32686[var7E]._field2[groupId] = getRandom(10); char buffer[80]; memset(buffer, 0, 80); - snprintf(buffer, 80, " %s%s is frozen!", _characterNamePt1, _characterNamePt2); + snprintf(buffer, 80, " %s%s is frozen!", _characterNamePt1, _characterNamePt2.c_str()); strncat((char *)_messageToBePrinted, buffer, 80); } // Action A - Check effect - End @@ -5224,22 +5224,22 @@ bool EfhEngine::handleFight(int16 monsterId) { *_enemyNamePt1 = 0; _enemyNamePt2 = kEncounters[_mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._monsterRef]._name; - snprintf(_characterNamePt2, 11, "%s", _npcBuf[_teamCharId[var7E]]._name); + _characterNamePt2 = _npcBuf[_teamCharId[var7E]]._name; _nameBuffer = _items[unk_monsterField5_itemId]._name; if (checkSpecialItemsOnCurrentPlace(unk_monsterField5_itemId)) { // handleFight - check damages - Start if (var62 == 0) { - snprintf((char *)_messageToBePrinted, 400, "%s%s %s at %s%s with %s %s, but misses!", _enemyNamePt1, _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2, kPossessive[var70], _nameBuffer.c_str()); + snprintf((char *)_messageToBePrinted, 400, "%s%s %s at %s%s with %s %s, but misses!", _enemyNamePt1, _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2.c_str(), kPossessive[var70], _nameBuffer.c_str()); } else if (hitPoints <= 0) { - snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s, but does no damage!", _enemyNamePt1, _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2, _attackBuffer, kPossessive[var70], _nameBuffer.c_str()); + snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s, but does no damage!", _enemyNamePt1, _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2.c_str(), _attackBuffer, kPossessive[var70], _nameBuffer.c_str()); } else if (hitPoints == 1) { - snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s for 1 point", _enemyNamePt1, _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2, _attackBuffer, kPossessive[var70], _nameBuffer.c_str()); + snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s for 1 point", _enemyNamePt1, _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2.c_str(), _attackBuffer, kPossessive[var70], _nameBuffer.c_str()); if (_npcBuf[_teamCharId[var7E]]._hitPoints <= 0) getDeathTypeDescription(var7E + 1000, monsterGroupIdOrMonsterId); else strncat((char *)_messageToBePrinted, "!", 2); } else { - snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s for %d points", _enemyNamePt1, _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2, _attackBuffer, kPossessive[var70], _nameBuffer.c_str(), hitPoints); + snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s for %d points", _enemyNamePt1, _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2.c_str(), _attackBuffer, kPossessive[var70], _nameBuffer.c_str(), hitPoints); if (_npcBuf[_teamCharId[var7E]]._hitPoints <= 0) getDeathTypeDescription(var7E + 1000, monsterGroupIdOrMonsterId); else @@ -5273,9 +5273,9 @@ bool EfhEngine::handleFight(int16 monsterId) { char buffer[80]; memset(buffer, 0, 80); if (damagePointsAbsorbed <= 1) - snprintf(buffer, 80, " %s%s's armor absorbs 1 point!", _characterNamePt1, _characterNamePt2); + snprintf(buffer, 80, " %s%s's armor absorbs 1 point!", _characterNamePt1, _characterNamePt2.c_str()); else - snprintf(buffer, 80, " %s%s's armor absorbs %d points!", _characterNamePt1, _characterNamePt2, damagePointsAbsorbed); + snprintf(buffer, 80, " %s%s's armor absorbs %d points!", _characterNamePt1, _characterNamePt2.c_str(), damagePointsAbsorbed); strncat((char *)_messageToBePrinted, buffer, 80); varInt = (originalDamage + damagePointsAbsorbed) / 10; @@ -5291,7 +5291,7 @@ bool EfhEngine::handleFight(int16 monsterId) { if (getRandom(100) < 20) { _teamCharStatus[var7E]._status = 1; _teamCharStatus[var7E]._duration = getRandom(10); - snprintf(buffer, 80, " %s%s falls asleep!", _characterNamePt1, _characterNamePt2); + snprintf(buffer, 80, " %s%s falls asleep!", _characterNamePt1, _characterNamePt2.c_str()); strncat((char *)_messageToBePrinted, buffer, 80); } break; @@ -5299,14 +5299,14 @@ bool EfhEngine::handleFight(int16 monsterId) { if (getRandom(100) < 20) { _teamCharStatus[var7E]._status = 2; _teamCharStatus[var7E]._duration = getRandom(10); - snprintf(buffer, 80, " %s%s is frozen!", _characterNamePt1, _characterNamePt2); + snprintf(buffer, 80, " %s%s is frozen!", _characterNamePt1, _characterNamePt2.c_str()); strncat((char *)_messageToBePrinted, buffer, 80); } break; case 5: case 6: if (getRandom(100) < 20) { - snprintf(buffer, 80, " %s%s's life energy is gone!", _characterNamePt1, _characterNamePt2); + snprintf(buffer, 80, " %s%s's life energy is gone!", _characterNamePt1, _characterNamePt2.c_str()); strncat((char *)_messageToBePrinted, buffer, 80); _npcBuf[_teamCharId[var7E]]._hitPoints = 0; } diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 77bcf1b1e710..9d237900a39b 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -512,7 +512,7 @@ class EfhEngine : public Engine { char _enemyNamePt1[5]; Common::String _enemyNamePt2; char _characterNamePt1[5]; - char _characterNamePt2[20]; + Common::String _characterNamePt2; Common::String _nameBuffer; char _attackBuffer[20]; uint8 _messageToBePrinted[400]; From 8008d096bcbfcb29fa4ee61617c4b1eafb411c2f Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sat, 12 Nov 2022 08:55:53 +0100 Subject: [PATCH 156/412] EFH: Turn _characterNamePt1 into a Common::String --- engines/efh/efh.cpp | 82 ++++++++++++++++++++++----------------------- engines/efh/efh.h | 4 +-- 2 files changed, 43 insertions(+), 43 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index b0690260577e..252977caa222 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -233,8 +233,8 @@ EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst) memset(_characterNamePt1, 0, 5); _characterNamePt2 = ""; - memset(_enemyNamePt1, 0, 5); - _enemyNamePt2= ""; + _enemyNamePt1 = ""; + _enemyNamePt2 = ""; _nameBuffer = ""; memset(_attackBuffer, 0, 20); @@ -4008,21 +4008,21 @@ void EfhEngine::handleFight_checkEndEffect(int16 charId) { // At this point : The status is different to 0 (normal) and the effect duration is finally 0 (end of effect) _enemyNamePt2 = _npcBuf[_teamCharId[charId]]._name; if ((_npcBuf[_teamCharId[charId]]._possessivePronounSHL6 >> 6) == 2) { - strncpy(_enemyNamePt1, "The ", 5); + _enemyNamePt1 = "The "; } else { - _enemyNamePt1[0] = 0; + _enemyNamePt1 = ""; } // End of effect message depends on the type of effect switch (_teamCharStatus[charId]._status) { case 1: - snprintf((char *)_messageToBePrinted, 400, "%s%s wakes up!", _enemyNamePt1, _enemyNamePt2.c_str()); + snprintf((char *)_messageToBePrinted, 400, "%s%s wakes up!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str()); break; case 2: - snprintf((char *)_messageToBePrinted, 400, "%s%s thaws out!", _enemyNamePt1, _enemyNamePt2.c_str()); + snprintf((char *)_messageToBePrinted, 400, "%s%s thaws out!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str()); break; default: - snprintf((char *)_messageToBePrinted, 400, "%s%s recovers!", _enemyNamePt1, _enemyNamePt2.c_str()); + snprintf((char *)_messageToBePrinted, 400, "%s%s recovers!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str()); break; } @@ -4566,13 +4566,13 @@ bool EfhEngine::characterSearchesMonsterCorpse(int16 charId, int16 monsterId) { return true; } -void EfhEngine::getXPAndSearchCorpse(int16 charId, char *namePt1, char *namePt2, int16 monsterId) { - debug("getXPAndSearchCorpse %d %s%s %d", charId, namePt1, namePt2, monsterId); +void EfhEngine::getXPAndSearchCorpse(int16 charId, Common::String namePt1, Common::String namePt2, int16 monsterId) { + debug("getXPAndSearchCorpse %d %s%s %d", charId, namePt1.c_str(), namePt2.c_str(), monsterId); int16 xpLevel = getXPLevel(_npcBuf[charId]._xp); _npcBuf[charId]._xp += kEncounters[_mapMonsters[monsterId]._monsterRef]._xpGiven; char buffer[80]; - snprintf(buffer, 80, " %s%s gains %d experience", namePt1, namePt2, kEncounters[_mapMonsters[monsterId]._monsterRef]._xpGiven); + snprintf(buffer, 80, " %s%s gains %d experience", namePt1.c_str(), namePt2.c_str(), kEncounters[_mapMonsters[monsterId]._monsterRef]._xpGiven); if (getXPLevel(_npcBuf[charId]._xp) > xpLevel) { generateSound(15); int16 var2 = getRandom(20) + getRandom(_npcBuf[charId]._infoScore[4]); @@ -4815,9 +4815,9 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { } if (var70 == 2) { - snprintf(_enemyNamePt1, 5, "The "); + _enemyNamePt1 = "The "; } else { - *_enemyNamePt1 = 0; + _enemyNamePt1 = ""; } _characterNamePt2 = kEncounters[_mapMonsters[_teamMonsterIdArray[groupId]]._monsterRef]._name; @@ -4826,22 +4826,22 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { if (checkSpecialItemsOnCurrentPlace(unk_monsterField5_itemId)) { // Action A - Check damages - Start if (var62 == 0) { - snprintf((char *)_messageToBePrinted, 400, "%s%s %s at %s%s with %s %s, but misses!", _enemyNamePt1, _enemyNamePt2.c_str(), kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2.c_str(), kPossessive[var70], _nameBuffer.c_str()); + snprintf((char *)_messageToBePrinted, 400, "%s%s %s at %s%s with %s %s, but misses!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2.c_str(), kPossessive[var70], _nameBuffer.c_str()); } else if (hitPoints <= 0){ - snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s, but does no damage!", _enemyNamePt1, _enemyNamePt2.c_str(), kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2.c_str(), _attackBuffer, kPossessive[var70], _nameBuffer.c_str()); + snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s, but does no damage!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2.c_str(), _attackBuffer, kPossessive[var70], _nameBuffer.c_str()); } else if (hitPoints == 1) { - snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s for 1 point", _enemyNamePt1, _enemyNamePt2.c_str(), kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2.c_str(), _attackBuffer, kPossessive[var70], _nameBuffer.c_str()); + snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s for 1 point", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2.c_str(), _attackBuffer, kPossessive[var70], _nameBuffer.c_str()); if (_mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] <= 0) { getDeathTypeDescription(groupId, teamCharId + 1000); - getXPAndSearchCorpse(_teamCharId[teamCharId], _enemyNamePt1, (char *)_enemyNamePt2.c_str(), _teamMonsterIdArray[groupId]); + getXPAndSearchCorpse(_teamCharId[teamCharId], _enemyNamePt1, _enemyNamePt2, _teamMonsterIdArray[groupId]); } else { strncat((char *)_messageToBePrinted, "!", 2); } } else { - snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s for %d points", _enemyNamePt1, _enemyNamePt2.c_str(), kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2.c_str(), _attackBuffer, kPossessive[var70], _nameBuffer.c_str(), hitPoints); + snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s for %d points", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2.c_str(), _attackBuffer, kPossessive[var70], _nameBuffer.c_str(), hitPoints); if (_mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] <= 0) { getDeathTypeDescription(groupId, teamCharId + 1000); - getXPAndSearchCorpse(_teamCharId[teamCharId], _enemyNamePt1, (char *)_enemyNamePt2.c_str(), _teamMonsterIdArray[groupId]); + getXPAndSearchCorpse(_teamCharId[teamCharId], _enemyNamePt1, _enemyNamePt2, _teamMonsterIdArray[groupId]); } else { strncat((char *)_messageToBePrinted, "!", 2); } @@ -4894,7 +4894,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { if (var51 <= 0) { char buffer[80]; memset(buffer, 0, 80); - snprintf(buffer, 80, " * %s%s's %s breaks!", _enemyNamePt1, _enemyNamePt2.c_str(), _nameBuffer.c_str()); + snprintf(buffer, 80, " * %s%s's %s breaks!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), _nameBuffer.c_str()); strncat((char *)_messageToBePrinted, buffer, 80); setCharacterObjectToBroken(varInt, var64); var6E = false; @@ -4924,7 +4924,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { } // Action A - Check effect - End } else { - snprintf((char *)_messageToBePrinted, 400, "%s%s tries to use %s %s, but it doesn't work!", _enemyNamePt1, _enemyNamePt2.c_str(), kPossessive[var70], _nameBuffer.c_str()); + snprintf((char *)_messageToBePrinted, 400, "%s%s tries to use %s %s, but it doesn't work!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPossessive[var70], _nameBuffer.c_str()); } genericGenerateSound(_items[unk_monsterField5_itemId]._attackType, var62); @@ -4943,11 +4943,11 @@ void EfhEngine::handleFight_lastAction_D(int16 teamCharId) { int16 var70 = _npcBuf[_teamCharId[teamCharId]]._possessivePronounSHL6 >> 6; if (var70 == 2) - strncpy(_enemyNamePt1, "The ", 5); + _enemyNamePt1 = "The "; else - *_enemyNamePt1 = 0; + _enemyNamePt1 = ""; - snprintf((char *)_messageToBePrinted, 400, "%s%s prepares to defend %sself!", _enemyNamePt1, _enemyNamePt2.c_str(), kPersonal[var70]); + snprintf((char *)_messageToBePrinted, 400, "%s%s prepares to defend %sself!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPersonal[var70]); sub1C219(_messageToBePrinted, 1, 2, true); } @@ -4962,11 +4962,11 @@ void EfhEngine::handleFight_lastAction_H(int16 teamCharId) { int16 var70 = _npcBuf[_teamCharId[teamCharId]]._possessivePronounSHL6 >> 6; if (var70 == 2) - strncpy(_enemyNamePt1, "The ", 5); + _enemyNamePt1 = "The "; else - *_enemyNamePt1 = 0; + _enemyNamePt1 = ""; - snprintf((char *)_messageToBePrinted, 400, "%s%s attempts to hide %sself!", _enemyNamePt1, _enemyNamePt2.c_str(), kPersonal[var70]); + snprintf((char *)_messageToBePrinted, 400, "%s%s attempts to hide %sself!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPersonal[var70]); sub1C219(_messageToBePrinted, 1, 2, true); } @@ -4980,11 +4980,11 @@ void EfhEngine::handleFight_lastAction_U(int16 teamCharId) { _nameBuffer = _items[unk_monsterField5_itemId]._name; int16 var70 = _npcBuf[_teamCharId[teamCharId]]._possessivePronounSHL6 >> 6; if (var70 == 2) - snprintf(_enemyNamePt1, 5, "The "); + _enemyNamePt1 = "The "; else - *_enemyNamePt1 = 0; + _enemyNamePt1 = ""; - snprintf((char *)_messageToBePrinted, 400, "%s%s uses %s %s! ", _enemyNamePt1, _enemyNamePt2.c_str(), kPossessive[var70], _nameBuffer.c_str()); + snprintf((char *)_messageToBePrinted, 400, "%s%s uses %s %s! ", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPossessive[var70], _nameBuffer.c_str()); sub1C219(_messageToBePrinted, 1, 2, true); } @@ -5219,9 +5219,9 @@ bool EfhEngine::handleFight(int16 monsterId) { *_characterNamePt1 = 0; if (var7E == 2) - snprintf(_enemyNamePt1, 5, "The "); + _enemyNamePt1 = "The "; else - *_enemyNamePt1 = 0; + _enemyNamePt1 = ""; _enemyNamePt2 = kEncounters[_mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._monsterRef]._name; _characterNamePt2 = _npcBuf[_teamCharId[var7E]]._name; @@ -5229,17 +5229,17 @@ bool EfhEngine::handleFight(int16 monsterId) { if (checkSpecialItemsOnCurrentPlace(unk_monsterField5_itemId)) { // handleFight - check damages - Start if (var62 == 0) { - snprintf((char *)_messageToBePrinted, 400, "%s%s %s at %s%s with %s %s, but misses!", _enemyNamePt1, _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2.c_str(), kPossessive[var70], _nameBuffer.c_str()); + snprintf((char *)_messageToBePrinted, 400, "%s%s %s at %s%s with %s %s, but misses!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2.c_str(), kPossessive[var70], _nameBuffer.c_str()); } else if (hitPoints <= 0) { - snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s, but does no damage!", _enemyNamePt1, _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2.c_str(), _attackBuffer, kPossessive[var70], _nameBuffer.c_str()); + snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s, but does no damage!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2.c_str(), _attackBuffer, kPossessive[var70], _nameBuffer.c_str()); } else if (hitPoints == 1) { - snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s for 1 point", _enemyNamePt1, _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2.c_str(), _attackBuffer, kPossessive[var70], _nameBuffer.c_str()); + snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s for 1 point", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2.c_str(), _attackBuffer, kPossessive[var70], _nameBuffer.c_str()); if (_npcBuf[_teamCharId[var7E]]._hitPoints <= 0) getDeathTypeDescription(var7E + 1000, monsterGroupIdOrMonsterId); else strncat((char *)_messageToBePrinted, "!", 2); } else { - snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s for %d points", _enemyNamePt1, _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2.c_str(), _attackBuffer, kPossessive[var70], _nameBuffer.c_str(), hitPoints); + snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s for %d points", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2.c_str(), _attackBuffer, kPossessive[var70], _nameBuffer.c_str(), hitPoints); if (_npcBuf[_teamCharId[var7E]]._hitPoints <= 0) getDeathTypeDescription(var7E + 1000, monsterGroupIdOrMonsterId); else @@ -5316,7 +5316,7 @@ bool EfhEngine::handleFight(int16 monsterId) { } // handleFight - Check effect - end } else { - snprintf((char *)_messageToBePrinted, 400, "%s%s tries to use %s %s, but it doesn't work!", _enemyNamePt1, _enemyNamePt2.c_str(), kPossessive[var70], _nameBuffer.c_str()); + snprintf((char *)_messageToBePrinted, 400, "%s%s tries to use %s %s, but it doesn't work!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPossessive[var70], _nameBuffer.c_str()); } genericGenerateSound(_items[unk_monsterField5_itemId]._attackType, var62); sub1C219(_messageToBePrinted, 1, 2, true); @@ -5329,19 +5329,19 @@ bool EfhEngine::handleFight(int16 monsterId) { _enemyNamePt2 = kEncounters[_mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._monsterRef]._name; int16 var70 = kEncounters[_mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._monsterRef]._nameArticle; if (var70 == 2) - strncpy(_enemyNamePt1, "The ", 5); + _enemyNamePt1 = "The "; else - *_enemyNamePt1 = 0; + _enemyNamePt1 = ""; switch (_stru32686[monsterGroupIdOrMonsterId]._field0[var86]) { case 1: - snprintf((char *)_messageToBePrinted, 400, "%s%s wakes up!", _enemyNamePt1, _enemyNamePt2.c_str()); + snprintf((char *)_messageToBePrinted, 400, "%s%s wakes up!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str()); break; case 2: - snprintf((char *)_messageToBePrinted, 400, "%s%s thaws out!", _enemyNamePt1, _enemyNamePt2.c_str()); + snprintf((char *)_messageToBePrinted, 400, "%s%s thaws out!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str()); break; default: - snprintf((char *)_messageToBePrinted, 400, "%s%s recovers!", _enemyNamePt1, _enemyNamePt2.c_str()); + snprintf((char *)_messageToBePrinted, 400, "%s%s recovers!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str()); break; } _stru32686[monsterGroupIdOrMonsterId]._field0[var86] = 0; diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 9d237900a39b..e789a2328669 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -398,7 +398,7 @@ class EfhEngine : public Engine { bool hasAdequateDefense_2(int16 charId, uint8 attackType); void getDeathTypeDescription(int16 attackerId, int16 victimId); bool characterSearchesMonsterCorpse(int16 charId, int16 monsterId); - void getXPAndSearchCorpse(int16 charId, char* namePt1, char* namePt2, int16 monsterId); + void getXPAndSearchCorpse(int16 charId, Common::String namePt1, Common::String namePt2, int16 monsterId); void addReactionText(int16 id); void handleFight_lastAction_A(int16 teamCharId); void handleFight_lastAction_D(int16 teamCharId); @@ -509,7 +509,7 @@ class EfhEngine : public Engine { AnimInfo _animInfo[100]; uint8 _history[256]; uint8 _techData[4096]; - char _enemyNamePt1[5]; + Common::String _enemyNamePt1; Common::String _enemyNamePt2; char _characterNamePt1[5]; Common::String _characterNamePt2; From cf5dd14c7a1ac8fa898748924fd296291bfadc64 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sun, 13 Nov 2022 10:43:44 +0100 Subject: [PATCH 157/412] EFH: More conversions from char [] to Common::String --- engines/efh/efh.cpp | 73 ++++++++++++++++++---------------------- engines/efh/efh.h | 2 +- engines/efh/graphics.cpp | 8 ++--- 3 files changed, 37 insertions(+), 46 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 252977caa222..01505e5b03c5 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -1307,9 +1307,6 @@ void EfhEngine::displayLowStatusScreen(bool flag) { static char strMaxHp[7] = "Max HP"; static char strWeapon[7] = "Weapon"; static char strDead[9] = "* DEAD *"; - - char buffer[80]; - memset(buffer, 0, 80); for (int counter = 0; counter < 2; ++counter) { if (counter == 0 || flag) { @@ -1327,15 +1324,15 @@ void EfhEngine::displayLowStatusScreen(bool flag) { continue; int16 charId = _teamCharId[i]; int16 textPosY = 161 + 9 * i; - snprintf(buffer, 11, "%s", _npcBuf[charId]._name); + Common::String buffer = _npcBuf[charId]._name; setTextPos(16, textPosY); displayStringAtTextPos(buffer); - snprintf(buffer, 80, "%d", getEquipmentDefense(charId, false)); - displayCenteredString(buffer, 104, 128, textPosY); - snprintf(buffer, 80, "%d", _npcBuf[charId]._hitPoints); - displayCenteredString(buffer, 144, 176, textPosY); - snprintf(buffer, 80, "%d", _npcBuf[charId]._maxHP); - displayCenteredString(buffer, 192, 224, textPosY); + buffer = Common::String::format("%d", getEquipmentDefense(charId, false)); + displayCenteredString(buffer.c_str(), 104, 128, textPosY); + buffer = Common::String::format("%d", _npcBuf[charId]._hitPoints); + displayCenteredString(buffer.c_str(), 144, 176, textPosY); + buffer = Common::String::format("%d", _npcBuf[charId]._maxHP); + displayCenteredString(buffer.c_str(), 192, 224, textPosY); if (_npcBuf[charId]._hitPoints <= 0) { displayCenteredString(strDead, 225, 302, textPosY); @@ -3943,9 +3940,8 @@ void EfhEngine::sub1C4CA(bool whiteFl) { void EfhEngine::displayCombatMenu(int16 charId) { debug("displayCombatMenu %d", charId); - char buffer[80]; - copyString(_npcBuf[charId]._name, buffer); - strncat(buffer, ":", 2); + Common::String buffer = _npcBuf[charId]._name; + buffer += ":"; setTextColorWhite(); setTextPos(144, 7); displayStringAtTextPos(buffer); @@ -5484,32 +5480,30 @@ int16 EfhEngine::getXPLevel(int32 xp) { void EfhEngine::displayCharacterSummary(int16 curMenuLine, int16 npcId) { debug("displayCharacterSummary %d %d", curMenuLine, npcId); - char buffer1[40]; char buffer2[40]; - memset(buffer1, 0, 40); memset(buffer2, 0, 40); setTextColorRed(); - copyString(_npcBuf[npcId]._name, buffer1); + Common::String buffer1 = _npcBuf[npcId]._name; setTextPos(146, 27); displayStringAtTextPos("Name: "); displayStringAtTextPos(buffer1); - snprintf(buffer1, 40, "Level: %d", getXPLevel(_npcBuf[npcId]._xp)); + buffer1 = Common::String::format("Level: %d", getXPLevel(_npcBuf[npcId]._xp)); setTextPos(146, 36); displayStringAtTextPos(buffer1); - snprintf(buffer1, 40, "XP: %lu", _npcBuf[npcId]._xp); + buffer1 = Common::String::format("XP: %lu", _npcBuf[npcId]._xp); setTextPos(227, 36); displayStringAtTextPos(buffer1); - snprintf(buffer1, 40, "Speed: %d", _npcBuf[npcId]._speed); + buffer1 = Common::String::format("Speed: %d", _npcBuf[npcId]._speed); setTextPos(146, 45); displayStringAtTextPos(buffer1); - snprintf(buffer1, 40, "Defense: %d", getEquipmentDefense(npcId, false)); + buffer1 = Common::String::format("Defense: %d", getEquipmentDefense(npcId, false)); setTextPos(146, 54); displayStringAtTextPos(buffer1); - snprintf(buffer1, 40, "Hit Points: %d", _npcBuf[npcId]._hitPoints); + buffer1 = Common::String::format("Hit Points: %d", _npcBuf[npcId]._hitPoints); setTextPos(146, 63); displayStringAtTextPos(buffer1); - snprintf(buffer1, 40, "Max HP: %d", _npcBuf[npcId]._maxHP); + buffer1 = Common::String::format("Max HP: %d", _npcBuf[npcId]._maxHP); setTextPos(227, 63); displayStringAtTextPos(buffer1); displayCenteredString("Inventory", 144, 310, 72); @@ -5541,16 +5535,16 @@ void EfhEngine::displayCharacterSummary(int16 curMenuLine, int16 npcId) { setTextPos(152, textPosY); if (counter == curMenuLine) { - snprintf(buffer1, 40, "%c>", 'A' + counter); + buffer1 = Common::String::format("%c>", 'A' + counter); } else { - snprintf(buffer1, 40, "%c)", 'A' + counter); + buffer1 = Common::String::format("%c)", 'A' + counter); } displayStringAtTextPos(buffer1); if (itemId != 0x7FFF) { setTextPos(168, textPosY); copyString(_items[itemId]._name, buffer2); - snprintf(buffer1, 40, " %s", buffer2); + buffer1 = Common::String::format(" %s", buffer2); displayStringAtTextPos(buffer1); setTextPos(262, textPosY); @@ -5560,7 +5554,7 @@ void EfhEngine::displayCharacterSummary(int16 curMenuLine, int16 npcId) { // useless? var54 = _items[_npcBuf[npcId]._inventory[_word3273A[counter]]._ref]._defense; } else { - snprintf(buffer1, 40, "%d", 1 + var54 / 8); + buffer1 = Common::String::format("%d", 1 + var54 / 8); displayStringAtTextPos(buffer1); setTextPos(286, textPosY); displayStringAtTextPos("Def"); @@ -5568,7 +5562,7 @@ void EfhEngine::displayCharacterSummary(int16 curMenuLine, int16 npcId) { } else if (_items[itemId]._uses != 0x7F) { int16 var52 = _npcBuf[npcId]._inventory[_word3273A[counter]]._stat1; if (var52 != 0x7F) { - snprintf(buffer1, 40, "%d", var52); + buffer1 = Common::String::format("%d", var52); displayStringAtTextPos(buffer1); setTextPos(286, textPosY); if (var52 == 1) @@ -5585,11 +5579,8 @@ void EfhEngine::displayCharacterSummary(int16 curMenuLine, int16 npcId) { void EfhEngine::displayCharacterInformationOrSkills(int16 curMenuLine, int16 charId) { debug("displayCharacterInformationOrSkills %d %d", curMenuLine, charId); - char buffer[40]; - memset(buffer, 0, 40); - setTextColorRed(); - copyString(_npcBuf[charId]._name, buffer); + Common::String buffer = _npcBuf[charId]._name; setTextPos(146, 27); displayStringAtTextPos("Name: "); displayStringAtTextPos(buffer); @@ -5607,15 +5598,15 @@ void EfhEngine::displayCharacterInformationOrSkills(int16 curMenuLine, int16 cha int16 textPosY = 38 + counter * 9; setTextPos(146, textPosY); if (counter == curMenuLine) { - snprintf(buffer, 40, "%c>", 'A' + counter); + buffer = Common::String::format("%c>", 'A' + counter); } else { - snprintf(buffer, 40, "%c)", 'A' + counter); + buffer = Common::String::format("%c)", 'A' + counter); } displayStringAtTextPos(buffer); setTextPos(163, textPosY); displayStringAtTextPos(kSkillArray[_word3273A[counter]]); - snprintf(buffer, 40, "%d", _npcBuf[charId]._activeScore[_word3273A[counter]]); + buffer = Common::String::format("%d", _npcBuf[charId]._activeScore[_word3273A[counter]]); setTextPos(278, textPosY); displayStringAtTextPos(buffer); setTextColorRed(); @@ -6760,7 +6751,6 @@ bool EfhEngine::checkMonsterCollision() { int16 var68 = 0; char dest[20]; - char buffer[80]; int16 monsterId; for (monsterId = 0; monsterId < 64; ++monsterId) { @@ -6792,6 +6782,7 @@ bool EfhEngine::checkMonsterCollision() { ++var6A; } + Common::String buffer = ""; do { for (int16 var6C = 0; var6C < 2; ++var6C) { int16 var1 = _mapMonsters[monsterId]._possessivePronounSHL6 & 0x3F; @@ -6800,30 +6791,30 @@ bool EfhEngine::checkMonsterCollision() { if (var6A > 1) strncat(dest, " ", 2); - snprintf(buffer, 80, "with %d %s", var6A, dest); + buffer = Common::String::format("with %d %s", var6A, dest); } else if (var1 == 0x3E) { - strncpy(buffer, "(NOT DEFINED)", 80); + buffer = "(NOT DEFINED)"; } else if (var1 == 0x3F) { // Useless check, it's the last possible value // Special character name copyString(_npcBuf[_mapMonsters[monsterId]._field_1]._name, dest); - snprintf(buffer, 80, "with %s", dest); + buffer = Common::String::format("with %s", dest); } clearBottomTextZone(0); _textColor = 0xE; displayCenteredString("Interaction", 24, 296, 152); - displayCenteredString(buffer, 24, 296, 161); + displayCenteredString(buffer.c_str(), 24, 296, 161); setTextPos(24, 169); setTextColorWhite(); displayStringAtTextPos("T"); setTextColorRed(); - snprintf(buffer, 80, "alk to the %s", dest); + buffer = Common::String::format("alk to the %s", dest); displayStringAtTextPos(buffer); setTextPos(24, 178); setTextColorWhite(); displayStringAtTextPos("A"); setTextColorRed(); - snprintf(buffer, 80, "ttack the %s", dest); + buffer = Common::String::format("ttack the %s", dest); displayStringAtTextPos(buffer); setTextPos(198, 169); setTextColorWhite(); diff --git a/engines/efh/efh.h b/engines/efh/efh.h index e789a2328669..a299e7421a79 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -455,7 +455,7 @@ class EfhEngine : public Engine { void setTextColorWhite(); void setTextColorRed(); void setTextColorGrey(); - void displayStringAtTextPos(const char *message); + void displayStringAtTextPos(Common::String message); void clearBottomTextZone(int16 color); void clearBottomTextZone_2(int16 color); void setNextCharacterPos(); diff --git a/engines/efh/graphics.cpp b/engines/efh/graphics.cpp index c31fdc61e385..486fd75ecdc6 100644 --- a/engines/efh/graphics.cpp +++ b/engines/efh/graphics.cpp @@ -337,11 +337,11 @@ void EfhEngine::setTextColorGrey() { _textColor = 0x8; } -void EfhEngine::displayStringAtTextPos(const char *message) { - debugC(1, kDebugGraphics, "displayStringAtTextPos %s", message); +void EfhEngine::displayStringAtTextPos(Common::String message) { + debugC(1, kDebugGraphics, "displayStringAtTextPos %s", message.c_str()); - drawString(message, _textPosX, _textPosY, _textColor); - _textPosX += getStringWidth(message) + 1; + drawString(message.c_str(), _textPosX, _textPosY, _textColor); + _textPosX += getStringWidth(message.c_str()) + 1; setNextCharacterPos(); } From 0258f7009fbd322f1218fefea3350668a0cd81d3 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Mon, 14 Nov 2022 20:01:46 +0100 Subject: [PATCH 158/412] EFH: more work on Common::String, somehow fix a crash in dialogs --- engines/efh/efh.cpp | 211 ++++++++++++++++++++------------------------ 1 file changed, 98 insertions(+), 113 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 01505e5b03c5..494a118c351c 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -3903,8 +3903,7 @@ void EfhEngine::sub1C4CA(bool whiteFl) { } else if (var1 == 0x3E) { displayStringAtTextPos("(NOT DEFINED)"); } else if (var1 == 0x3F) { - char stringToDisplay[20]; - copyString(_npcBuf[_mapMonsters[_teamMonsterIdArray[counter]]._field_1]._name, stringToDisplay); + Common::String stringToDisplay = _npcBuf[_mapMonsters[_teamMonsterIdArray[counter]]._field_1]._name; displayStringAtTextPos(stringToDisplay); } @@ -4554,11 +4553,8 @@ bool EfhEngine::characterSearchesMonsterCorpse(int16 charId, int16 monsterId) { if (!giveItemTo(charId, itemId, 0xFF)) return false; - char tmpString[20]; - copyString(_items[itemId]._name, tmpString); - char buffer[80]; - snprintf(buffer, 80, " and finds a %s!", tmpString); - strncat((char *)_messageToBePrinted, buffer, 80); + Common::String buffer = Common::String::format(" and finds a %s!", _items[itemId]._name); + strncat((char *)_messageToBePrinted, buffer.c_str(), buffer.size() + 1); return true; } @@ -5005,8 +5001,6 @@ void EfhEngine::sub1D8C2(int16 charId, int16 damage) { int16 var42 = 0; int16 var40 = _npcBuf[charId]._possessivePronounSHL6 / 64; - char buffer[40]; - char buffer2[20]; if (var40 > 2) { var40 = 2; @@ -5023,17 +5017,17 @@ void EfhEngine::sub1D8C2(int16 charId, int16 damage) { _npcBuf[charId]._inventory[objectId]._stat2 -= damage; if (_npcBuf[charId]._inventory[objectId]._stat2 <= 0) { - copyString(_items[_npcBuf[charId]._inventory[objectId]._ref]._name, buffer2); + Common::String buffer2 = _items[_npcBuf[charId]._inventory[objectId]._ref]._name; removeObject(charId, objectId); if (var42 == 0) { var42 = 1; - snprintf(buffer, 40, ", but %s %s", kPossessive[var40], buffer2); - strncat((char *)_messageToBePrinted, buffer, 40); + Common::String buffer = Common::String::format(", but %s ", kPossessive[var40]) + buffer2; + strncat((char *)_messageToBePrinted, buffer.c_str(), 40); } else { ++var42; - snprintf(buffer, 40, ", %s", buffer2); - strncat((char *)_messageToBePrinted, buffer, 40); + Common::String buffer = Common::String(", ") + buffer2; + strncat((char *)_messageToBePrinted, buffer.c_str(), 40); } } @@ -5480,9 +5474,6 @@ int16 EfhEngine::getXPLevel(int32 xp) { void EfhEngine::displayCharacterSummary(int16 curMenuLine, int16 npcId) { debug("displayCharacterSummary %d %d", curMenuLine, npcId); - char buffer2[40]; - memset(buffer2, 0, 40); - setTextColorRed(); Common::String buffer1 = _npcBuf[npcId]._name; setTextPos(146, 27); @@ -5543,8 +5534,7 @@ void EfhEngine::displayCharacterSummary(int16 curMenuLine, int16 npcId) { if (itemId != 0x7FFF) { setTextPos(168, textPosY); - copyString(_items[itemId]._name, buffer2); - buffer1 = Common::String::format(" %s", buffer2); + buffer1 = Common::String::format(" %s", _items[itemId]._name); displayStringAtTextPos(buffer1); setTextPos(262, textPosY); @@ -5816,8 +5806,7 @@ int16 EfhEngine::selectOtherCharFromTeam() { int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine, int16 argA) { debug("sub19E2E %d %d %d %d %d %d", charId, objectId, windowId, menuId, curMenuLine, argA); - char buffer1[80]; - char buffer2[80]; + Common::String buffer1 = ""; bool varA6 = false; bool retVal = false; @@ -5854,11 +5843,11 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me } // The original was duplicating this code in each branch of the previous random check. if (victims > 1) { - snprintf(buffer1, 80, "%d %ss fall asleep!", victims, kEncounters[_mapMonsters[_teamMonsterIdArray[windowId]]._monsterRef]._name); + buffer1 = Common::String::format("%d %ss fall asleep!", victims, kEncounters[_mapMonsters[_teamMonsterIdArray[windowId]]._monsterRef]._name); } else { - snprintf(buffer1, 80, "%d %s falls asleep!", victims, kEncounters[_mapMonsters[_teamMonsterIdArray[windowId]]._monsterRef]._name); + buffer1 = Common::String::format("%d %s falls asleep!", victims, kEncounters[_mapMonsters[_teamMonsterIdArray[windowId]]._monsterRef]._name); } - strncat((char *)_messageToBePrinted, buffer1, 400); + strncat((char *)_messageToBePrinted, buffer1.c_str(), 400); } varA6 = true; @@ -5894,11 +5883,11 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me // : This part is only present in the original in the case < 50, but for me // it's missing in the other case as there's an effect (frozen enemies) but no feedback to the player if (victim > 1) { - snprintf(buffer1, 80, "%d %ss are frozen in place!", victim, kEncounters[_mapMonsters[_teamMonsterIdArray[windowId]]._monsterRef]._name); + buffer1 = Common::String::format("%d %ss are frozen in place!", victim, kEncounters[_mapMonsters[_teamMonsterIdArray[windowId]]._monsterRef]._name); } else { - snprintf(buffer1, 80, "%d %s is frozen in place!", victim, kEncounters[_mapMonsters[_teamMonsterIdArray[windowId]]._monsterRef]._name); + buffer1 = Common::String::format("%d %s is frozen in place!", victim, kEncounters[_mapMonsters[_teamMonsterIdArray[windowId]]._monsterRef]._name); } - strncat((char *)_messageToBePrinted, buffer1, 80); + strncat((char *)_messageToBePrinted, buffer1.c_str(), 80); // } @@ -5978,11 +5967,11 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me } if (varAA != 0x1B) { - strncpy(buffer1, " The magic makes the user as quick and agile as a bird!", 80); + buffer1 = " The magic makes the user as quick and agile as a bird!"; if (argA == 2) { - displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + displayString_3(buffer1.c_str(), false, charId, windowId, menuId, curMenuLine); } else { - strncat((char *)_messageToBePrinted, buffer1, 80); + strncat((char *)_messageToBePrinted, buffer1.c_str(), 80); } _word32482[varAA] -= 50; if (_word32482[varAA] < 0) @@ -6002,11 +5991,11 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me } if (teamCharId != 0x1B) { - strncpy(buffer1, " The magic makes the user invisible!", 80); + buffer1 = " The magic makes the user invisible!"; if (argA == 2) { - displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + displayString_3(buffer1.c_str(), false, charId, windowId, menuId, curMenuLine); } else { - strncat((char *)_messageToBePrinted, buffer1, 80); + strncat((char *)_messageToBePrinted, buffer1.c_str(), 80); } _word32680[teamCharId] -= 50; @@ -6026,29 +6015,29 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me if (_tileFact[varAE]._field0 == 0) { totalPartyKill(); - strncpy(buffer1, "The entire party vanishes in a flash... only to appear in stone !", 80); + buffer1 = "The entire party vanishes in a flash... only to appear in stone !"; if (argA == 2) { - displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + displayString_3(buffer1.c_str(), false, charId, windowId, menuId, curMenuLine); } else { - strncat((char *)_messageToBePrinted, buffer1, 80); + strncat((char *)_messageToBePrinted, buffer1.c_str(), 80); retVal = true; } // emptyFunction(2); } else { if (varAE == 0 || varAE == 0x48) { - strncpy(buffer1, "The entire party vanishes in a flash...but re-appears, as if nothing happened!", 80); + buffer1 = "The entire party vanishes in a flash...but re-appears, as if nothing happened!"; if (argA == 2) { - displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + displayString_3(buffer1.c_str(), false, charId, windowId, menuId, curMenuLine); } else { - strncat((char *)_messageToBePrinted, buffer1, 80); + strncat((char *)_messageToBePrinted, buffer1.c_str(), 80); retVal = true; } } else { - strncpy(buffer1, "The entire party vanishes in a flash...only to appear elsewhere!", 80); + buffer1 = "The entire party vanishes in a flash...only to appear elsewhere!"; if (argA == 2) { - displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + displayString_3(buffer1.c_str(), false, charId, windowId, menuId, curMenuLine); } else { - strncat((char *)_messageToBePrinted, buffer1, 80); + strncat((char *)_messageToBePrinted, buffer1.c_str(), 80); retVal = true; } } @@ -6063,29 +6052,29 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me int16 varAE = sub15538(_mapPosX, _mapPosY); if (_tileFact[varAE]._field0 == 0) { totalPartyKill(); - strncpy(buffer1, "The entire party vanishes in a flash... only to appear in stone !", 80); + buffer1 = "The entire party vanishes in a flash... only to appear in stone !"; if (argA == 2) { - displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + displayString_3(buffer1.c_str(), false, charId, windowId, menuId, curMenuLine); } else { - strncat((char *)_messageToBePrinted, buffer1, 80); + strncat((char *)_messageToBePrinted, buffer1.c_str(), 80); retVal = true; } // emptyFunction(2); } else { if (varAE == 0 || varAE == 0x48) { - strncpy(buffer1, "The entire party vanishes in a flash...but re-appears, as if nothing happened!", 80); + buffer1 = "The entire party vanishes in a flash...but re-appears, as if nothing happened!"; if (argA == 2) { - displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + displayString_3(buffer1.c_str(), false, charId, windowId, menuId, curMenuLine); } else { - strncat((char *)_messageToBePrinted, buffer1, 80); + strncat((char *)_messageToBePrinted, buffer1.c_str(), 80); retVal = true; } } else { - strncpy(buffer1, "The entire party vanishes in a flash...only to appear elsewhere!",80); + buffer1 = "The entire party vanishes in a flash...only to appear elsewhere!"; if (argA == 2) { - displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + displayString_3(buffer1.c_str(), false, charId, windowId, menuId, curMenuLine); } else { - strncat((char *)_messageToBePrinted, buffer1, 80); + strncat((char *)_messageToBePrinted, buffer1.c_str(), 80); retVal = true; } } @@ -6113,48 +6102,47 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me varA6 = true; break; case 19: // "Junk" - strncpy(buffer1, " * The item breaks!", 80); + buffer1 = " * The item breaks!"; if (argA == 2) { - displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + displayString_3(buffer1.c_str(), false, charId, windowId, menuId, curMenuLine); } else { - strncat((char *)_messageToBePrinted, buffer1, 80); + strncat((char *)_messageToBePrinted, buffer1.c_str(), 80); } setCharacterObjectToBroken(charId, objectId); varA6 = true; break; case 23: // "Divining Rod" - copyString(_items[itemId]._name, buffer2); - snprintf(buffer1, 80, "The %s says, '", buffer2); + buffer1 = Common::String::format("The %s says, '", _items[itemId]._name); if (_items[itemId].field_19 < _mapPosX) { if (_items[itemId].field_1A < _mapPosY) { - strncat(buffer1, "North West!", 80); + buffer1 += "North West!"; } else if (_items[itemId].field_1A > _mapPosY) { - strncat(buffer1, "South West!", 80); + buffer1 += "South West!"; } else { - strncat(buffer1, "West!", 80); + buffer1 += "West!"; } } else if (_items[itemId].field_19 > _mapPosX) { if (_items[itemId].field_1A < _mapPosY) { - strncat(buffer1, "North East!", 80); + buffer1 += "North East!"; } else if (_items[itemId].field_1A > _mapPosY) { - strncat(buffer1, "South East!", 80); + buffer1 += "South East!"; } else { - strncat(buffer1, "East!", 80); + buffer1 += "East!"; } } else { // equals _mapPosX if (_items[itemId].field_1A < _mapPosY) { - strncat(buffer1, "North!", 80); + buffer1 += "North!"; } else if (_items[itemId].field_1A > _mapPosY) { - strncat(buffer1, "South!", 80); + buffer1 += "South!"; } else { - strncat(buffer1, "Here!!!",80); + buffer1 += "Here!!!"; } } - strncat(buffer1, "'", 2); + buffer1 += "'"; if (argA == 2) { - displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + displayString_3(buffer1.c_str(), false, charId, windowId, menuId, curMenuLine); } else { - strncat((char *)_messageToBePrinted, buffer1, 80); + strncat((char *)_messageToBePrinted, buffer1.c_str(), 80); retVal = true; } @@ -6176,14 +6164,14 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me _npcBuf[_teamCharId[teamCharId]]._activeScore[varAE] = 20; } if (effectPoints > 1) - snprintf(buffer1, 80, "%s increased %d points!", kSkillArray[varAE], effectPoints); + buffer1 = Common::String::format("%s increased %d points!", kSkillArray[varAE], effectPoints); else - snprintf(buffer1, 80, "%s increased 1 point!", kSkillArray[varAE]); + buffer1 = Common::String::format("%s increased 1 point!", kSkillArray[varAE]); if (argA == 2) { - displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + displayString_3(buffer1.c_str(), false, charId, windowId, menuId, curMenuLine); } else { - strncat((char *)_messageToBePrinted, buffer1, 80); + strncat((char *)_messageToBePrinted, buffer1.c_str(), 80); retVal = true; } } @@ -6207,14 +6195,14 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me _npcBuf[_teamCharId[teamCharId]]._activeScore[varAE] = 1; } if (effectPoints > 1) - snprintf(buffer1, 80, "%s lowered %d points!", kSkillArray[varAE], effectPoints); + buffer1 = Common::String::format("%s lowered %d points!", kSkillArray[varAE], effectPoints); else - snprintf(buffer1, 80, "%s lowered 1 point!", kSkillArray[varAE]); + buffer1 = Common::String::format("%s lowered 1 point!", kSkillArray[varAE]); if (argA == 2) { - displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + displayString_3(buffer1.c_str(), false, charId, windowId, menuId, curMenuLine); } else { - strncat((char *)_messageToBePrinted, buffer1, 80); + strncat((char *)_messageToBePrinted, buffer1.c_str(), 80); retVal = true; } } @@ -6223,11 +6211,11 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me } break; case 26: // "Black Sphere" - strncpy(buffer1, "The entire party collapses, dead!!!", 80); + buffer1 = "The entire party collapses, dead!!!"; if (argA == 2) { - displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + displayString_3(buffer1.c_str(), false, charId, windowId, menuId, curMenuLine); } else { - strncat((char *)_messageToBePrinted, buffer1, 80); + strncat((char *)_messageToBePrinted, buffer1.c_str(), 80); retVal = true; } totalPartyKill(); @@ -6245,12 +6233,11 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me if (teamCharId != 0x1B) { _npcBuf[_teamCharId[teamCharId]]._hitPoints = 0; - copyString(_npcBuf[_teamCharId[teamCharId]]._name, buffer2); - snprintf(buffer1, 80, "%s collapses, dead!!!", buffer2); + buffer1 = Common::String::format("%s collapses, dead!!!", _npcBuf[_teamCharId[teamCharId]]._name); if (argA == 2) { - displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + displayString_3(buffer1.c_str(), false, charId, windowId, menuId, curMenuLine); } else { - strncat((char *)_messageToBePrinted, buffer1, 80); + strncat((char *)_messageToBePrinted, buffer1.c_str(), 80); retVal = true; } // emptyFunction(2); @@ -6287,22 +6274,21 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me } if (teamCharId != 0x1B) { - int16 varAE = getRandom(_items[itemId].field17_attackTypeDefense); - _npcBuf[_teamCharId[teamCharId]]._hitPoints += varAE; + int16 effectPoints = getRandom(_items[itemId].field17_attackTypeDefense); + _npcBuf[_teamCharId[teamCharId]]._hitPoints += effectPoints; if (_npcBuf[_teamCharId[teamCharId]]._hitPoints > _npcBuf[_teamCharId[teamCharId]]._maxHP) _npcBuf[_teamCharId[teamCharId]]._hitPoints = _npcBuf[_teamCharId[teamCharId]]._maxHP; - copyString(_npcBuf[_teamCharId[teamCharId]]._name, buffer2); - if (varAE > 1) - snprintf(buffer1, 80, "%s is healed %d points!", buffer2, varAE); + if (effectPoints > 1) + buffer1 = Common::String::format("%s is healed %d points!", _npcBuf[_teamCharId[teamCharId]]._name, effectPoints); else - snprintf(buffer1, 80, "%s is healed 1 point!", buffer2); + buffer1 = Common::String::format("%s is healed 1 point!", _npcBuf[_teamCharId[teamCharId]]._name); } if (argA == 2) { - displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + displayString_3(buffer1.c_str(), false, charId, windowId, menuId, curMenuLine); } else { - strncat((char *)_messageToBePrinted, buffer1, 80); + strncat((char *)_messageToBePrinted, buffer1.c_str(), 80); retVal = true; } @@ -6319,22 +6305,21 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me } if (teamCharId != 0x1B) { - int16 varAE = getRandom(_items[itemId].field17_attackTypeDefense); - _npcBuf[_teamCharId[teamCharId]]._hitPoints -= varAE; + int16 effectPoints = getRandom(_items[itemId].field17_attackTypeDefense); + _npcBuf[_teamCharId[teamCharId]]._hitPoints -= effectPoints; if (_npcBuf[_teamCharId[teamCharId]]._hitPoints < 0) _npcBuf[_teamCharId[teamCharId]]._hitPoints = 0; - copyString(_npcBuf[_teamCharId[teamCharId]]._name, buffer2); - if (varAE > 1) - snprintf(buffer1, 80, "%s is harmed for %d points!", buffer2, varAE); + if (effectPoints > 1) + buffer1 = Common::String::format("%s is harmed for %d points!", _npcBuf[_teamCharId[teamCharId]]._name, effectPoints); else - snprintf(buffer1, 80, "%s is harmed for 1 point!", buffer2); + buffer1 = Common::String::format("%s is harmed for 1 point!", _npcBuf[_teamCharId[teamCharId]]._name); } if (argA == 2) { - displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + displayString_3(buffer1.c_str(), false, charId, windowId, menuId, curMenuLine); } else { - strncat((char *)_messageToBePrinted, buffer1, 80); + strncat((char *)_messageToBePrinted, buffer1.c_str(), 80); retVal = true; } @@ -6361,12 +6346,12 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me if ((_npcBuf[charId]._inventory[objectId]._stat1 & 0x7F) != 0x7F) { int8 varA1 = (_npcBuf[charId]._inventory[objectId]._stat1 & 0x7F) - 1; if (varA1 <= 0) { - strncpy(buffer1, " * The item breaks!", 80); + buffer1 = " * The item breaks!"; if (argA == 2) { Common::KeyCode varAE = getLastCharAfterAnimCount(_guessAnimationAmount); - displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + displayString_3(buffer1.c_str(), false, charId, windowId, menuId, curMenuLine); } else { - strncat((char *)_messageToBePrinted, buffer1, 80); + strncat((char *)_messageToBePrinted, buffer1.c_str(), 80); } setCharacterObjectToBroken(charId, objectId); } else { @@ -6750,10 +6735,8 @@ bool EfhEngine::checkMonsterCollision() { debug("checkMonsterCollision"); int16 var68 = 0; - char dest[20]; - - int16 monsterId; - for (monsterId = 0; monsterId < 64; ++monsterId) { + + for (int16 monsterId = 0; monsterId < 64; ++monsterId) { if (!checkPictureRefAvailability(monsterId)) continue; @@ -6786,18 +6769,20 @@ bool EfhEngine::checkMonsterCollision() { do { for (int16 var6C = 0; var6C < 2; ++var6C) { int16 var1 = _mapMonsters[monsterId]._possessivePronounSHL6 & 0x3F; + Common::String dest; if (var1 <= 0x3D) { - strncpy(dest, kEncounters[_mapMonsters[monsterId]._monsterRef]._name, 80); + dest = kEncounters[_mapMonsters[monsterId]._monsterRef]._name; if (var6A > 1) - strncat(dest, " ", 2); + dest += "s"; - buffer = Common::String::format("with %d %s", var6A, dest); + buffer = Common::String::format("with %d ", var6A) + dest; } else if (var1 == 0x3E) { buffer = "(NOT DEFINED)"; + dest = "(NOT DEFINED)"; } else if (var1 == 0x3F) { // Useless check, it's the last possible value // Special character name - copyString(_npcBuf[_mapMonsters[monsterId]._field_1]._name, dest); - buffer = Common::String::format("with %s", dest); + dest = _npcBuf[_mapMonsters[monsterId]._field_1]._name; + buffer = Common::String("with ") + dest; } clearBottomTextZone(0); @@ -6808,13 +6793,13 @@ bool EfhEngine::checkMonsterCollision() { setTextColorWhite(); displayStringAtTextPos("T"); setTextColorRed(); - buffer = Common::String::format("alk to the %s", dest); + buffer = Common::String("alk to the ") + dest; displayStringAtTextPos(buffer); setTextPos(24, 178); setTextColorWhite(); displayStringAtTextPos("A"); setTextColorRed(); - buffer = Common::String::format("ttack the %s", dest); + buffer = Common::String("ttack the ") + dest; displayStringAtTextPos(buffer); setTextPos(198, 169); setTextColorWhite(); From 2d6f4f7f17404111b9c4afa0aad6f6104be607e7 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Tue, 15 Nov 2022 01:05:23 +0100 Subject: [PATCH 159/412] EFH: "Remove" copyString() --- engines/efh/efh.h | 2 +- engines/efh/utils.cpp | 25 ++++++++++++++----------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/engines/efh/efh.h b/engines/efh/efh.h index a299e7421a79..150347d05f6c 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -464,7 +464,7 @@ class EfhEngine : public Engine { void displayColoredMenuBox(int16 minX, int16 minY, int16 maxX, int16 maxY, int16 color); // Utils - #if true + #if false void copyString(char *srcStr, char *destStr); #endif int32 readFileToBuffer(Common::String &filename, uint8 *destBuffer); diff --git a/engines/efh/utils.cpp b/engines/efh/utils.cpp index ee23a0679e72..e621d91b37a1 100644 --- a/engines/efh/utils.cpp +++ b/engines/efh/utils.cpp @@ -26,6 +26,20 @@ namespace Efh { +#if 0 +// Note : The original engine is using copyString(src, dest). It has been replaced either by a string assignment or a snprintf +void EfhEngine::copyString(char *srcStr, char *destStr) { + debugC(1, kDebugUtils, "copyString %s", srcStr); + char lastChar = 1; + int16 idx = 0; + + while (lastChar != 0) { + lastChar = destStr[idx] = srcStr[idx]; + ++idx; + } +} +#endif + int32 EfhEngine::readFileToBuffer(Common::String &filename, uint8 *destBuffer) { debugC(1, kDebugUtils, "readFileToBuffer %s", filename.c_str()); Common::File f; @@ -323,17 +337,6 @@ void EfhEngine::setNumLock() { // No implementation in ScummVM } -void EfhEngine::copyString(char *srcStr, char *destStr) { - debugC(1, kDebugUtils, "copyString %s", srcStr); - char lastChar = 1; - int16 idx = 0; - - while (lastChar != 0) { - lastChar = destStr[idx] = srcStr[idx]; - ++idx; - } -} - bool EfhEngine::getValidationFromUser() { debugC(1, kDebugUtils, "getValidationFromUser"); Common::KeyCode input = handleAndMapInput(true); From 8251081c093ecc0a6c3fb0c96c857a02db8cb4de Mon Sep 17 00:00:00 2001 From: Strangerke Date: Fri, 18 Nov 2022 12:03:24 +0100 Subject: [PATCH 160/412] EFH: Start preparing TECH and MAP files for savegames --- engines/efh/efh.cpp | 28 ++++++++++++++++++++-------- engines/efh/efh.h | 5 ++++- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 494a118c351c..26983e13711c 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -332,7 +332,8 @@ EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst) memset(_tileFact, 0, ARRAYSIZE(_tileFact)); memset(_animInfo, 0, ARRAYSIZE(_animInfo)); memset(_history, 0, ARRAYSIZE(_history)); - memset(_techData, 0, ARRAYSIZE(_techData)); + for(int i = 0; i < 20; ++i) + memset(_techDataArr[i], 0, ARRAYSIZE(_techDataArr[i])); memset(_mapMonsters, 0, ARRAYSIZE(_mapMonsters)); memset(_mapGameMap, 0, ARRAYSIZE(_mapGameMap)); memset(_imageSetSubFilesArray, 0, ARRAYSIZE(_imageSetSubFilesArray)); @@ -681,11 +682,7 @@ void EfhEngine::loadTechMapImp(int16 fileId) { _techId = fileId; findMapFile(_techId); - Common::String fileName = Common::String::format("tech.%d", _techId); - readFileToBuffer(fileName, _hiResImageBuf); - uncompressBuffer(_hiResImageBuf, _techData); - - fileName = Common::String::format("map.%d", _techId); + Common::String fileName = Common::String::format("map.%d", _techId); readFileToBuffer(fileName, _hiResImageBuf); uncompressBuffer(_hiResImageBuf, _map); // This is not present in the original. @@ -934,6 +931,18 @@ void EfhEngine::playIntro() { getLastCharAfterAnimCount(80); } +/** + * Pre-Loads MAP and TECH files. + * This is required in order to implement a clean savegame feature + */ +void EfhEngine::preLoadMaps() { + for (int i = 0; i < 19; ++i) { + Common::String fileName = Common::String::format("tech.%d", _techId); + readFileToBuffer(fileName, _hiResImageBuf); + uncompressBuffer(_hiResImageBuf, _techDataArr[_techId]); + } +} + void EfhEngine::initEngine() { _videoMode = 2; // In the original, 2 = VGA/MCGA, EGA = 4, Tandy = 6, cga = 8. _graphicsStruct = new EfhGraphicsStruct; @@ -957,6 +966,9 @@ void EfhEngine::initEngine() { _fontDescr._extraHorizontalSpace = 1; _word31E9E = false; + // Pre-load stuff required for savegames + preLoadMaps(); + saveAnimImageSetId(); // Load Title Screen @@ -2159,7 +2171,7 @@ void EfhEngine::sub2455E(int16 arg0, int16 arg2, int16 arg4) { for (int16 var4 = varC; var4 <= var8; ++var4) { for (int16 var2 = varA; var2 <= var6; ++var2) { - _techData[var2 + var4 * 64] = varD; + _techDataArr[_techId][var2 + var4 * 64] = varD; } } } @@ -4146,7 +4158,7 @@ int16 EfhEngine::getCharacterScore(int16 charId, int16 itemId) { bool EfhEngine::checkSpecialItemsOnCurrentPlace(int16 itemId) { debug("checkSpecialItemsOnCurrentPlace %d", itemId); - switch(_techData[_techDataId_MapPosX * 64 + _techDataId_MapPosY]) { + switch(_techDataArr[_techId][_techDataId_MapPosX * 64 + _techDataId_MapPosY]) { case 1: if ((itemId < 0x58 || itemId > 0x68) && (itemId < 0x86 || itemId > 0x89) && (itemId < 0x74 || itemId > 0x76) && (itemId != 0x8C)) return true; diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 150347d05f6c..1dedbf29610b 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -289,6 +289,7 @@ class EfhEngine : public Engine { Common::KeyCode playSong(uint8 *buffer); void readImpFile(int16 id, bool techMapFl); void playIntro(); + void preLoadMaps(); void initEngine(); void initMapMonsters(); void loadMapArrays(); @@ -508,7 +509,7 @@ class EfhEngine : public Engine { TileFactStruct _tileFact[432]; AnimInfo _animInfo[100]; uint8 _history[256]; - uint8 _techData[4096]; + uint8 _techDataArr[19][4100]; Common::String _enemyNamePt1; Common::String _enemyNamePt2; char _characterNamePt1[5]; @@ -575,9 +576,11 @@ class EfhEngine : public Engine { uint16 _tempTextDelay; uint8 *_tempTextPtr; + // TODO: Remove those useless debug flags bool _dbgForceDisplayUpperRightBorder; // Original debug flag? Always false. bool _dbgForceMonsterBlock; // Original debug flag? Always false. bool _word2C8D7; // Original debug flag? Always true. + bool _ongoingFightFl; bool _statusMenuActive; int16 _menuDepth; From 8acbbcafb0a2d02f41187e8cfef4c570078b98c2 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Fri, 18 Nov 2022 12:05:03 +0100 Subject: [PATCH 161/412] EFH: Fix typo in combats --- engines/efh/efh.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 26983e13711c..9b2faba372e2 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -4880,7 +4880,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { if (damagePointsAbsorbed <= 1) snprintf(buffer, 80, " %s%s's armor absorbs 1 point!", _characterNamePt1, _characterNamePt2.c_str()); else - snprintf(buffer, 80, " %s%s',27h,'s armor absorbs %d points!", _characterNamePt1, _characterNamePt2.c_str(), damagePointsAbsorbed); + snprintf(buffer, 80, " %s%s's armor absorbs %d points!", _characterNamePt1, _characterNamePt2.c_str(), damagePointsAbsorbed); strncat((char *)_messageToBePrinted, buffer, 80); } From b6291456274c0f78a418fcfa27f4c7b29605e315 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Fri, 18 Nov 2022 16:36:20 +0100 Subject: [PATCH 162/412] EFH: Preload maps --- engines/efh/efh.cpp | 47 ++++++++++++++++++++++++++------------------- engines/efh/efh.h | 6 +++--- 2 files changed, 30 insertions(+), 23 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 9b2faba372e2..f7e5249bceae 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -194,7 +194,9 @@ EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst) _videoMode = 0; _graphicsStruct = nullptr; - _mapBitmapRef = nullptr; + + for (int i = 0; i < 19; ++i) + _mapBitmapRefArr[i] = nullptr; _defaultBoxColor = 0; @@ -320,7 +322,6 @@ EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst) memset(_loResImageBuf, 0, ARRAYSIZE(_loResImageBuf)); memset(_menuBuf, 0, ARRAYSIZE(_menuBuf)); memset(_windowWithBorderBuf, 0, ARRAYSIZE(_windowWithBorderBuf)); - memset(_map, 0, ARRAYSIZE(_map)); memset(_places, 0, ARRAYSIZE(_places)); for (int i = 0; i < 24; ++i) memset(_curPlace[i], 0, ARRAYSIZE(_curPlace[i])); @@ -332,8 +333,10 @@ EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst) memset(_tileFact, 0, ARRAYSIZE(_tileFact)); memset(_animInfo, 0, ARRAYSIZE(_animInfo)); memset(_history, 0, ARRAYSIZE(_history)); - for(int i = 0; i < 20; ++i) + for (int i = 0; i < 19; ++i) { memset(_techDataArr[i], 0, ARRAYSIZE(_techDataArr[i])); + memset(_mapArr[i], 0, ARRAYSIZE(_mapArr[i])); + } memset(_mapMonsters, 0, ARRAYSIZE(_mapMonsters)); memset(_mapGameMap, 0, ARRAYSIZE(_mapGameMap)); memset(_imageSetSubFilesArray, 0, ARRAYSIZE(_imageSetSubFilesArray)); @@ -682,15 +685,15 @@ void EfhEngine::loadTechMapImp(int16 fileId) { _techId = fileId; findMapFile(_techId); - Common::String fileName = Common::String::format("map.%d", _techId); - readFileToBuffer(fileName, _hiResImageBuf); - uncompressBuffer(_hiResImageBuf, _map); + // The original was loading the specific tech.%d and map.%d files. + // This is gone in our implementation as we pre-load all the files to save them inside the savegames + // This is not present in the original. // The purpose is to properly load the misc map data in arrays in order to use them without being a pain afterwards - loadMapArrays(); - - loadImageSetToTileBank(1, _mapBitmapRef[0] + 1); - loadImageSetToTileBank(2, _mapBitmapRef[1] + 1); + loadMapArrays(_techId); + + loadImageSetToTileBank(1, _mapBitmapRefArr[_techId][0] + 1); + loadImageSetToTileBank(2, _mapBitmapRefArr[_techId][1] + 1); initMapMonsters(); readImpFile(_techId, true); @@ -937,9 +940,15 @@ void EfhEngine::playIntro() { */ void EfhEngine::preLoadMaps() { for (int i = 0; i < 19; ++i) { - Common::String fileName = Common::String::format("tech.%d", _techId); + Common::String fileName = Common::String::format("tech.%d", i); + readFileToBuffer(fileName, _hiResImageBuf); + uncompressBuffer(_hiResImageBuf, _techDataArr[i]); + + fileName = Common::String::format("map.%d", i); readFileToBuffer(fileName, _hiResImageBuf); - uncompressBuffer(_hiResImageBuf, _techDataArr[_techId]); + uncompressBuffer(_hiResImageBuf, _mapArr[i]); + + _mapBitmapRefArr[i] = &_mapArr[i][0]; } } @@ -948,8 +957,6 @@ void EfhEngine::initEngine() { _graphicsStruct = new EfhGraphicsStruct; _graphicsStruct->copy(_vgaGraphicsStruct1); - _mapBitmapRef = &_map[0]; - _vgaGraphicsStruct2->copy(_vgaGraphicsStruct1); _vgaGraphicsStruct2->_shiftValue = 0x2000; @@ -1055,10 +1062,10 @@ void EfhEngine::initMapMonsters() { } } -void EfhEngine::loadMapArrays() { - debug("loadMapArrays"); +void EfhEngine::loadMapArrays(int idx) { + debug("loadMapArrays %d", idx); - uint8 *_mapUnknownPtr = &_map[2]; + uint8 *_mapUnknownPtr = &_mapArr[idx][2]; for (int i = 0; i < 100; ++i) { _mapUnknown[i]._placeId = _mapUnknownPtr[9 * i]; @@ -1070,7 +1077,7 @@ void EfhEngine::loadMapArrays() { _mapUnknown[i]._field7 = READ_LE_UINT16(&_mapUnknownPtr[9 * i + 7]); } - uint8 *mapMonstersPtr = &_map[902]; + uint8 *mapMonstersPtr = &_mapArr[idx][902]; for (int i = 0; i < 64; ++i) { _mapMonsters[i]._possessivePronounSHL6 = mapMonstersPtr[29 * i]; @@ -1088,7 +1095,7 @@ void EfhEngine::loadMapArrays() { _mapMonsters[i]._pictureRef[j] = READ_LE_INT16(&mapMonstersPtr[29 * i + 11 + j * 2]); } - uint8 *mapPtr = &_map[2758]; + uint8 *mapPtr = &_mapArr[idx][2758]; for (int i = 0; i < 64; ++i) { for (int j = 0; j < 64; ++j) _mapGameMap[i][j] = *mapPtr++; @@ -6876,7 +6883,7 @@ void EfhEngine::loadImageSetToTileBank(int16 tileBankId, int16 imageSetId) { _currentTileBankImageSetId[bankId] = setId; if (bankId == 0 || bankId == 1) - _mapBitmapRef[bankId] = setId; + _mapBitmapRefArr[_techId][bankId] = setId; int16 ptrIndex = bankId * 72; loadImageSet(setId, _tileBank[bankId], &_imageSetSubFilesArray[ptrIndex], _hiResImageBuf); diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 1dedbf29610b..223a2e435a85 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -292,7 +292,7 @@ class EfhEngine : public Engine { void preLoadMaps(); void initEngine(); void initMapMonsters(); - void loadMapArrays(); + void loadMapArrays(int idx); void saveAnimImageSetId(); int16 getEquipmentDefense(int16 charId, bool flag); uint16 sub1C80A(int16 charId, int16 field18, bool flag); @@ -498,7 +498,7 @@ class EfhEngine : public Engine { uint8 _loResImageBuf[40100]; uint8 _menuBuf[12500]; uint8 _windowWithBorderBuf[1500]; - uint8 _map[7000]; + uint8 _mapArr[19][7000]; uint8 _places[12000]; uint8 _curPlace[24][24]; NPCStruct _npcBuf[100]; @@ -518,7 +518,7 @@ class EfhEngine : public Engine { char _attackBuffer[20]; uint8 _messageToBePrinted[400]; - uint8 *_mapBitmapRef; + uint8 *_mapBitmapRefArr[19]; UnkMapStruct _mapUnknown[100]; MapMonster _mapMonsters[64]; uint8 _mapGameMap[64][64]; From d695ab34379799f37009e30ec8c0886ca8b60496 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Mon, 21 Nov 2022 01:11:40 +0100 Subject: [PATCH 163/412] EFH: Partial implementation of savegames. Loading is missing. --- engines/efh/efh.cpp | 173 ++++++++++++++++++++++++++++++++++++- engines/efh/efh.h | 22 +++-- engines/efh/metaengine.cpp | 44 ++++------ 3 files changed, 202 insertions(+), 37 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index f7e5249bceae..512d2b75f5ba 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -26,6 +26,10 @@ #include "common/config-manager.h" #include "common/events.h" #include "engines/util.h" +#include "common/savefile.h" +#include "graphics/palette.h" +#include "graphics/scaler.h" +#include "graphics/thumbnail.h" #include "efh/efh.h" #include "efh/constants.h" @@ -372,7 +376,75 @@ void EfhEngine::syncSoundSettings() { } Common::String EfhEngine::getSavegameFilename(int slot) { - return _targetName + Common::String::format("-%02d.SAV", slot); + return _targetName + Common::String::format("-%03d.SAV", slot); +} + +bool EfhEngine::canLoadGameStateCurrently() { + return true; +} + +bool EfhEngine::canSaveGameStateCurrently() { + return true; +} + +Common::Error EfhEngine::loadGameState(int slot) { + Common::InSaveFile *saveFile = g_system->getSavefileManager()->openForLoading(getSaveStateName(slot)); + if (!saveFile) + return Common::kReadingFailed; +/* + Common::Serializer s(saveFile, nullptr); + + uint32 signature; + s.syncAsUint32LE(signature); + uint8 version; + s.syncAsByte(version); + if (signature != EFH_SAVE_HEADER || version > kSavegameVersion) + error("Invalid savegame"); + + // Load the thumbnail + Graphics::Surface *thumbnail; + Graphics::loadThumbnail(*srf, thumbnail) + + synchronize(s); +*/ + + delete saveFile; + + return Common::kNoError; +} + +Common::Error EfhEngine::saveGameState(int slot, const Common::String &desc, bool isAutosave) { + Common::OutSaveFile *out = _system->getSavefileManager()->openForSaving(getSaveStateName(slot)); + if (!out) + return Common::kCreatingFileFailed; + + out->writeUint32LE(EFH_SAVE_HEADER); + out->writeByte(kSavegameVersion); + + // Write savegame name + uint16 size = desc.size(); + out->writeUint16LE(size); + for (int i = 0; i < size; ++i) + out->writeByte(desc.c_str()[i]); + + // Get the active palette + uint8 thumbPalette[16 * 3]; + _system->getPaletteManager()->grabPalette(thumbPalette, 0, 16); + // Create a thumbnail and save it + Graphics::Surface *thumb = new Graphics::Surface(); + Graphics::Surface *sf = _mainSurface; + ::createThumbnail(thumb, (const byte *)sf->getPixels(), 320, 200, thumbPalette); + Graphics::saveThumbnail(*out, *thumb); + thumb->free(); + delete thumb; + + Common::Serializer s(nullptr, out); + synchronize(s); + + out->finalize(); + delete out; + + return Common::kNoError; } Common::Error EfhEngine::run() { @@ -6870,6 +6942,104 @@ bool EfhEngine::checkMonsterCollision() { return true; } +void EfhEngine::synchronize(Common::Serializer &s) { + s.syncAsSint16LE(_techId); + s.syncAsUint16LE(_fullPlaceId); + s.syncAsSint16LE(_guessAnimationAmount); + s.syncAsUint16LE(_largeMapFlag); + s.syncAsSint16LE(_teamCharId[0]); + s.syncAsSint16LE(_teamCharId[1]); + s.syncAsSint16LE(_teamCharId[2]); + + for (int i = 0; i < 3; ++i) { + s.syncAsSint16LE(_teamCharStatus[i]._status); + s.syncAsSint16LE(_teamCharStatus[i]._duration); + } + + s.syncAsSint16LE(_teamSize); + s.syncAsSint16LE(_unkArray2C8AA[0]); + s.syncAsSint16LE(_word2C872); + s.syncAsSint16LE(_imageSetSubFilesIdx); + s.syncAsSint16LE(_mapPosX); + s.syncAsSint16LE(_mapPosY); + s.syncAsSint16LE(_techDataId_MapPosX); + s.syncAsSint16LE(_techDataId_MapPosY); + + for (int i = 0; i < 19; ++i) { + int size = ARRAYSIZE(_techDataArr[i]); + for (int j = 0; j < size; ++j) + s.syncAsByte(_techDataArr[i][j]); + + size = ARRAYSIZE(_mapArr[i]); + for (int j = 0; j < size; ++j) + s.syncAsByte(_mapArr[i][j]); + + _mapBitmapRefArr[i] = &_mapArr[i][0]; + } + + // Dialog flags + for (int i = 0; i < 256; ++i) + s.syncAsByte(_history[i]); + + // NPCs + for (int i = 0; i < 99; ++i) { + for (int idx = 0; idx < 11; ++idx) + s.syncAsByte(_npcBuf[i]._name[idx]); + + s.syncAsByte(_npcBuf[i].field_B); + s.syncAsByte(_npcBuf[i].field_C); + s.syncAsByte(_npcBuf[i].field_D); + s.syncAsByte(_npcBuf[i].field_E); + s.syncAsByte(_npcBuf[i].field_F); + s.syncAsByte(_npcBuf[i].field_10); + s.syncAsByte(_npcBuf[i].field_11); + s.syncAsSint16LE(_npcBuf[i].field_12); + s.syncAsSint16LE(_npcBuf[i].field_14); + s.syncAsSint32LE(_npcBuf[i]._xp); + for (int idx = 0; idx < 15; ++idx) + s.syncAsByte(_npcBuf[i]._activeScore[idx]); + + for (int idx = 0; idx < 11; ++idx) + s.syncAsByte(_npcBuf[i]._passiveScore[idx]); + + for (int idx = 0; idx < 11; ++idx) + s.syncAsByte(_npcBuf[i]._infoScore[idx]); + + s.syncAsByte(_npcBuf[i].field_3F); + s.syncAsByte(_npcBuf[i].field_40); + for (int idx = 0; idx < 10; ++idx) { + s.syncAsSint16LE(_npcBuf[i]._inventory[idx]._ref); + s.syncAsByte(_npcBuf[i]._inventory[idx]._stat1); + s.syncAsByte(_npcBuf[i]._inventory[idx]._stat2); + } + s.syncAsByte(_npcBuf[i]._possessivePronounSHL6); + s.syncAsByte(_npcBuf[i]._speed); + s.syncAsByte(_npcBuf[i].field_6B); + s.syncAsByte(_npcBuf[i].field_6C); + s.syncAsByte(_npcBuf[i].field_6D); + s.syncAsByte(_npcBuf[i]._unkItemId); + s.syncAsByte(_npcBuf[i].field_6F); + s.syncAsByte(_npcBuf[i].field_70); + s.syncAsByte(_npcBuf[i].field_71); + s.syncAsByte(_npcBuf[i].field_72); + s.syncAsByte(_npcBuf[i].field_73); + s.syncAsSint16LE(_npcBuf[i]._hitPoints); + s.syncAsSint16LE(_npcBuf[i]._maxHP); + s.syncAsByte(_npcBuf[i].field_78); + s.syncAsSint16LE(_npcBuf[i].field_79); + s.syncAsSint16LE(_npcBuf[i].field_7B); + s.syncAsByte(_npcBuf[i].field_7D); + s.syncAsByte(_npcBuf[i].field_7E); + s.syncAsByte(_npcBuf[i].field_7F); + s.syncAsByte(_npcBuf[i].field_80); + s.syncAsByte(_npcBuf[i].field_81); + s.syncAsByte(_npcBuf[i].field_82); + s.syncAsByte(_npcBuf[i].field_83); + s.syncAsByte(_npcBuf[i].field_84); + s.syncAsByte(_npcBuf[i].field_85); + } +} + void EfhEngine::loadImageSetToTileBank(int16 tileBankId, int16 imageSetId) { debugC(3, kDebugEngine, "loadImageSetToTileBank %d %d", tileBankId, imageSetId); @@ -6959,6 +7129,7 @@ void EfhEngine::loadEfhGame() { void EfhEngine::saveEfhGame() { warning("STUB - saveEfhGame"); + openMainMenuDialog(); } uint8 EfhEngine::getMapTileInfo(int16 mapPosX, int16 mapPosY) { diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 223a2e435a85..ed9b7eaebe2c 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -29,6 +29,7 @@ #include "common/file.h" #include "common/rect.h" #include "common/events.h" +#include "common/serializer.h" #include "engines/engine.h" #include "graphics/surface.h" @@ -42,18 +43,20 @@ class RandomSource; * This is the namespace of the Efh engine. * * Status of this engine: - * - Skeletton + * - No savegames + * - No music in intro + * - No random PC speaker farts (aka sounds) * * Games using this engine: * - Escape From Hell * - * Escape From Hell is based on a modified Wasteland engine, so this engine could eventually, one day, also support: - * - Wasteland - * - Fountain of Dreams + * Note: Wasteland and Fountain of dreams *seem* to use the same engine, but it's not the case. + * This engine was written from scratch based on the visual look of the other */ namespace Efh { -static const int kSavegameVersion = 1; +static const uint8 kSavegameVersion = 1; +#define EFH_SAVE_HEADER MKTAG('E', 'F', 'H', 'S') enum AccessDebugChannels { kDebugEngine = 1 << 0, @@ -257,6 +260,12 @@ class EfhEngine : public Engine { const char *getCopyrightString() const; Common::String getSavegameFilename(int slot); + + bool canLoadGameStateCurrently() override; + bool canSaveGameStateCurrently() override; + Common::Error loadGameState(int slot) override; + Common::Error saveGameState(int slot, const Common::String &desc, bool isAutosave = false) override; + void syncSoundSettings() override; bool _shouldQuit; @@ -264,10 +273,8 @@ class EfhEngine : public Engine { protected: Common::EventManager *_eventMan; int _lastTime; - void saveGame(); // Engine APIs Common::Error run() override; - void handleMenu(); private: static EfhEngine *s_Engine; @@ -430,6 +437,7 @@ class EfhEngine : public Engine { int16 sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine, int16 argA); int16 handleStatusMenu(int16 gameMode, int16 charId); bool checkMonsterCollision(); + void synchronize(Common::Serializer &s); // Graphics void initPalette(); diff --git a/engines/efh/metaengine.cpp b/engines/efh/metaengine.cpp index 9857fb0bee7d..e2fca88a03a1 100644 --- a/engines/efh/metaengine.cpp +++ b/engines/efh/metaengine.cpp @@ -83,7 +83,7 @@ SaveStateList EfhMetaEngine::listSaves(const char *target) const { Common::SaveFileManager *saveFileMan = g_system->getSavefileManager(); Common::StringArray filenames; Common::String pattern = target; - pattern += "-##.SAV"; + pattern += ".###"; filenames = saveFileMan->listSavefiles(pattern); @@ -91,24 +91,25 @@ SaveStateList EfhMetaEngine::listSaves(const char *target) const { char slot[3]; int slotNum = 0; for (Common::StringArray::const_iterator filename = filenames.begin(); filename != filenames.end(); ++filename) { - slot[0] = filename->c_str()[filename->size() - 6]; - slot[1] = filename->c_str()[filename->size() - 5]; + slot[0] = filename->c_str()[filename->size() - 2]; + slot[1] = filename->c_str()[filename->size() - 1]; slot[2] = '\0'; // Obtain the last 2 digits of the filename (without extension), since they correspond to the save slot slotNum = atoi(slot); if (slotNum >= 0 && slotNum <= getMaximumSaveSlot()) { Common::InSaveFile *file = saveFileMan->openForLoading(*filename); if (file) { - int saveVersion = file->readByte(); + uint32 sign = file->readUint32LE(); + uint8 saveVersion = file->readByte(); - if (saveVersion != kSavegameVersion) { - warning("Savegame of incompatible version"); + if (sign != EFH_SAVE_HEADER || saveVersion > kSavegameVersion) { + warning("Incompatible savegame"); delete file; continue; } // read name - uint16 nameSize = file->readUint16BE(); + uint16 nameSize = file->readUint16LE(); if (nameSize >= 255) { delete file; continue; @@ -128,19 +129,20 @@ SaveStateList EfhMetaEngine::listSaves(const char *target) const { } SaveStateDescriptor EfhMetaEngine::querySaveMetaInfos(const char *target, int slot) const { - Common::String fileName = Common::String::format("%s-%02d.SAV", target, slot); + Common::String fileName = Common::String::format("%s.%03d", target, slot); Common::InSaveFile *file = g_system->getSavefileManager()->openForLoading(fileName); if (file) { - int saveVersion = file->readByte(); + uint32 sign = file->readUint32LE(); + uint8 saveVersion = file->readByte(); - if (saveVersion != kSavegameVersion) { - warning("Savegame of incompatible version"); + if (sign != EFH_SAVE_HEADER || saveVersion > kSavegameVersion) { + warning("Incompatible savegame"); delete file; return SaveStateDescriptor(); } - uint32 saveNameLength = file->readUint16BE(); + uint32 saveNameLength = file->readUint16LE(); Common::String saveName; for (uint32 i = 0; i < saveNameLength; ++i) { char curChr = file->readByte(); @@ -156,22 +158,6 @@ SaveStateDescriptor EfhMetaEngine::querySaveMetaInfos(const char *target, int sl } desc.setThumbnail(thumbnail); - desc.setDeletableFlag(true); - desc.setWriteProtectedFlag(false); - - uint32 saveDate = file->readUint32BE(); - uint16 saveTime = file->readUint16BE(); - - int day = (saveDate >> 24) & 0xFF; - int month = (saveDate >> 16) & 0xFF; - int year = saveDate & 0xFFFF; - - desc.setSaveDate(year, month, day); - - int hour = (saveTime >> 8) & 0xFF; - int minutes = saveTime & 0xFF; - - desc.setSaveTime(hour, minutes); desc.setDeletableFlag(slot != 0); desc.setWriteProtectedFlag(slot == 0); @@ -182,7 +168,7 @@ SaveStateDescriptor EfhMetaEngine::querySaveMetaInfos(const char *target, int sl } void EfhMetaEngine::removeSaveState(const char *target, int slot) const { - Common::String fileName = Common::String::format("%s-%02d.SAV", target, slot); + Common::String fileName = Common::String::format("%s.%03d", target, slot); g_system->getSavefileManager()->removeSavefile(fileName); } From 638696444dc3718cce69b496b49c12cc4bd55217 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Tue, 22 Nov 2022 08:38:03 +0100 Subject: [PATCH 164/412] EFH: Add save date & time --- engines/efh/efh.cpp | 9 +++++++++ engines/efh/metaengine.cpp | 10 +++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 512d2b75f5ba..393fbc30991f 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -438,6 +438,15 @@ Common::Error EfhEngine::saveGameState(int slot, const Common::String &desc, boo thumb->free(); delete thumb; + // Write out the save date/time + TimeDate td; + g_system->getTimeAndDate(td); + out->writeSint16LE(td.tm_year + 1900); + out->writeSint16LE(td.tm_mon + 1); + out->writeSint16LE(td.tm_mday); + out->writeSint16LE(td.tm_hour); + out->writeSint16LE(td.tm_min); + Common::Serializer s(nullptr, out); synchronize(s); diff --git a/engines/efh/metaengine.cpp b/engines/efh/metaengine.cpp index e2fca88a03a1..a207dca55d2e 100644 --- a/engines/efh/metaengine.cpp +++ b/engines/efh/metaengine.cpp @@ -157,7 +157,15 @@ SaveStateDescriptor EfhMetaEngine::querySaveMetaInfos(const char *target, int sl return SaveStateDescriptor(); } desc.setThumbnail(thumbnail); - + // Read in save date/time + int16 year = file->readSint16LE(); + int16 month = file->readSint16LE(); + int16 day = file->readSint16LE(); + int16 hour = file->readSint16LE(); + int16 minute = file->readSint16LE(); + desc.setSaveDate(year, month, day); + desc.setSaveTime(hour, minute); + desc.setDeletableFlag(slot != 0); desc.setWriteProtectedFlag(slot == 0); From e54b01d47493dbdce2a7ff1caf9a51cc3996cfd3 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Wed, 23 Nov 2022 00:50:17 +0100 Subject: [PATCH 165/412] EFH: Partial loading code --- engines/efh/efh.cpp | 25 +++++++++++++++---------- engines/efh/metaengine.cpp | 7 +++---- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 393fbc30991f..6af0ddc5e94c 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -391,22 +391,26 @@ Common::Error EfhEngine::loadGameState(int slot) { Common::InSaveFile *saveFile = g_system->getSavefileManager()->openForLoading(getSaveStateName(slot)); if (!saveFile) return Common::kReadingFailed; -/* - Common::Serializer s(saveFile, nullptr); - uint32 signature; - s.syncAsUint32LE(signature); - uint8 version; - s.syncAsByte(version); + uint32 signature = saveFile->readUint32LE(); + byte version = saveFile->readByte(); + if (signature != EFH_SAVE_HEADER || version > kSavegameVersion) error("Invalid savegame"); - // Load the thumbnail + // Skip savegame name + uint16 size = saveFile->readUint16BE(); + saveFile->skip(size); + + // Skip the thumbnail Graphics::Surface *thumbnail; - Graphics::loadThumbnail(*srf, thumbnail) + Graphics::loadThumbnail(*saveFile, thumbnail, true); + // Skip the savegame date + saveFile->skip(10); // year, month, day, hours, minutes (all int16) + + Common::Serializer s(saveFile, nullptr); synchronize(s); -*/ delete saveFile; @@ -592,7 +596,8 @@ Common::Error EfhEngine::run() { if (input == Common::KEYCODE_y) { displayMenuAnswerString("-> Yes <-", 24, 296, 169); getInput(2); - loadEfhGame(); +// loadEfhGame(); + saveEfhGame(); clearBottomTextZone_2(0); displayLowStatusScreen(true); } else { diff --git a/engines/efh/metaengine.cpp b/engines/efh/metaengine.cpp index a207dca55d2e..01d76fb82648 100644 --- a/engines/efh/metaengine.cpp +++ b/engines/efh/metaengine.cpp @@ -81,21 +81,19 @@ int EfhMetaEngine::getMaximumSaveSlot() const { SaveStateList EfhMetaEngine::listSaves(const char *target) const { Common::SaveFileManager *saveFileMan = g_system->getSavefileManager(); - Common::StringArray filenames; Common::String pattern = target; pattern += ".###"; - filenames = saveFileMan->listSavefiles(pattern); + Common::StringArray filenames = saveFileMan->listSavefiles(pattern); SaveStateList saveList; char slot[3]; - int slotNum = 0; for (Common::StringArray::const_iterator filename = filenames.begin(); filename != filenames.end(); ++filename) { slot[0] = filename->c_str()[filename->size() - 2]; slot[1] = filename->c_str()[filename->size() - 1]; slot[2] = '\0'; // Obtain the last 2 digits of the filename (without extension), since they correspond to the save slot - slotNum = atoi(slot); + int slotNum = atoi(slot); if (slotNum >= 0 && slotNum <= getMaximumSaveSlot()) { Common::InSaveFile *file = saveFileMan->openForLoading(*filename); if (file) { @@ -157,6 +155,7 @@ SaveStateDescriptor EfhMetaEngine::querySaveMetaInfos(const char *target, int sl return SaveStateDescriptor(); } desc.setThumbnail(thumbnail); + // Read in save date/time int16 year = file->readSint16LE(); int16 month = file->readSint16LE(); From 0d158f15834bc58d3fed03ef226db240d26da4c8 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Wed, 23 Nov 2022 01:03:38 +0100 Subject: [PATCH 166/412] EFH: Fix parsing of savegame --- engines/efh/efh.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 6af0ddc5e94c..dccfe84eb69a 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -399,13 +399,14 @@ Common::Error EfhEngine::loadGameState(int slot) { error("Invalid savegame"); // Skip savegame name - uint16 size = saveFile->readUint16BE(); + uint16 size = saveFile->readUint16LE(); saveFile->skip(size); // Skip the thumbnail Graphics::Surface *thumbnail; - Graphics::loadThumbnail(*saveFile, thumbnail, true); - + Graphics::loadThumbnail(*saveFile, thumbnail); + delete (thumbnail); + // Skip the savegame date saveFile->skip(10); // year, month, day, hours, minutes (all int16) From df4ac48e9f46c7d768016fc15ff47086a325c787 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Wed, 23 Nov 2022 01:18:40 +0100 Subject: [PATCH 167/412] EFH: Fix loading (hopefully) --- engines/efh/efh.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index dccfe84eb69a..dfc9634ad80b 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -415,6 +415,14 @@ Common::Error EfhEngine::loadGameState(int slot) { delete saveFile; + _oldMapPosX = _mapPosX; + _oldMapPosY = _mapPosY; + _unkRelatedToAnimImageSetId = 0; + + loadTechMapImp(_techId); + _lastMainPlaceId = 0xFFFF; + loadPlacesFile(_fullPlaceId, true); + return Common::kNoError; } From 143c483bde9bd5f07bfd805df69949f8d0adeba8 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Wed, 23 Nov 2022 08:50:34 +0100 Subject: [PATCH 168/412] EFH: Load from launcher --- engines/efh/efh.cpp | 29 ++++++++++++++++++++++------- engines/efh/efh.h | 5 +++-- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index dfc9634ad80b..e6be0246dd33 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -344,6 +344,14 @@ EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst) memset(_mapMonsters, 0, ARRAYSIZE(_mapMonsters)); memset(_mapGameMap, 0, ARRAYSIZE(_mapGameMap)); memset(_imageSetSubFilesArray, 0, ARRAYSIZE(_imageSetSubFilesArray)); + + // If requested, load a savegame instead of showing the intro + _loadSaveSlot = -1; + if (ConfMan.hasKey("save_slot")) { + int saveSlot = ConfMan.getInt("save_slot"); + if (saveSlot >= 0 && saveSlot <= 999) + _loadSaveSlot = saveSlot; + } } EfhEngine::~EfhEngine() { @@ -1073,12 +1081,14 @@ void EfhEngine::initEngine() { saveAnimImageSetId(); - // Load Title Screen + // Load Title Screen, skip if loading a savegame from launcher loadImageSet(11, _circleImageBuf, _circleImageSubFileArray, _hiResImageBuf); - displayFctFullScreen(); - displayRawDataAtPos(_circleImageSubFileArray[0], 0, 0); - displayFctFullScreen(); - displayRawDataAtPos(_circleImageSubFileArray[0], 0, 0); + if (_loadSaveSlot == -1) { + displayFctFullScreen(); + displayRawDataAtPos(_circleImageSubFileArray[0], 0, 0); + displayFctFullScreen(); + displayRawDataAtPos(_circleImageSubFileArray[0], 0, 0); + } // Load map tiles bitmaps loadImageSetToTileBank(1, 1); @@ -1110,7 +1120,7 @@ void EfhEngine::initEngine() { setDefaultNoteDuration(); Common::KeyCode lastInput = playSong(_titleSong); - if (lastInput != Common::KEYCODE_ESCAPE) { + if (lastInput != Common::KEYCODE_ESCAPE && _loadSaveSlot == -1) { playIntro(); } @@ -1122,7 +1132,12 @@ void EfhEngine::initEngine() { // Note: The original at this point saves int 24h and sets a new int24 to handle fatal failure checkProtection(); - loadEfhGame(); + if (_loadSaveSlot == -1) { + loadEfhGame(); + } else { + loadGameState(_loadSaveSlot); + _loadSaveSlot = -1; + } _engineInitPending = false; } diff --git a/engines/efh/efh.h b/engines/efh/efh.h index ed9b7eaebe2c..8e5211638e3b 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -43,15 +43,15 @@ class RandomSource; * This is the namespace of the Efh engine. * * Status of this engine: - * - No savegames * - No music in intro * - No random PC speaker farts (aka sounds) + * - The rest is more or less working :) * * Games using this engine: * - Escape From Hell * * Note: Wasteland and Fountain of dreams *seem* to use the same engine, but it's not the case. - * This engine was written from scratch based on the visual look of the other + * Escape From Hell was written from scratch based on the visual look of the other */ namespace Efh { @@ -281,6 +281,7 @@ class EfhEngine : public Engine { GameType _gameType; Common::Platform _platform; + int _loadSaveSlot; void initialize(); void readAnimInfo(); From a3046a0be0286964fd537c62800c885c3ab00c0a Mon Sep 17 00:00:00 2001 From: Strangerke Date: Wed, 23 Nov 2022 11:26:10 +0100 Subject: [PATCH 169/412] EFH: Janitorial - Remove trailing spaces & tabs --- engines/efh/efh.cpp | 246 ++++++++++++++++++------------------- engines/efh/efh.h | 8 +- engines/efh/graphics.cpp | 2 +- engines/efh/metaengine.cpp | 4 +- engines/efh/utils.cpp | 2 +- 5 files changed, 131 insertions(+), 131 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index e6be0246dd33..3068ab76f0f3 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -132,7 +132,7 @@ void NPCStruct::init() { for (int i = 0; i < 10; ++i) _inventory[i].init(); - + _possessivePronounSHL6 = 0; _speed = 0; field_6B = 0; @@ -405,7 +405,7 @@ Common::Error EfhEngine::loadGameState(int slot) { if (signature != EFH_SAVE_HEADER || version > kSavegameVersion) error("Invalid savegame"); - + // Skip savegame name uint16 size = saveFile->readUint16LE(); saveFile->skip(size); @@ -414,10 +414,10 @@ Common::Error EfhEngine::loadGameState(int slot) { Graphics::Surface *thumbnail; Graphics::loadThumbnail(*saveFile, thumbnail); delete (thumbnail); - + // Skip the savegame date - saveFile->skip(10); // year, month, day, hours, minutes (all int16) - + saveFile->skip(10); // year, month, day, hours, minutes (all int16) + Common::Serializer s(saveFile, nullptr); synchronize(s); @@ -447,7 +447,7 @@ Common::Error EfhEngine::saveGameState(int slot, const Common::String &desc, boo out->writeUint16LE(size); for (int i = 0; i < size; ++i) out->writeByte(desc.c_str()[i]); - + // Get the active palette uint8 thumbPalette[16 * 3]; _system->getPaletteManager()->grabPalette(thumbPalette, 0, 16); @@ -457,7 +457,7 @@ Common::Error EfhEngine::saveGameState(int slot, const Common::String &desc, boo ::createThumbnail(thumb, (const byte *)sf->getPixels(), 320, 200, thumbPalette); Graphics::saveThumbnail(*out, *thumb); thumb->free(); - delete thumb; + delete thumb; // Write out the save date/time TimeDate td; @@ -468,7 +468,7 @@ Common::Error EfhEngine::saveGameState(int slot, const Common::String &desc, boo out->writeSint16LE(td.tm_hour); out->writeSint16LE(td.tm_min); - Common::Serializer s(nullptr, out); + Common::Serializer s(nullptr, out); synchronize(s); out->finalize(); @@ -599,8 +599,8 @@ Common::Error EfhEngine::run() { clearBottomTextZone_2(0); displayLowStatusScreen(true); } - - } + + } break; case Common::KEYCODE_F7: { // Original is using CTRL-L for (int16 counter = 0; counter < 2; ++counter) { @@ -649,7 +649,7 @@ Common::Error EfhEngine::run() { if (_largeMapFlag) { _techDataId_MapPosX = _mapPosX; _techDataId_MapPosY = _mapPosY; - } + } } if (!_shouldQuit) { @@ -692,7 +692,7 @@ void EfhEngine::initialize() { void EfhEngine::readAnimInfo() { debugC(6, kDebugEngine, "readAnimInfo"); - + Common::String fileName = "animinfo"; uint8 animInfoBuf[9000]; memset(animInfoBuf, 0, 9000); @@ -729,7 +729,7 @@ void EfhEngine::readAnimInfo() { void EfhEngine::findMapFile(int16 mapId) { debugC(7, kDebugEngine, "findMapFile %d", mapId); - + if (!_word31E9E) return; @@ -744,7 +744,7 @@ void EfhEngine::findMapFile(int16 mapId) { void EfhEngine::loadNewPortrait() { debugC(7, kDebugEngine, "loadNewPortrait"); - + static int16 const unkConstRelatedToAnimImageSetId[19] = {0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2}; _unkRelatedToAnimImageSetId = unkConstRelatedToAnimImageSetId[_techId]; @@ -759,7 +759,7 @@ void EfhEngine::loadNewPortrait() { void EfhEngine::loadAnimImageSet() { debug("loadAnimImageSet"); - + if (_currentAnimImageSetId == _animImageSetId || _animImageSetId == 0xFF) return; @@ -774,14 +774,14 @@ void EfhEngine::loadAnimImageSet() { void EfhEngine::loadHistory() { debug("loadHistory"); - + Common::String fileName = "history"; readFileToBuffer(fileName, _history); } void EfhEngine::loadTechMapImp(int16 fileId) { debug("loadTechMapImp %d", fileId); - + if (fileId == 0xFF) return; @@ -790,23 +790,23 @@ void EfhEngine::loadTechMapImp(int16 fileId) { // The original was loading the specific tech.%d and map.%d files. // This is gone in our implementation as we pre-load all the files to save them inside the savegames - + // This is not present in the original. // The purpose is to properly load the misc map data in arrays in order to use them without being a pain afterwards loadMapArrays(_techId); - + loadImageSetToTileBank(1, _mapBitmapRefArr[_techId][0] + 1); loadImageSetToTileBank(2, _mapBitmapRefArr[_techId][1] + 1); initMapMonsters(); readImpFile(_techId, true); displayAnimFrames(0xFE, false); - + } void EfhEngine::loadPlacesFile(uint16 fullPlaceId, bool forceReloadFl) { debug("loadPlacesFile %d %s", fullPlaceId, forceReloadFl ? "True" : "False"); - + if (fullPlaceId == 0xFF) return; @@ -826,7 +826,7 @@ void EfhEngine::loadPlacesFile(uint16 fullPlaceId, bool forceReloadFl) { void EfhEngine::readTileFact() { debugC(7, kDebugEngine, "readTileFact"); - + Common::String fileName = "tilefact"; uint8 tileFactBuff[864]; readFileToBuffer(fileName, tileFactBuff); @@ -839,7 +839,7 @@ void EfhEngine::readTileFact() { void EfhEngine::readItems() { debugC(7, kDebugEngine, "readItems"); - + Common::String fileName = "items"; uint8 itemBuff[8100]; readFileToBuffer(fileName, itemBuff); @@ -849,7 +849,7 @@ void EfhEngine::readItems() { for (int16 idx = 0; idx < 15; ++idx) _items[i]._name[idx] = *curPtr++; - + _items[i]._damage = *curPtr++; _items[i]._defense = *curPtr++; _items[i]._attacks = *curPtr++; @@ -869,7 +869,7 @@ void EfhEngine::readItems() { void EfhEngine::loadNPCS() { debugC(7, kDebugEngine, "loadNPCS"); - + Common::String fileName = "npcs"; uint8 npcLoading[13400]; readFileToBuffer(fileName, npcLoading); @@ -940,16 +940,16 @@ void EfhEngine::loadNPCS() { Common::KeyCode EfhEngine::playSong(uint8 *buffer) { warning("STUB: playSong"); - - + + _system->delayMillis(1000); - + return Common::KEYCODE_INVALID; } void EfhEngine::readImpFile(int16 id, bool techMapFl) { debug("readImpFile %d %s", id, techMapFl ? "True" : "False"); - + Common::String fileName = Common::String::format("imp.%d", id); if (techMapFl) @@ -962,7 +962,7 @@ void EfhEngine::readImpFile(int16 id, bool techMapFl) { void EfhEngine::playIntro() { debugC(6, kDebugEngine, "playIntro"); - + displayRawDataAtPos(_circleImageSubFileArray[0], 0, 0); displayFctFullScreen(); displayRawDataAtPos(_circleImageSubFileArray[0], 0, 0); @@ -980,7 +980,7 @@ void EfhEngine::playIntro() { displayFctFullScreen(); displayRawDataAtPos(_circleImageSubFileArray[0], 0, 144); drawText(_imp2PtrArray[0], 6, 150, 268, 186, false); - + lastInput = getLastCharAfterAnimCount(80); if (lastInput == Common::KEYCODE_ESCAPE) return; @@ -1078,7 +1078,7 @@ void EfhEngine::initEngine() { // Pre-load stuff required for savegames preLoadMaps(); - + saveAnimImageSetId(); // Load Title Screen, skip if loading a savegame from launcher @@ -1115,7 +1115,7 @@ void EfhEngine::initEngine() { // Load picture room with girlfriend loadImageSet(62, _circleImageBuf, _circleImageSubFileArray, _hiResImageBuf); - fileName = "titlsong"; + fileName = "titlsong"; readFileToBuffer(fileName, _titleSong); setDefaultNoteDuration(); Common::KeyCode lastInput = playSong(_titleSong); @@ -1143,7 +1143,7 @@ void EfhEngine::initEngine() { void EfhEngine::initMapMonsters() { debug("initMapMonsters"); - + for (uint8 monsterId = 0; monsterId < 64; ++monsterId) { if (_mapMonsters[monsterId]._guess_fullPlaceId == 0xFF) continue; @@ -1168,7 +1168,7 @@ void EfhEngine::initMapMonsters() { uint16 delta = getRandom(pictureRef / 2); _mapMonsters[monsterId]._pictureRef[counter] = pictureRef + delta; } - } + } } } @@ -1186,7 +1186,7 @@ void EfhEngine::loadMapArrays(int idx) { _mapUnknown[i]._field5 = READ_LE_UINT16(&_mapUnknownPtr[9 * i + 5]); _mapUnknown[i]._field7 = READ_LE_UINT16(&_mapUnknownPtr[9 * i + 7]); } - + uint8 *mapMonstersPtr = &_mapArr[idx][902]; for (int i = 0; i < 64; ++i) { @@ -1257,7 +1257,7 @@ uint16 EfhEngine::sub1C80A(int16 charId, int16 field18, bool flag) { continue; int16 itemId = _npcBuf[charId]._inventory[i]._ref; - + if (_items[itemId].field_18 != field18) continue; @@ -1280,7 +1280,7 @@ void EfhEngine::drawGameScreenAndTempText(bool flag) { int16 mapImageSetId = (imageSetId * 72) + (mapTileInfo % 72); #endif - + for (int counter = 0; counter < 2; ++counter) { if (counter == 0 || flag) { displayGameScreen(); @@ -1301,7 +1301,7 @@ void EfhEngine::drawGameScreenAndTempText(bool flag) { void EfhEngine::drawMap(bool largeMapFl, int16 mapPosX, int16 mapPosY, int16 mapSize, bool drawHeroFl, bool drawMonstersFl) { debugC(6, kDebugEngine, "drawMap %s %d-%d %d %s %s", largeMapFl ? "True" : "False", mapPosX, mapPosY, mapSize, drawHeroFl ? "True" : "False", drawMonstersFl ? "True" : "False"); - + int16 shiftPosX = 5; int16 shiftPosY = 4; int16 minX = mapPosX - 5; @@ -1404,7 +1404,7 @@ void EfhEngine::displayLargeMap(int16 posX, int16 posY) { void EfhEngine::drawScreen() { debugC(2, kDebugEngine, "drawScreen"); - + for (int16 counter = 0; counter < 2; ++counter) { _redrawNeededFl = false; if (!_largeMapFlag) { @@ -1429,14 +1429,14 @@ void EfhEngine::drawScreen() { void EfhEngine::displayLowStatusScreen(bool flag) { debugC(6, kDebugEngine, "displayLowStatusScreen %s", flag ? "True" : "False"); - + static char strName[5] = "Name"; static char strDef[4] = "DEF"; static char strHp[3] = "HP"; static char strMaxHp[7] = "Max HP"; static char strWeapon[7] = "Weapon"; static char strDead[9] = "* DEAD *"; - + for (int counter = 0; counter < 2; ++counter) { if (counter == 0 || flag) { clearBottomTextZone(0); @@ -1476,7 +1476,7 @@ void EfhEngine::displayLowStatusScreen(bool flag) { else _nameBuffer = _items[var4]._name; } - break; + break; case 1: _nameBuffer = "* ASLEEP *"; break; @@ -1499,7 +1499,7 @@ void EfhEngine::displayLowStatusScreen(bool flag) { uint8 *EfhEngine::script_readNumberArray(uint8 *srcBuffer, int16 destArraySize, int16 *destArray) { debug("script_readNumberArray"); - + uint8 *buffer = srcBuffer; for (int16 i = 0; i < destArraySize; ++i) { buffer++; @@ -1511,8 +1511,8 @@ uint8 *EfhEngine::script_readNumberArray(uint8 *srcBuffer, int16 destArraySize, uint8 *EfhEngine::script_getNumber(uint8 *srcBuffer, int16 *retval) { debug("script_getNumber"); - - uint8 *buffer = srcBuffer; + + uint8 *buffer = srcBuffer; int16 var2 = 0; for (;;) { uint8 curChar = *buffer; @@ -1564,7 +1564,7 @@ void EfhEngine::removeCharacterFromTeam(int16 teamMemberId) { void EfhEngine::refreshTeamSize() { debug("refreshTeamSize"); - + _teamSize = 0; for (int16 counter = 0; counter < 3; ++counter) { if (_teamCharId[counter] != -1) @@ -1585,7 +1585,7 @@ bool EfhEngine::isCharacterATeamMember(int16 id) { bool EfhEngine::isTPK() { debug("isTPK"); - + int16 zeroedChar = 0; for (int16 counter = 0; counter < _teamSize; ++counter) { if (_npcBuf[_teamCharId[counter]]._hitPoints <= 0) @@ -1597,7 +1597,7 @@ bool EfhEngine::isTPK() { void EfhEngine::handleWinSequence() { debugC(1, kDebugEngine, "handleWinSequence"); - + saveAnimImageSetId(); findMapFile(18); // clearMemory(); @@ -1670,7 +1670,7 @@ void EfhEngine::handleWinSequence() { input = getInput(1); } } - + free(decompBuffer); free(winSeqBuf3); free(winSeqBuf4); @@ -1718,7 +1718,7 @@ int16 EfhEngine::chooseCharacterToReplace() { int16 EfhEngine::handleCharacterJoining() { debug("handleCharacterJoining"); - + static char strReplaceWho[13] = "Replace Who?"; for (int16 counter = 0; counter < 3; ++counter) { if (_teamCharId[counter] == -1) { @@ -1910,7 +1910,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int16 posX, int16 posY, int16 if (flag && scriptNumberArray[0] != -1) { _npcBuf[_teamCharId[scriptNumberArray[0]]]._hitPoints = 0; } - break; + break; case 0x09: buffer = script_readNumberArray(buffer, 2, scriptNumberArray); if (flag) { @@ -1955,7 +1955,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int16 posX, int16 posY, int16 removeObject(_teamCharId[counter], objectId); found = true; break; - } + } } } } @@ -1998,7 +1998,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int16 posX, int16 posY, int16 if (isCharacterATeamMember(var110)) var_F0 = scriptNumberArray[1]; else - var_F0 = scriptNumberArray[2]; + var_F0 = scriptNumberArray[2]; } break; case 0x10: @@ -2060,7 +2060,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int16 posX, int16 posY, int16 break; } } - } + } } break; case 0x17: @@ -2197,10 +2197,10 @@ void EfhEngine::drawText(uint8 *srcPtr, int16 posX, int16 posY, int16 maxX, int1 uint16 stringIdx = 0; uint8 *impPtr = srcPtr; memset(_messageToBePrinted, 0, 200); - + for (;;) { uint8 curChar = *impPtr; - + if (curChar == 0 || curChar == 0x40 || curChar == 0x60) break; @@ -2220,7 +2220,7 @@ void EfhEngine::drawText(uint8 *srcPtr, int16 posX, int16 posY, int16 maxX, int1 void EfhEngine::displayMiddleLeftTempText(uint8 *impArray, bool flag) { debugC(3, kDebugEngine, "displayMiddleLeftTempText %s %s", (char *)impArray, flag ? "True" : "False"); - + for (uint8 counter = 0; counter < 2; ++counter) { if (counter == 0 || flag) { // clear middle-left text area @@ -2298,7 +2298,7 @@ int16 EfhEngine::sub1C219(uint8 *str, int16 menuType, int16 arg4, bool displayTe int16 varA = 0xFF; int16 minX, maxX, minY, maxY; - + switch (menuType) { case 0: minX = 129; @@ -2777,7 +2777,7 @@ bool EfhEngine::moveMonsterTowardsTeam(int16 monsterId) { bool EfhEngine::moveMonsterGroupOther(int16 monsterId, int16 direction) { debug("moveMonsterGroupOther %d %d", monsterId, direction); - + switch (direction - 1) { case 0: --_mapMonsters[monsterId]._posY; @@ -2829,7 +2829,7 @@ bool EfhEngine::moveMonsterGroup(int16 monsterId) { int16 EfhEngine::computeMonsterGroupDistance(int16 monsterId) { debugC(2, kDebugEngine, "computeMonsterGroupDistance %d", monsterId); - + int16 monsterPosX = _mapMonsters[monsterId]._posX; int16 monsterPosY = _mapMonsters[monsterId]._posY; @@ -2841,7 +2841,7 @@ int16 EfhEngine::computeMonsterGroupDistance(int16 monsterId) { bool EfhEngine::checkWeaponRange(int16 monsterId, int16 weaponId) { debugC(6, kDebugEngine, "checkWeaponRange %d %d", monsterId, weaponId); - + static const int16 kRange[5] = {1, 2, 3, 3, 3}; assert(_items[weaponId]._range < 5); @@ -2886,7 +2886,7 @@ bool EfhEngine::checkTeamWeaponRange(int16 monsterId) { bool EfhEngine::checkIfMonsterOnSameLargeMapPlace(int16 monsterId) { debugC(6, kDebugEngine, "checkIfMonsterOnSameLargeMapPlace %d", monsterId); - + if (_largeMapFlag && _mapMonsters[monsterId]._guess_fullPlaceId == 0xFE) return true; @@ -2898,7 +2898,7 @@ bool EfhEngine::checkIfMonsterOnSameLargeMapPlace(int16 monsterId) { bool EfhEngine::checkMonsterWeaponRange(int16 monsterId) { debugC(6, kDebugEngine, "checkMonsterWeaponRange %d", monsterId); - + return checkWeaponRange(monsterId, _mapMonsters[monsterId]._itemId_Weapon); } @@ -2907,7 +2907,7 @@ void EfhEngine::sub174A0() { static int16 sub174A0_monsterPosX = -1; static int16 sub174A0_monsterPosY = -1; - + int16 var14 = 0; int16 var6 = 0; _redrawNeededFl = true; @@ -2917,7 +2917,7 @@ void EfhEngine::sub174A0() { int16 minDisplayedMapY = CLIP(_mapPosY - 9, 0, mapSize); int16 maxDisplayedMapX = CLIP(minDisplayedMapX + 20, 0, mapSize); int16 maxDisplayedMapY = CLIP(minDisplayedMapY + 17, 0, mapSize); - + for (int16 monsterId = 0; monsterId < 64; ++monsterId) { if (!checkPictureRefAvailability(monsterId)) continue; @@ -3071,7 +3071,7 @@ void EfhEngine::sub174A0() { var1A = moveMonsterGroupOther(monsterId, getRandom(8)); continue; } - + break; } } while (!var1A && var16 > 0); @@ -3083,7 +3083,7 @@ void EfhEngine::sub174A0() { bool EfhEngine::checkPictureRefAvailability(int16 monsterId) { debugC(6, kDebugEngine, "checkPictureRefAvailability %d", monsterId); - + if (_mapMonsters[monsterId]._guess_fullPlaceId == 0xFF) return false; @@ -3283,7 +3283,7 @@ bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { displayAnimFrames(0xFE, true); return true; default: - + break; } @@ -3336,7 +3336,7 @@ void EfhEngine::sub22AA8(int16 arg0) { do { switch (*var12) { case 0x00: - case 0x0A: + case 0x0A: break; case 0x0D: case 0x20: @@ -3388,7 +3388,7 @@ void EfhEngine::sub22AA8(int16 arg0) { var2 = sub1C219(_messageToBePrinted, 1, 1, true); if (var2 != 0xFF) var4 = var2; - + if (var4 != -1) { for (int16 counter = 0; counter < 2; ++counter) { if (varA) { @@ -3405,7 +3405,7 @@ void EfhEngine::sub22AA8(int16 arg0) { if (var2 != 0xFF) var4 = var2; } - + } while (varA == 0 && var4 != -1); varA = 0; @@ -3419,7 +3419,7 @@ void EfhEngine::sub22AA8(int16 arg0) { bool EfhEngine::sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemId, int16 arg8, int16 imageSetId) { debug("sub22293 %d-%d %d %d %d %d", mapPosX, mapPosY, charId, itemId, arg8, imageSetId); - + int16 var8 = sub151FD(mapPosX, mapPosY); if (var8 == -1) { @@ -3479,7 +3479,7 @@ bool EfhEngine::sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemI sub22AA8(_mapUnknown[var8]._field5); return true; } - } + } } } @@ -3492,7 +3492,7 @@ bool EfhEngine::sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemI if (_mapUnknown[var8]._field7 > 0xFE) return false; sub22AA8(_mapUnknown[var8]._field7); - return true; + return true; } return false; @@ -3500,7 +3500,7 @@ bool EfhEngine::sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemI int8 EfhEngine::sub15581(int16 mapPosX, int16 mapPosY, int16 arg4) { debug("sub15581 %d-%d %d", mapPosX, mapPosY, arg4); - + int16 curTileInfo = getMapTileInfo(mapPosX, mapPosY); int16 imageSetId = _currentTileBankImageSetId[curTileInfo / 72]; imageSetId *= 72; @@ -3608,7 +3608,7 @@ void EfhEngine::sub1BE89(int16 monsterId) { void EfhEngine::resetTeamMonsterIdArray() { debug("resetTeamMonsterIdArray"); - + for (int i = 0; i < 5; ++i) { _teamMonsterIdArray[i] = -1; } @@ -3616,7 +3616,7 @@ void EfhEngine::resetTeamMonsterIdArray() { bool EfhEngine::isTeamMemberStatusNormal(int16 teamMemberId) { debug("isTeamMemberStatusNormal %d", teamMemberId); - + if (_npcBuf[_teamCharId[teamMemberId]]._hitPoints > 0 && _teamCharStatus[teamMemberId]._status == 0) return true; @@ -3625,7 +3625,7 @@ bool EfhEngine::isTeamMemberStatusNormal(int16 teamMemberId) { void EfhEngine::sub1CDFA() { debug("sub1CDFA"); // Initiatives - + for (int16 counter = 0; counter < 3; ++counter) { if (_teamCharId[counter] != -1 && counter < _teamSize) { _stru3244C[counter]._field0 = counter + 1000; @@ -3652,14 +3652,14 @@ void EfhEngine::sub1CDFA() { continue; SWAP(_stru3244C[counter]._field0, _stru3244C[counter2]._field0); - SWAP(_stru3244C[counter]._field2, _stru3244C[counter2]._field2); + SWAP(_stru3244C[counter]._field2, _stru3244C[counter2]._field2); } } } void EfhEngine::redrawScreenForced() { debug("redrawScreenForced"); - + for (int16 counter = 0; counter < 2; ++counter) { drawScreen(); if (counter == 0) @@ -3669,7 +3669,7 @@ void EfhEngine::redrawScreenForced() { int16 EfhEngine::selectMonsterGroup() { debug("selectMonsterGroup"); - + int16 retVal = -1; while (retVal == -1) { @@ -3697,9 +3697,9 @@ int16 EfhEngine::selectMonsterGroup() { int16 EfhEngine::sub1C956(int16 charId, int16 unkFied18Val, bool arg4) { debug("sub1C956 %d %d %d", charId, unkFied18Val, arg4); - + int16 varE = -1; - + int16 var6 = sub1C80A(charId, unkFied18Val, true); int16 range = 0; if (var6 != 0x7FFF) @@ -3748,7 +3748,7 @@ int16 EfhEngine::sub1C956(int16 charId, int16 unkFied18Val, bool arg4) { if (varE == 27) varE = -1; - + return varE; } @@ -3841,7 +3841,7 @@ bool EfhEngine::sub1CB27() { case 26: _teamNextAttack[counter1] = 0xC8; break; - + case 19: case 20: case 21: @@ -3850,9 +3850,9 @@ bool EfhEngine::sub1CB27() { default: break; } - + } - + } break; case Common::KEYCODE_t: // Terrain @@ -3895,7 +3895,7 @@ void EfhEngine::sub1BE9A(int16 monsterId) { } _teamMonsterIdArray[counter1] = _teamMonsterIdArray[counter2]; } - + } // sub1BE9A - 1rst loop counter1_monsterId - End @@ -3916,7 +3916,7 @@ void EfhEngine::sub1BE9A(int16 monsterId) { for (int16 counter1 = 0; counter1 < 64; ++counter1) { if (_mapMonsters[counter1]._guess_fullPlaceId == 0xFF) continue; - + if (((_mapMonsters[counter1]._possessivePronounSHL6 & 0x3F) == 0x3F && !isCharacterATeamMember(_mapMonsters[counter1]._field_1)) || (_mapMonsters[counter1]._possessivePronounSHL6 & 0x3F) <= 0x3D) { if (checkIfMonsterOnSameLargeMapPlace(counter1)) { bool var6 = false; @@ -3946,12 +3946,12 @@ void EfhEngine::sub1BE9A(int16 monsterId) { for (int16 counter2 = 0; counter2 < 9; ++counter2) { _stru32686[counter1]._field0[counter2] = 0; } - + if (++var4 >= 5) break; } } - } + } } // sub1BE9A - loop var2 - End } @@ -3993,7 +3993,7 @@ int16 EfhEngine::getTeamMonsterAnimId() { int16 EfhEngine::countMonsterGroupMembers(int16 monsterGroup) { debugC(9, kDebugEngine, "countMonsterGroupMembers %d", monsterGroup); - + int16 result = 0; for (int16 counter = 0; counter < 9; ++counter) { if (isMonsterActive(monsterGroup, counter)) @@ -4121,7 +4121,7 @@ void EfhEngine::drawCombatScreen(int16 charId, bool whiteFl, bool forceDrawFl) { void EfhEngine::handleFight_checkEndEffect(int16 charId) { debug("handleFight_checkEndEffect %d", charId); - + // In the original, this function is part of handleFight. // It has been split for readability purposes. if (_teamCharStatus[charId]._status == 0) @@ -4159,7 +4159,7 @@ void EfhEngine::handleFight_checkEndEffect(int16 charId) { int16 EfhEngine::sub1DEC8(int16 groupNumber) { debug("sub1DEC8 %d", groupNumber); - + int16 var4 = -1; int16 monsterId = _teamMonsterIdArray[groupNumber]; @@ -4390,7 +4390,7 @@ bool EfhEngine::hasAdequateDefense(int16 monsterId, uint8 attackType) { debug("hasAdequateDefense %d %d", monsterId, attackType); int16 itemId = _mapMonsters[monsterId]._itemId_Weapon; - + if (_items[itemId].field_16 != 0) return false; @@ -4662,14 +4662,14 @@ void EfhEngine::getDeathTypeDescription(int16 attackerId, int16 victimId) { break; default: break; - } + } strncat((char *)_messageToBePrinted, buffer, 80); } bool EfhEngine::characterSearchesMonsterCorpse(int16 charId, int16 monsterId) { debug("characterSearchesMonsterCorpse %d %d", charId, monsterId); - + int16 rndVal = getRandom(100); if (kEncounters[_mapMonsters[monsterId]._monsterRef]._dropOccurrencePct < rndVal) return false; @@ -4708,12 +4708,12 @@ void EfhEngine::getXPAndSearchCorpse(int16 charId, Common::String namePt1, Commo strncat((char *)_messageToBePrinted, buffer, 80); if (!characterSearchesMonsterCorpse(charId, monsterId)) strncat((char *)_messageToBePrinted, "!", 2); - + } void EfhEngine::addReactionText(int16 id) { debug("addReactionText %d", id); - + int16 rand3 = getRandom(3); char buffer[80]; memset(buffer, 0, 80); @@ -4910,12 +4910,12 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { } } // Action A - Loop var84 - End - + if (originalDamage < 0) originalDamage = 0; hitPoints = originalDamage + damagePointsAbsorbed; - + if (!checkSpecialItemsOnCurrentPlace(unk_monsterField5_itemId)) var62 = 0; @@ -5127,7 +5127,7 @@ char EfhEngine::getFightMessageLastCharacter(char *message) { void EfhEngine::sub1D8C2(int16 charId, int16 damage) { debug("sub1D8C2 %d %d", charId, damage); - + int16 var42 = 0; int16 var40 = _npcBuf[charId]._possessivePronounSHL6 / 64; @@ -5432,7 +5432,7 @@ bool EfhEngine::handleFight(int16 monsterId) { break; default: break; - } + } // handleFight - Check effect - end } else { snprintf((char *)_messageToBePrinted, 400, "%s%s tries to use %s %s, but it doesn't work!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPossessive[var70], _nameBuffer.c_str()); @@ -5697,7 +5697,7 @@ void EfhEngine::displayCharacterSummary(int16 curMenuLine, int16 npcId) { void EfhEngine::displayCharacterInformationOrSkills(int16 curMenuLine, int16 charId) { debug("displayCharacterInformationOrSkills %d %d", curMenuLine, charId); - + setTextColorRed(); Common::String buffer = _npcBuf[charId]._name; setTextPos(146, 27); @@ -5734,7 +5734,7 @@ void EfhEngine::displayCharacterInformationOrSkills(int16 curMenuLine, int16 cha void EfhEngine::displayStatusMenuActions(int16 menuId, int16 curMenuLine, int16 npcId) { debug("displayStatusMenuActions %d %d %d", menuId, curMenuLine, npcId); - + drawColoredRect(144, 15, 310, 184, 0); displayCenteredString("(ESCape Aborts)", 144, 310, 175); _textColor = 0x0E; @@ -5807,7 +5807,7 @@ int16 EfhEngine::displayString_3(const char *str, bool animFl, int16 charId, int debug("displayString_3 %s %s %d %d %d %d", str, animFl ? "True" : "False", charId, windowId, menuId, curMenuLine); int16 retVal = 0; - + for (int16 counter = 0; counter < 2; ++counter) { unk_StatusMenu(windowId, menuId, curMenuLine, charId, true, false); displayWindow(_windowWithBorderBuf, 19, 113, _hiResImageBuf); @@ -5824,7 +5824,7 @@ int16 EfhEngine::displayString_3(const char *str, bool animFl, int16 charId, int getLastCharAfterAnimCount(_guessAnimationAmount); sub18E80(charId, windowId, menuId, curMenuLine); } - + return retVal; } @@ -5855,7 +5855,7 @@ void EfhEngine::equipCursedItem(int16 charId, int16 objectId, int16 windowId, in } else { displayString_3("Cursed Item Already Equipped!", true, charId, windowId, menuId, curMenuLine); } - + } void EfhEngine::sub191FF(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine) { @@ -5919,7 +5919,7 @@ int16 EfhEngine::selectOtherCharFromTeam() { debug("selectOtherCharFromTeam"); Common::KeyCode maxVal = (Common::KeyCode) (Common::KEYCODE_0 + _teamSize); - Common::KeyCode input = Common::KEYCODE_INVALID; + Common::KeyCode input = Common::KEYCODE_INVALID; for (;;) { input = waitForKey(); if (input == Common::KEYCODE_ESCAPE || (input >= Common::KEYCODE_0 && input <= maxVal)) @@ -5970,7 +5970,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me } } } - // The original was duplicating this code in each branch of the previous random check. + // The original was duplicating this code in each branch of the previous random check. if (victims > 1) { buffer1 = Common::String::format("%d %ss fall asleep!", victims, kEncounters[_mapMonsters[_teamMonsterIdArray[windowId]]._monsterRef]._name); } else { @@ -6051,7 +6051,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me } break; } - } + } } } varA6 = true; @@ -6071,7 +6071,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me if (isMonsterActive(windowId, counter)) { _mapMonsters[_teamMonsterIdArray[windowId]]._pictureRef[counter] = 0; } - } + } } } @@ -6106,7 +6106,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me if (_word32482[varAA] < 0) _word32482[varAA] = 0; } - + varA6 = true; } break; @@ -6122,7 +6122,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me if (teamCharId != 0x1B) { buffer1 = " The magic makes the user invisible!"; if (argA == 2) { - displayString_3(buffer1.c_str(), false, charId, windowId, menuId, curMenuLine); + displayString_3(buffer1.c_str(), false, charId, windowId, menuId, curMenuLine); } else { strncat((char *)_messageToBePrinted, buffer1.c_str(), 80); } @@ -6172,7 +6172,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me } } - varA6 = true; + varA6 = true; } break; case 17: { // "Devil Dust" @@ -6384,7 +6384,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me if (_teamCharStatus[teamCharId]._status == 0) { strncat((char *)_messageToBePrinted, " The item makes a loud noise, awakening the character!", 80); _teamCharStatus[teamCharId]._status = 0; - _teamCharStatus[teamCharId]._duration = 0; + _teamCharStatus[teamCharId]._duration = 0; } else { strncat((char *)_messageToBePrinted, " The item makes a loud noise, but has no effect!", 80); } @@ -6401,7 +6401,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me } else { teamCharId = windowId; } - + if (teamCharId != 0x1B) { int16 effectPoints = getRandom(_items[itemId].field17_attackTypeDefense); _npcBuf[_teamCharId[teamCharId]]._hitPoints += effectPoints; @@ -6453,7 +6453,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me } varA6 = true; - + } break; case 3: @@ -7105,9 +7105,9 @@ void EfhEngine::checkProtection() { _textColor = 0xE; //CHECKME : Well, yeah, some code may be missing there. Who knows. - + _protectionPassed = true; - drawGameScreenAndTempText(true); + drawGameScreenAndTempText(true); } void EfhEngine::loadEfhGame() { @@ -7141,7 +7141,7 @@ void EfhEngine::loadEfhGame() { _teamSize = f.readSint16LE(); - _unkArray2C8AA[0] = f.readSint16LE(); + _unkArray2C8AA[0] = f.readSint16LE(); _word2C872 = f.readSint16LE(); @@ -7212,7 +7212,7 @@ uint16 EfhEngine::getStringWidth(const char *buffer) { if (retVal) retVal--; - + return retVal; } diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 8e5211638e3b..8b8d3e1fd68f 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -49,7 +49,7 @@ class RandomSource; * * Games using this engine: * - Escape From Hell - * + * * Note: Wasteland and Fountain of dreams *seem* to use the same engine, but it's not the case. * Escape From Hell was written from scratch based on the visual look of the other */ @@ -481,7 +481,7 @@ class EfhEngine : public Engine { void setDefaultNoteDuration(); void decryptImpFile(bool techMapFl); void loadImageSet(int16 imageSetId, uint8 *buffer, uint8 **subFilesArray, uint8 *destBuffer); - void rImageFile(Common::String filename, uint8 *targetBuffer, uint8 **subFilesArray, uint8 *packedBuffer); + void rImageFile(Common::String filename, uint8 *targetBuffer, uint8 **subFilesArray, uint8 *packedBuffer); uint32 uncompressBuffer(uint8 *compressedBuf, uint8 *destBuf); int16 getRandom(int16 maxVal); Common::KeyCode getLastCharAfterAnimCount(int16 delay); @@ -526,7 +526,7 @@ class EfhEngine : public Engine { Common::String _nameBuffer; char _attackBuffer[20]; uint8 _messageToBePrinted[400]; - + uint8 *_mapBitmapRefArr[19]; UnkMapStruct _mapUnknown[100]; MapMonster _mapMonsters[64]; @@ -558,7 +558,7 @@ class EfhEngine : public Engine { int16 _teamCharId[3]; int16 _textPosX; int16 _textPosY; - + Common::Rect _initRect; bool _engineInitPending; bool _protectionPassed; diff --git a/engines/efh/graphics.cpp b/engines/efh/graphics.cpp index 486fd75ecdc6..cb81f6841dc0 100644 --- a/engines/efh/graphics.cpp +++ b/engines/efh/graphics.cpp @@ -103,7 +103,7 @@ void EfhEngine::displayAnimFrames(int16 animId, bool displayMenuBoxFl) { void EfhEngine::displayFctFullScreen() { debugC(1, kDebugGraphics, "displayFctFullScreen"); - + // CHECKME: 319 is in the original but looks suspicious. // copyDirtyRect(0, 0, 319, 200); diff --git a/engines/efh/metaengine.cpp b/engines/efh/metaengine.cpp index 01d76fb82648..f39da1dfd735 100644 --- a/engines/efh/metaengine.cpp +++ b/engines/efh/metaengine.cpp @@ -155,7 +155,7 @@ SaveStateDescriptor EfhMetaEngine::querySaveMetaInfos(const char *target, int sl return SaveStateDescriptor(); } desc.setThumbnail(thumbnail); - + // Read in save date/time int16 year = file->readSint16LE(); int16 month = file->readSint16LE(); @@ -164,7 +164,7 @@ SaveStateDescriptor EfhMetaEngine::querySaveMetaInfos(const char *target, int sl int16 minute = file->readSint16LE(); desc.setSaveDate(year, month, day); desc.setSaveTime(hour, minute); - + desc.setDeletableFlag(slot != 0); desc.setWriteProtectedFlag(slot == 0); diff --git a/engines/efh/utils.cpp b/engines/efh/utils.cpp index e621d91b37a1..d95845d0458f 100644 --- a/engines/efh/utils.cpp +++ b/engines/efh/utils.cpp @@ -285,7 +285,7 @@ Common::KeyCode EfhEngine::handleAndMapInput(bool animFl) { _system->getEventManager()->pollEvent(event); Common::KeyCode retVal = Common::KEYCODE_INVALID; - uint32 lastMs = _system->getMillis(); + uint32 lastMs = _system->getMillis(); while (retVal == Common::KEYCODE_INVALID) { _system->getEventManager()->pollEvent(event); From 473b74aab3cc936f2aa1d01d1a931ece7f64411e Mon Sep 17 00:00:00 2001 From: Strangerke Date: Wed, 23 Nov 2022 21:23:22 +0100 Subject: [PATCH 170/412] EFH: Fix headers (GPLv3) --- engines/efh/constants.cpp | 15 +++++++-------- engines/efh/constants.h | 15 +++++++-------- engines/efh/detection.cpp | 15 +++++++-------- engines/efh/detection.h | 15 +++++++-------- engines/efh/efh.cpp | 15 +++++++-------- engines/efh/efh.h | 15 +++++++-------- engines/efh/graphics.cpp | 15 +++++++-------- engines/efh/metaengine.cpp | 15 +++++++-------- engines/efh/utils.cpp | 15 +++++++-------- 9 files changed, 63 insertions(+), 72 deletions(-) diff --git a/engines/efh/constants.cpp b/engines/efh/constants.cpp index 2deb3ec07829..a4ac45ecc2c7 100644 --- a/engines/efh/constants.cpp +++ b/engines/efh/constants.cpp @@ -4,19 +4,18 @@ * 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 2 - * of the License, or (at your option) any later version. - + * 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * along with this program. If not, see . * */ diff --git a/engines/efh/constants.h b/engines/efh/constants.h index 0fced1a00fae..d90cab882f5f 100644 --- a/engines/efh/constants.h +++ b/engines/efh/constants.h @@ -4,19 +4,18 @@ * 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 2 - * of the License, or (at your option) any later version. - + * 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * along with this program. If not, see . * */ diff --git a/engines/efh/detection.cpp b/engines/efh/detection.cpp index e58602b5e1c5..3f563edce6a7 100644 --- a/engines/efh/detection.cpp +++ b/engines/efh/detection.cpp @@ -4,19 +4,18 @@ * 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 2 - * of the License, or (at your option) any later version. - + * 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * along with this program. If not, see . * */ diff --git a/engines/efh/detection.h b/engines/efh/detection.h index 9c4a40452b83..c48a6d0ea2fa 100644 --- a/engines/efh/detection.h +++ b/engines/efh/detection.h @@ -4,19 +4,18 @@ * 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 2 - * of the License, or (at your option) any later version. - + * 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * along with this program. If not, see . * */ diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 3068ab76f0f3..40a35c40b5e9 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -4,19 +4,18 @@ * 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 2 - * of the License, or (at your option) any later version. - + * 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * along with this program. If not, see . * */ diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 8b8d3e1fd68f..44eaaee13b9d 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -4,19 +4,18 @@ * 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 2 - * of the License, or (at your option) any later version. - + * 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * along with this program. If not, see . * */ diff --git a/engines/efh/graphics.cpp b/engines/efh/graphics.cpp index cb81f6841dc0..7d87337f7ce3 100644 --- a/engines/efh/graphics.cpp +++ b/engines/efh/graphics.cpp @@ -4,19 +4,18 @@ * 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 2 - * of the License, or (at your option) any later version. - + * 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * along with this program. If not, see . * */ diff --git a/engines/efh/metaengine.cpp b/engines/efh/metaengine.cpp index f39da1dfd735..fbb31d5181e7 100644 --- a/engines/efh/metaengine.cpp +++ b/engines/efh/metaengine.cpp @@ -4,19 +4,18 @@ * 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 2 - * of the License, or (at your option) any later version. - + * 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * along with this program. If not, see . * */ diff --git a/engines/efh/utils.cpp b/engines/efh/utils.cpp index d95845d0458f..2d379bde8595 100644 --- a/engines/efh/utils.cpp +++ b/engines/efh/utils.cpp @@ -4,19 +4,18 @@ * 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 2 - * of the License, or (at your option) any later version. - + * 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * along with this program. If not, see . * */ From 7ec543b2bf2ab3b1c349f30f653e42e67427fe9d Mon Sep 17 00:00:00 2001 From: Strangerke Date: Wed, 23 Nov 2022 23:20:47 +0100 Subject: [PATCH 171/412] EFH: Remove game type, simplify game descriptions --- engines/efh/constants.cpp | 2 +- engines/efh/detection.cpp | 32 +++++++++++++---------------- engines/efh/detection.h | 41 -------------------------------------- engines/efh/efh.cpp | 7 +------ engines/efh/efh.h | 13 +++++------- engines/efh/metaengine.cpp | 14 ++++++------- 6 files changed, 27 insertions(+), 82 deletions(-) delete mode 100644 engines/efh/detection.h diff --git a/engines/efh/constants.cpp b/engines/efh/constants.cpp index a4ac45ecc2c7..e5550d481d79 100644 --- a/engines/efh/constants.cpp +++ b/engines/efh/constants.cpp @@ -21,7 +21,7 @@ #include "efh/constants.h" -#include "engine.h" +#include "engines/engine.h" namespace Efh { diff --git a/engines/efh/detection.cpp b/engines/efh/detection.cpp index 3f563edce6a7..81f13ff46dd3 100644 --- a/engines/efh/detection.cpp +++ b/engines/efh/detection.cpp @@ -21,9 +21,7 @@ #include "base/plugins.h" #include "engines/advancedDetector.h" -#include "common/textconsole.h" -#include "efh/detection.h" #include "efh/efh.h" namespace Efh { @@ -34,27 +32,25 @@ static const PlainGameDescriptor efhGames[] = { {nullptr, nullptr} }; -static const EfhGameDescription gameDescriptions[] = { +static const ADGameDescription gameDescriptions[] = { // Escape From Hell English - Unpacked version { - {"efh", nullptr, AD_ENTRY1s("escape.exe", "2702f8f713e113a853a925d29aecc709", 147312), - Common::EN_ANY, - Common::kPlatformDOS, - ADGF_UNSTABLE, - GUIO0() - }, - kGameTypeEfh + "efh", nullptr, AD_ENTRY1s("escape.exe", "2702f8f713e113a853a925d29aecc709", 147312), + Common::EN_ANY, + Common::kPlatformDOS, + ADGF_UNSTABLE, + GUIO0() }, // Escape From Hell English { - {"efh", nullptr, AD_ENTRY1s("escape.exe", "1ca4ae3f2ea66c30d1ef3e257a86cd05", 141487), - Common::EN_ANY, - Common::kPlatformDOS, - ADGF_UNSTABLE, - GUIO0()}, - kGameTypeEfh}, - {AD_TABLE_END_MARKER, kGameTypeNone} + "efh", nullptr, AD_ENTRY1s("escape.exe", "1ca4ae3f2ea66c30d1ef3e257a86cd05", 141487), + Common::EN_ANY, + Common::kPlatformDOS, + ADGF_UNSTABLE, + GUIO0() + }, + AD_TABLE_END_MARKER }; static const DebugChannelDef debugFlagList[] = { @@ -65,7 +61,7 @@ static const DebugChannelDef debugFlagList[] = { class EfhMetaEngineDetection : public AdvancedMetaEngineDetection { public: - EfhMetaEngineDetection() : AdvancedMetaEngineDetection(gameDescriptions, sizeof(EfhGameDescription), efhGames) { + EfhMetaEngineDetection() : AdvancedMetaEngineDetection(gameDescriptions, sizeof(ADGameDescription), efhGames) { } const char *getEngineName() const override { diff --git a/engines/efh/detection.h b/engines/efh/detection.h deleted file mode 100644 index c48a6d0ea2fa..000000000000 --- a/engines/efh/detection.h +++ /dev/null @@ -1,41 +0,0 @@ -/* 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 . - * - */ - -#ifndef EFH_DETECTION_H -#define EFH_DETECTION_H - -#include "engines/advancedDetector.h" - -namespace Efh { - -enum GameType { - kGameTypeNone = 0, - kGameTypeEfh -}; - -struct EfhGameDescription { - ADGameDescription desc; - GameType gameType; -}; - -} // End of namespace Efh - -#endif // EFH_DETECTION_H diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 40a35c40b5e9..e3768e5c009b 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -174,7 +174,7 @@ void TileFactStruct::init() { _field0 = _field1 = 0; } -EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst), _gameDescription(gd) { +EfhEngine::EfhEngine(OSystem *syst, const ADGameDescription *gd) : Engine(syst), _gameDescription(gd) { const Common::FSNode gameDataDir(ConfMan.get("path")); SearchMan.addSubDirectoryMatching(gameDataDir, "gendata"); @@ -188,7 +188,6 @@ EfhEngine::EfhEngine(OSystem *syst, const EfhGameDescription *gd) : Engine(syst) _shouldQuit = false; _eventMan = nullptr; _lastTime = 0; - _gameType = kGameTypeNone; _platform = Common::kPlatformUnknown; _mainSurface = nullptr; @@ -368,10 +367,6 @@ const char *EfhEngine::getCopyrightString() const { return "Escape From Hell (C) Electronic Arts, 1990"; } -GameType EfhEngine::getGameType() const { - return _gameType; -} - Common::Platform EfhEngine::getPlatform() const { return _platform; } diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 44eaaee13b9d..7c59a9ceffe7 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -22,9 +22,10 @@ #ifndef EFH_EFH_H #define EFH_EFH_H -#include "efh/detection.h" #include "efh/constants.h" +#include "engines/advancedDetector.h" + #include "common/file.h" #include "common/rect.h" #include "common/events.h" @@ -63,8 +64,6 @@ enum AccessDebugChannels { kDebugGraphics = 1 << 2 }; -struct EfhGameDescription; - class EfhGraphicsStruct { public: EfhGraphicsStruct(); @@ -240,19 +239,18 @@ struct TileFactStruct { class EfhEngine : public Engine { public: - EfhEngine(OSystem *syst, const EfhGameDescription *gd); + EfhEngine(OSystem *syst, const ADGameDescription *gd); ~EfhEngine() override; OSystem *_system; Graphics::Surface *_mainSurface; Common::RandomSource *_rnd; - const EfhGameDescription *_gameDescription; + const ADGameDescription *_gameDescription; uint32 getFeatures() const; const char *getGameId() const; - void initGame(const EfhGameDescription *gd); - GameType getGameType() const; + void initGame(const ADGameDescription *gd); Common::Platform getPlatform() const; bool hasFeature(EngineFeature f) const override; @@ -278,7 +276,6 @@ class EfhEngine : public Engine { private: static EfhEngine *s_Engine; - GameType _gameType; Common::Platform _platform; int _loadSaveSlot; diff --git a/engines/efh/metaengine.cpp b/engines/efh/metaengine.cpp index fbb31d5181e7..26aca59b97d8 100644 --- a/engines/efh/metaengine.cpp +++ b/engines/efh/metaengine.cpp @@ -27,16 +27,15 @@ #include "graphics/surface.h" #include "efh/efh.h" -#include "efh/detection.h" namespace Efh { uint32 EfhEngine::getFeatures() const { - return _gameDescription->desc.flags; + return _gameDescription->flags; } const char *EfhEngine::getGameId() const { - return _gameDescription->desc.gameId; + return _gameDescription->gameId; } } // End of namespace Efh @@ -59,8 +58,8 @@ class EfhMetaEngine : public AdvancedMetaEngine { }; Common::Error EfhMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *gd) const { - *engine = new EfhEngine(syst, (const EfhGameDescription *)gd); - ((EfhEngine *)*engine)->initGame((const EfhGameDescription *)gd); + *engine = new EfhEngine(syst, gd); + ((EfhEngine *)*engine)->initGame(gd); return Common::kNoError; } @@ -188,9 +187,8 @@ REGISTER_PLUGIN_STATIC(EFH, PLUGIN_TYPE_ENGINE, Efh::EfhMetaEngine); namespace Efh { -void EfhEngine::initGame(const EfhGameDescription *gd) { - _gameType = gd->gameType; - _platform = gd->desc.platform; +void EfhEngine::initGame(const ADGameDescription *gd) { + _platform = gd->platform; } } // End of namespace Efh From e10d31a6b9f77360a7ab9a0ce43332415123944c Mon Sep 17 00:00:00 2001 From: Strangerke Date: Wed, 23 Nov 2022 23:27:56 +0100 Subject: [PATCH 172/412] EFH: Fix alignment in metaengine, reorder some includes, remove a useless include --- engines/efh/constants.cpp | 2 -- engines/efh/efh.h | 3 +-- engines/efh/graphics.cpp | 2 +- engines/efh/metaengine.cpp | 2 +- engines/efh/utils.cpp | 2 +- 5 files changed, 4 insertions(+), 7 deletions(-) diff --git a/engines/efh/constants.cpp b/engines/efh/constants.cpp index e5550d481d79..6d1d01c6ee9d 100644 --- a/engines/efh/constants.cpp +++ b/engines/efh/constants.cpp @@ -21,8 +21,6 @@ #include "efh/constants.h" -#include "engines/engine.h" - namespace Efh { const uint8 kFontWidthArray[96] = { diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 7c59a9ceffe7..3d31f85993eb 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -22,8 +22,6 @@ #ifndef EFH_EFH_H #define EFH_EFH_H -#include "efh/constants.h" - #include "engines/advancedDetector.h" #include "common/file.h" @@ -34,6 +32,7 @@ #include "engines/engine.h" #include "graphics/surface.h" +#include "efh/constants.h" namespace Common { class RandomSource; diff --git a/engines/efh/graphics.cpp b/engines/efh/graphics.cpp index 7d87337f7ce3..d77759d84811 100644 --- a/engines/efh/graphics.cpp +++ b/engines/efh/graphics.cpp @@ -19,9 +19,9 @@ * */ -#include "efh/efh.h" #include "graphics/palette.h" #include "common/system.h" +#include "efh/efh.h" namespace Efh { diff --git a/engines/efh/metaengine.cpp b/engines/efh/metaengine.cpp index 26aca59b97d8..8276fe4012da 100644 --- a/engines/efh/metaengine.cpp +++ b/engines/efh/metaengine.cpp @@ -182,7 +182,7 @@ void EfhMetaEngine::removeSaveState(const char *target, int slot) const { #if PLUGIN_ENABLED_DYNAMIC(EFH) REGISTER_PLUGIN_DYNAMIC(EFH, PLUGIN_TYPE_ENGINE, Efh::EfhMetaEngine); #else -REGISTER_PLUGIN_STATIC(EFH, PLUGIN_TYPE_ENGINE, Efh::EfhMetaEngine); + REGISTER_PLUGIN_STATIC(EFH, PLUGIN_TYPE_ENGINE, Efh::EfhMetaEngine); #endif namespace Efh { diff --git a/engines/efh/utils.cpp b/engines/efh/utils.cpp index 2d379bde8595..a720686e3252 100644 --- a/engines/efh/utils.cpp +++ b/engines/efh/utils.cpp @@ -19,9 +19,9 @@ * */ -#include "efh/efh.h" #include "common/system.h" #include "common/random.h" +#include "efh/efh.h" namespace Efh { From 17a6120f5a5c1163520c2e5970e8e716040d04bd Mon Sep 17 00:00:00 2001 From: Strangerke Date: Thu, 24 Nov 2022 08:47:14 +0100 Subject: [PATCH 173/412] EFH: Start splitting efh.cpp --- engines/efh/efh.cpp | 475 ------------------------------------- engines/efh/efh.h | 44 ++-- engines/efh/files.cpp | 344 +++++++++++++++++++++++++++ engines/efh/metaengine.cpp | 12 +- engines/efh/module.mk | 2 + engines/efh/savegames.cpp | 225 ++++++++++++++++++ engines/efh/utils.cpp | 56 +---- 7 files changed, 600 insertions(+), 558 deletions(-) create mode 100644 engines/efh/files.cpp create mode 100644 engines/efh/savegames.cpp diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index e3768e5c009b..01293e74dae5 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -25,10 +25,7 @@ #include "common/config-manager.h" #include "common/events.h" #include "engines/util.h" -#include "common/savefile.h" #include "graphics/palette.h" -#include "graphics/scaler.h" -#include "graphics/thumbnail.h" #include "efh/efh.h" #include "efh/constants.h" @@ -377,100 +374,6 @@ void EfhEngine::syncSoundSettings() { // _sound->syncVolume(); } -Common::String EfhEngine::getSavegameFilename(int slot) { - return _targetName + Common::String::format("-%03d.SAV", slot); -} - -bool EfhEngine::canLoadGameStateCurrently() { - return true; -} - -bool EfhEngine::canSaveGameStateCurrently() { - return true; -} - -Common::Error EfhEngine::loadGameState(int slot) { - Common::InSaveFile *saveFile = g_system->getSavefileManager()->openForLoading(getSaveStateName(slot)); - if (!saveFile) - return Common::kReadingFailed; - - uint32 signature = saveFile->readUint32LE(); - byte version = saveFile->readByte(); - - if (signature != EFH_SAVE_HEADER || version > kSavegameVersion) - error("Invalid savegame"); - - // Skip savegame name - uint16 size = saveFile->readUint16LE(); - saveFile->skip(size); - - // Skip the thumbnail - Graphics::Surface *thumbnail; - Graphics::loadThumbnail(*saveFile, thumbnail); - delete (thumbnail); - - // Skip the savegame date - saveFile->skip(10); // year, month, day, hours, minutes (all int16) - - Common::Serializer s(saveFile, nullptr); - synchronize(s); - - delete saveFile; - - _oldMapPosX = _mapPosX; - _oldMapPosY = _mapPosY; - _unkRelatedToAnimImageSetId = 0; - - loadTechMapImp(_techId); - _lastMainPlaceId = 0xFFFF; - loadPlacesFile(_fullPlaceId, true); - - return Common::kNoError; -} - -Common::Error EfhEngine::saveGameState(int slot, const Common::String &desc, bool isAutosave) { - Common::OutSaveFile *out = _system->getSavefileManager()->openForSaving(getSaveStateName(slot)); - if (!out) - return Common::kCreatingFileFailed; - - out->writeUint32LE(EFH_SAVE_HEADER); - out->writeByte(kSavegameVersion); - - // Write savegame name - uint16 size = desc.size(); - out->writeUint16LE(size); - for (int i = 0; i < size; ++i) - out->writeByte(desc.c_str()[i]); - - // Get the active palette - uint8 thumbPalette[16 * 3]; - _system->getPaletteManager()->grabPalette(thumbPalette, 0, 16); - // Create a thumbnail and save it - Graphics::Surface *thumb = new Graphics::Surface(); - Graphics::Surface *sf = _mainSurface; - ::createThumbnail(thumb, (const byte *)sf->getPixels(), 320, 200, thumbPalette); - Graphics::saveThumbnail(*out, *thumb); - thumb->free(); - delete thumb; - - // Write out the save date/time - TimeDate td; - g_system->getTimeAndDate(td); - out->writeSint16LE(td.tm_year + 1900); - out->writeSint16LE(td.tm_mon + 1); - out->writeSint16LE(td.tm_mday); - out->writeSint16LE(td.tm_hour); - out->writeSint16LE(td.tm_min); - - Common::Serializer s(nullptr, out); - synchronize(s); - - out->finalize(); - delete out; - - return Common::kNoError; -} - Common::Error EfhEngine::run() { debug("run"); s_Engine = this; @@ -684,276 +587,14 @@ void EfhEngine::initialize() { _shouldQuit = false; } -void EfhEngine::readAnimInfo() { - debugC(6, kDebugEngine, "readAnimInfo"); - - Common::String fileName = "animinfo"; - uint8 animInfoBuf[9000]; - memset(animInfoBuf, 0, 9000); - uint8 *curPtr = animInfoBuf; - - readFileToBuffer(fileName, animInfoBuf); - for (int i = 0; i < 100; ++i) { - for (int id = 0; id < 15; ++id) { - _animInfo[i]._unkAnimArray[id]._field[0] = *curPtr++; - _animInfo[i]._unkAnimArray[id]._field[1] = *curPtr++; - _animInfo[i]._unkAnimArray[id]._field[2] = *curPtr++; - _animInfo[i]._unkAnimArray[id]._field[3] = *curPtr++; - - debugC(6, kDebugEngine, "%d %d %d %d", _animInfo[i]._unkAnimArray[id]._field[0], _animInfo[i]._unkAnimArray[id]._field[1], _animInfo[i]._unkAnimArray[id]._field[2], _animInfo[i]._unkAnimArray[id]._field[3]); - } - - Common::String debugStr = ""; - for (int id = 0; id < 10; ++id) { - _animInfo[i]._field3C_startY[id] = *curPtr++; - debugStr += Common::String::format("%d ", _animInfo[i]._field3C_startY[id]); - } - debugC(6, kDebugEngine, "%s", debugStr.c_str()); - - debugStr = ""; - for (int id = 0; id < 10; ++id) { - _animInfo[i]._field46_startX[id] = READ_LE_INT16(curPtr); - curPtr += 2; - debugStr += Common::String::format("%d ", _animInfo[i]._field46_startX[id]); - } - debugC(6, kDebugEngine, "%s", debugStr.c_str()); - debugC(6, kDebugEngine, "---------"); - } -} - -void EfhEngine::findMapFile(int16 mapId) { - debugC(7, kDebugEngine, "findMapFile %d", mapId); - - if (!_word31E9E) - return; - - Common::String fileName = Common::String::format("map.%d", mapId); - Common::File f; - // The original was checking for the file and eventually asking to change floppies - if (!f.open(fileName)) - error("File not found: %s", fileName.c_str()); - - f.close(); -} - -void EfhEngine::loadNewPortrait() { - debugC(7, kDebugEngine, "loadNewPortrait"); - - static int16 const unkConstRelatedToAnimImageSetId[19] = {0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2}; - _unkRelatedToAnimImageSetId = unkConstRelatedToAnimImageSetId[_techId]; - - if (_currentAnimImageSetId == 200 + _unkRelatedToAnimImageSetId) - return; - - findMapFile(_techId); - _currentAnimImageSetId = 200 + _unkRelatedToAnimImageSetId; - int imageSetId = _unkRelatedToAnimImageSetId + 13; - loadImageSet(imageSetId, _portraitBuf, _portraitSubFilesArray, _hiResImageBuf); -} - -void EfhEngine::loadAnimImageSet() { - debug("loadAnimImageSet"); - - if (_currentAnimImageSetId == _animImageSetId || _animImageSetId == 0xFF) - return; - - findMapFile(_techId); - - _unkAnimRelatedIndex = 0; - _currentAnimImageSetId = _animImageSetId; - - int16 animSetId = _animImageSetId + 17; - loadImageSet(animSetId, _portraitBuf, _portraitSubFilesArray, _hiResImageBuf); -} - -void EfhEngine::loadHistory() { - debug("loadHistory"); - - Common::String fileName = "history"; - readFileToBuffer(fileName, _history); -} - -void EfhEngine::loadTechMapImp(int16 fileId) { - debug("loadTechMapImp %d", fileId); - - if (fileId == 0xFF) - return; - - _techId = fileId; - findMapFile(_techId); - - // The original was loading the specific tech.%d and map.%d files. - // This is gone in our implementation as we pre-load all the files to save them inside the savegames - - // This is not present in the original. - // The purpose is to properly load the misc map data in arrays in order to use them without being a pain afterwards - loadMapArrays(_techId); - - loadImageSetToTileBank(1, _mapBitmapRefArr[_techId][0] + 1); - loadImageSetToTileBank(2, _mapBitmapRefArr[_techId][1] + 1); - - initMapMonsters(); - readImpFile(_techId, true); - displayAnimFrames(0xFE, false); - -} - -void EfhEngine::loadPlacesFile(uint16 fullPlaceId, bool forceReloadFl) { - debug("loadPlacesFile %d %s", fullPlaceId, forceReloadFl ? "True" : "False"); - - if (fullPlaceId == 0xFF) - return; - - findMapFile(_techId); - _fullPlaceId = fullPlaceId; - uint16 minPlace = _lastMainPlaceId * 20; - uint16 maxPlace = minPlace + 19; - - if (_fullPlaceId < minPlace || _fullPlaceId > maxPlace || forceReloadFl) { - _lastMainPlaceId = _fullPlaceId / 20; - Common::String fileName = Common::String::format("places.%d", _lastMainPlaceId); - readFileToBuffer(fileName, _hiResImageBuf); - uncompressBuffer(_hiResImageBuf, _places); - } - copyCurrentPlaceToBuffer(_fullPlaceId % 20); -} - -void EfhEngine::readTileFact() { - debugC(7, kDebugEngine, "readTileFact"); - - Common::String fileName = "tilefact"; - uint8 tileFactBuff[864]; - readFileToBuffer(fileName, tileFactBuff); - uint8 *curPtr = tileFactBuff; - for (int i = 0; i < 432; ++i) { - _tileFact[i]._field0 = *curPtr++; - _tileFact[i]._field1 = *curPtr++; - } -} - -void EfhEngine::readItems() { - debugC(7, kDebugEngine, "readItems"); - - Common::String fileName = "items"; - uint8 itemBuff[8100]; - readFileToBuffer(fileName, itemBuff); - uint8 *curPtr = itemBuff; - - for (int i = 0; i < 300; ++i) { - for (int16 idx = 0; idx < 15; ++idx) - _items[i]._name[idx] = *curPtr++; - - - _items[i]._damage = *curPtr++; - _items[i]._defense = *curPtr++; - _items[i]._attacks = *curPtr++; - _items[i]._uses = *curPtr++; - _items[i].field_13 = *curPtr++; - _items[i]._range = *curPtr++; - _items[i]._attackType = *curPtr++; - _items[i].field_16 = *curPtr++; - _items[i].field17_attackTypeDefense = *curPtr++; - _items[i].field_18 = *curPtr++; - _items[i].field_19 = *curPtr++; - _items[i].field_1A = *curPtr++; - - debugC(7, kDebugEngine, "%s\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x", _items[i]._name, _items[i]._damage, _items[i]._defense, _items[i]._attacks, _items[i]._uses, _items[i].field_13, _items[i]._range, _items[i]._attackType, _items[i].field_16, _items[i].field17_attackTypeDefense, _items[i].field_18, _items[i].field_19, _items[i].field_1A); - } -} - -void EfhEngine::loadNPCS() { - debugC(7, kDebugEngine, "loadNPCS"); - - Common::String fileName = "npcs"; - uint8 npcLoading[13400]; - readFileToBuffer(fileName, npcLoading); - uint8 *curPtr = npcLoading; - - for (int i = 0; i < 99; ++i) { - for (int idx = 0; idx < 11; ++idx) - _npcBuf[i]._name[idx] = *curPtr++; - _npcBuf[i].field_B = *curPtr++; - _npcBuf[i].field_C = *curPtr++; - _npcBuf[i].field_D = *curPtr++; - _npcBuf[i].field_E = *curPtr++; - _npcBuf[i].field_F = *curPtr++; - _npcBuf[i].field_10 = *curPtr++; - _npcBuf[i].field_11 = *curPtr++; - _npcBuf[i].field_12 = READ_LE_INT16(curPtr); - _npcBuf[i].field_14 = READ_LE_INT16(curPtr + 2); - curPtr += 4; - _npcBuf[i]._xp = READ_LE_INT32(curPtr); - curPtr += 4; - for (int idx = 0; idx < 15; ++idx) { - _npcBuf[i]._activeScore[idx] = *curPtr++; - } - for (int idx = 0; idx < 11; ++idx) { - _npcBuf[i]._passiveScore[idx] = *curPtr++; - } - for (int idx = 0; idx < 11; ++idx) { - _npcBuf[i]._infoScore[idx] = *curPtr++; - } - _npcBuf[i].field_3F = *curPtr++; - _npcBuf[i].field_40 = *curPtr++; - for (int idx = 0; idx < 10; ++idx) { - _npcBuf[i]._inventory[idx]._ref = READ_LE_INT16(curPtr); - curPtr += 2; - _npcBuf[i]._inventory[idx]._stat1 = *curPtr++; - _npcBuf[i]._inventory[idx]._stat2 = *curPtr++; - } - _npcBuf[i]._possessivePronounSHL6 = *curPtr++; - _npcBuf[i]._speed = *curPtr++; - _npcBuf[i].field_6B = *curPtr++; - _npcBuf[i].field_6C = *curPtr++; - _npcBuf[i].field_6D = *curPtr++; - _npcBuf[i]._unkItemId = *curPtr++; - _npcBuf[i].field_6F = *curPtr++; - _npcBuf[i].field_70 = *curPtr++; - _npcBuf[i].field_71 = *curPtr++; - _npcBuf[i].field_72 = *curPtr++; - _npcBuf[i].field_73 = *curPtr++; - _npcBuf[i]._hitPoints = READ_LE_INT16(curPtr); - _npcBuf[i]._maxHP = READ_LE_INT16(curPtr + 2); - curPtr += 4; - _npcBuf[i].field_78 = *curPtr++; - _npcBuf[i].field_79 = READ_LE_INT16(curPtr); - _npcBuf[i].field_7B = READ_LE_INT16(curPtr + 2); - curPtr += 4; - _npcBuf[i].field_7D = *curPtr++; - _npcBuf[i].field_7E = *curPtr++; - _npcBuf[i].field_7F = *curPtr++; - _npcBuf[i].field_80 = *curPtr++; - _npcBuf[i].field_81 = *curPtr++; - _npcBuf[i].field_82 = *curPtr++; - _npcBuf[i].field_83 = *curPtr++; - _npcBuf[i].field_84 = *curPtr++; - _npcBuf[i].field_85 = *curPtr++; - } -} - Common::KeyCode EfhEngine::playSong(uint8 *buffer) { warning("STUB: playSong"); - - _system->delayMillis(1000); return Common::KEYCODE_INVALID; } -void EfhEngine::readImpFile(int16 id, bool techMapFl) { - debug("readImpFile %d %s", id, techMapFl ? "True" : "False"); - - Common::String fileName = Common::String::format("imp.%d", id); - - if (techMapFl) - readFileToBuffer(fileName, _imp1); - else - readFileToBuffer(fileName, _imp2); - - decryptImpFile(techMapFl); -} - void EfhEngine::playIntro() { debugC(6, kDebugEngine, "playIntro"); @@ -1031,24 +672,6 @@ void EfhEngine::playIntro() { getLastCharAfterAnimCount(80); } -/** - * Pre-Loads MAP and TECH files. - * This is required in order to implement a clean savegame feature - */ -void EfhEngine::preLoadMaps() { - for (int i = 0; i < 19; ++i) { - Common::String fileName = Common::String::format("tech.%d", i); - readFileToBuffer(fileName, _hiResImageBuf); - uncompressBuffer(_hiResImageBuf, _techDataArr[i]); - - fileName = Common::String::format("map.%d", i); - readFileToBuffer(fileName, _hiResImageBuf); - uncompressBuffer(_hiResImageBuf, _mapArr[i]); - - _mapBitmapRefArr[i] = &_mapArr[i][0]; - } -} - void EfhEngine::initEngine() { _videoMode = 2; // In the original, 2 = VGA/MCGA, EGA = 4, Tandy = 6, cga = 8. _graphicsStruct = new EfhGraphicsStruct; @@ -6974,104 +6597,6 @@ bool EfhEngine::checkMonsterCollision() { return true; } -void EfhEngine::synchronize(Common::Serializer &s) { - s.syncAsSint16LE(_techId); - s.syncAsUint16LE(_fullPlaceId); - s.syncAsSint16LE(_guessAnimationAmount); - s.syncAsUint16LE(_largeMapFlag); - s.syncAsSint16LE(_teamCharId[0]); - s.syncAsSint16LE(_teamCharId[1]); - s.syncAsSint16LE(_teamCharId[2]); - - for (int i = 0; i < 3; ++i) { - s.syncAsSint16LE(_teamCharStatus[i]._status); - s.syncAsSint16LE(_teamCharStatus[i]._duration); - } - - s.syncAsSint16LE(_teamSize); - s.syncAsSint16LE(_unkArray2C8AA[0]); - s.syncAsSint16LE(_word2C872); - s.syncAsSint16LE(_imageSetSubFilesIdx); - s.syncAsSint16LE(_mapPosX); - s.syncAsSint16LE(_mapPosY); - s.syncAsSint16LE(_techDataId_MapPosX); - s.syncAsSint16LE(_techDataId_MapPosY); - - for (int i = 0; i < 19; ++i) { - int size = ARRAYSIZE(_techDataArr[i]); - for (int j = 0; j < size; ++j) - s.syncAsByte(_techDataArr[i][j]); - - size = ARRAYSIZE(_mapArr[i]); - for (int j = 0; j < size; ++j) - s.syncAsByte(_mapArr[i][j]); - - _mapBitmapRefArr[i] = &_mapArr[i][0]; - } - - // Dialog flags - for (int i = 0; i < 256; ++i) - s.syncAsByte(_history[i]); - - // NPCs - for (int i = 0; i < 99; ++i) { - for (int idx = 0; idx < 11; ++idx) - s.syncAsByte(_npcBuf[i]._name[idx]); - - s.syncAsByte(_npcBuf[i].field_B); - s.syncAsByte(_npcBuf[i].field_C); - s.syncAsByte(_npcBuf[i].field_D); - s.syncAsByte(_npcBuf[i].field_E); - s.syncAsByte(_npcBuf[i].field_F); - s.syncAsByte(_npcBuf[i].field_10); - s.syncAsByte(_npcBuf[i].field_11); - s.syncAsSint16LE(_npcBuf[i].field_12); - s.syncAsSint16LE(_npcBuf[i].field_14); - s.syncAsSint32LE(_npcBuf[i]._xp); - for (int idx = 0; idx < 15; ++idx) - s.syncAsByte(_npcBuf[i]._activeScore[idx]); - - for (int idx = 0; idx < 11; ++idx) - s.syncAsByte(_npcBuf[i]._passiveScore[idx]); - - for (int idx = 0; idx < 11; ++idx) - s.syncAsByte(_npcBuf[i]._infoScore[idx]); - - s.syncAsByte(_npcBuf[i].field_3F); - s.syncAsByte(_npcBuf[i].field_40); - for (int idx = 0; idx < 10; ++idx) { - s.syncAsSint16LE(_npcBuf[i]._inventory[idx]._ref); - s.syncAsByte(_npcBuf[i]._inventory[idx]._stat1); - s.syncAsByte(_npcBuf[i]._inventory[idx]._stat2); - } - s.syncAsByte(_npcBuf[i]._possessivePronounSHL6); - s.syncAsByte(_npcBuf[i]._speed); - s.syncAsByte(_npcBuf[i].field_6B); - s.syncAsByte(_npcBuf[i].field_6C); - s.syncAsByte(_npcBuf[i].field_6D); - s.syncAsByte(_npcBuf[i]._unkItemId); - s.syncAsByte(_npcBuf[i].field_6F); - s.syncAsByte(_npcBuf[i].field_70); - s.syncAsByte(_npcBuf[i].field_71); - s.syncAsByte(_npcBuf[i].field_72); - s.syncAsByte(_npcBuf[i].field_73); - s.syncAsSint16LE(_npcBuf[i]._hitPoints); - s.syncAsSint16LE(_npcBuf[i]._maxHP); - s.syncAsByte(_npcBuf[i].field_78); - s.syncAsSint16LE(_npcBuf[i].field_79); - s.syncAsSint16LE(_npcBuf[i].field_7B); - s.syncAsByte(_npcBuf[i].field_7D); - s.syncAsByte(_npcBuf[i].field_7E); - s.syncAsByte(_npcBuf[i].field_7F); - s.syncAsByte(_npcBuf[i].field_80); - s.syncAsByte(_npcBuf[i].field_81); - s.syncAsByte(_npcBuf[i].field_82); - s.syncAsByte(_npcBuf[i].field_83); - s.syncAsByte(_npcBuf[i].field_84); - s.syncAsByte(_npcBuf[i].field_85); - } -} - void EfhEngine::loadImageSetToTileBank(int16 tileBankId, int16 imageSetId) { debugC(3, kDebugEngine, "loadImageSetToTileBank %d %d", tileBankId, imageSetId); diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 3d31f85993eb..8d25d0dbb195 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -255,15 +255,15 @@ class EfhEngine : public Engine { bool hasFeature(EngineFeature f) const override; const char *getCopyrightString() const; - Common::String getSavegameFilename(int slot); + void syncSoundSettings() override; + // Savegames.cpp + Common::String getSavegameFilename(int slot); bool canLoadGameStateCurrently() override; bool canSaveGameStateCurrently() override; Common::Error loadGameState(int slot) override; Common::Error saveGameState(int slot, const Common::String &desc, bool isAutosave = false) override; - void syncSoundSettings() override; - bool _shouldQuit; protected: @@ -279,20 +279,8 @@ class EfhEngine : public Engine { int _loadSaveSlot; void initialize(); - void readAnimInfo(); - void findMapFile(int16 mapId); - void loadNewPortrait(); - void loadAnimImageSet(); - void loadHistory(); - void loadTechMapImp(int16 fileId); - void loadPlacesFile(uint16 fullPlaceId, bool forceReloadFl); - void readTileFact(); - void readItems(); - void loadNPCS(); Common::KeyCode playSong(uint8 *buffer); - void readImpFile(int16 id, bool techMapFl); void playIntro(); - void preLoadMaps(); void initEngine(); void initMapMonsters(); void loadMapArrays(int idx); @@ -433,7 +421,22 @@ class EfhEngine : public Engine { int16 sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine, int16 argA); int16 handleStatusMenu(int16 gameMode, int16 charId); bool checkMonsterCollision(); - void synchronize(Common::Serializer &s); + + // Files + int32 readFileToBuffer(Common::String &filename, uint8 *destBuffer); + void readAnimInfo(); + void findMapFile(int16 mapId); + void rImageFile(Common::String filename, uint8 *targetBuffer, uint8 **subFilesArray, uint8 *packedBuffer); + void readItems(); + void readImpFile(int16 id, bool techMapFl); + void loadNewPortrait(); + void loadAnimImageSet(); + void loadHistory(); + void loadTechMapImp(int16 fileId); + void loadPlacesFile(uint16 fullPlaceId, bool forceReloadFl); + void readTileFact(); + void loadNPCS(); + void preLoadMaps(); // Graphics void initPalette(); @@ -468,15 +471,13 @@ class EfhEngine : public Engine { void displayWindow(uint8 *buffer, int16 posX, int16 posY, uint8 *dest); void displayColoredMenuBox(int16 minX, int16 minY, int16 maxX, int16 maxY, int16 color); + // Savegames + void synchronize(Common::Serializer &s); + // Utils - #if false - void copyString(char *srcStr, char *destStr); - #endif - int32 readFileToBuffer(Common::String &filename, uint8 *destBuffer); void setDefaultNoteDuration(); void decryptImpFile(bool techMapFl); void loadImageSet(int16 imageSetId, uint8 *buffer, uint8 **subFilesArray, uint8 *destBuffer); - void rImageFile(Common::String filename, uint8 *targetBuffer, uint8 **subFilesArray, uint8 *packedBuffer); uint32 uncompressBuffer(uint8 *compressedBuf, uint8 *destBuf); int16 getRandom(int16 maxVal); Common::KeyCode getLastCharAfterAnimCount(int16 delay); @@ -488,7 +489,6 @@ class EfhEngine : public Engine { void setNumLock(); bool getValidationFromUser(); - uint8 _videoMode; uint8 _bufferCharBM[128]; int8 *_vgaLineBuffer[200]; diff --git a/engines/efh/files.cpp b/engines/efh/files.cpp new file mode 100644 index 000000000000..5c6a50d27e9d --- /dev/null +++ b/engines/efh/files.cpp @@ -0,0 +1,344 @@ +/* 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 "efh/efh.h" + +namespace Efh { + +int32 EfhEngine::readFileToBuffer(Common::String &filename, uint8 *destBuffer) { + debugC(1, kDebugUtils, "readFileToBuffer %s", filename.c_str()); + Common::File f; + if (!f.open(filename)) + error("Unable to find file %s", filename.c_str()); + + int size = f.size(); + + return f.read(destBuffer, size); +} + +void EfhEngine::readAnimInfo() { + debugC(6, kDebugEngine, "readAnimInfo"); + + Common::String fileName = "animinfo"; + uint8 animInfoBuf[9000]; + memset(animInfoBuf, 0, 9000); + uint8 *curPtr = animInfoBuf; + + readFileToBuffer(fileName, animInfoBuf); + for (int i = 0; i < 100; ++i) { + for (int id = 0; id < 15; ++id) { + _animInfo[i]._unkAnimArray[id]._field[0] = *curPtr++; + _animInfo[i]._unkAnimArray[id]._field[1] = *curPtr++; + _animInfo[i]._unkAnimArray[id]._field[2] = *curPtr++; + _animInfo[i]._unkAnimArray[id]._field[3] = *curPtr++; + + debugC(6, kDebugEngine, "%d %d %d %d", _animInfo[i]._unkAnimArray[id]._field[0], _animInfo[i]._unkAnimArray[id]._field[1], _animInfo[i]._unkAnimArray[id]._field[2], _animInfo[i]._unkAnimArray[id]._field[3]); + } + + Common::String debugStr = ""; + for (int id = 0; id < 10; ++id) { + _animInfo[i]._field3C_startY[id] = *curPtr++; + debugStr += Common::String::format("%d ", _animInfo[i]._field3C_startY[id]); + } + debugC(6, kDebugEngine, "%s", debugStr.c_str()); + + debugStr = ""; + for (int id = 0; id < 10; ++id) { + _animInfo[i]._field46_startX[id] = READ_LE_INT16(curPtr); + curPtr += 2; + debugStr += Common::String::format("%d ", _animInfo[i]._field46_startX[id]); + } + debugC(6, kDebugEngine, "%s", debugStr.c_str()); + debugC(6, kDebugEngine, "---------"); + } +} + +void EfhEngine::findMapFile(int16 mapId) { + debugC(7, kDebugEngine, "findMapFile %d", mapId); + + if (!_word31E9E) + return; + + Common::String fileName = Common::String::format("map.%d", mapId); + Common::File f; + // The original was checking for the file and eventually asking to change floppies + if (!f.open(fileName)) + error("File not found: %s", fileName.c_str()); + + f.close(); +} + +void EfhEngine::rImageFile(Common::String filename, uint8 *targetBuffer, uint8 **subFilesArray, uint8 *packedBuffer) { + debugC(1, kDebugUtils, "rImageFile %s", filename.c_str()); + readFileToBuffer(filename, packedBuffer); + uint32 size = uncompressBuffer(packedBuffer, targetBuffer); + +#ifdef debug + // dump a decompressed image file + Common::DumpFile dump; + dump.open(filename + ".dump"); + dump.write(targetBuffer, size); + dump.flush(); + dump.close(); + // End of dump +#endif + + // TODO: Refactoring: once uncompressed, the container contains for each image its width, its height, and raw data (4 Bpp) + // => Write a class to handle that more properly + uint8 *ptr = targetBuffer; + uint16 counter = 0; + while (READ_LE_INT16(ptr) != 0) { + subFilesArray[counter] = ptr; + ++counter; + int16 imageWidth = READ_LE_INT16(ptr); + ptr += 2; + int16 imageHeight = READ_LE_INT16(ptr); + ptr += 2; + ptr += (imageWidth * imageHeight); + } +} + +void EfhEngine::readImpFile(int16 id, bool techMapFl) { + debug("readImpFile %d %s", id, techMapFl ? "True" : "False"); + + Common::String fileName = Common::String::format("imp.%d", id); + + if (techMapFl) + readFileToBuffer(fileName, _imp1); + else + readFileToBuffer(fileName, _imp2); + + decryptImpFile(techMapFl); +} + +void EfhEngine::readItems() { + debugC(7, kDebugEngine, "readItems"); + + Common::String fileName = "items"; + uint8 itemBuff[8100]; + readFileToBuffer(fileName, itemBuff); + uint8 *curPtr = itemBuff; + + for (int i = 0; i < 300; ++i) { + for (int16 idx = 0; idx < 15; ++idx) + _items[i]._name[idx] = *curPtr++; + + _items[i]._damage = *curPtr++; + _items[i]._defense = *curPtr++; + _items[i]._attacks = *curPtr++; + _items[i]._uses = *curPtr++; + _items[i].field_13 = *curPtr++; + _items[i]._range = *curPtr++; + _items[i]._attackType = *curPtr++; + _items[i].field_16 = *curPtr++; + _items[i].field17_attackTypeDefense = *curPtr++; + _items[i].field_18 = *curPtr++; + _items[i].field_19 = *curPtr++; + _items[i].field_1A = *curPtr++; + + debugC(7, kDebugEngine, "%s\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x", _items[i]._name, _items[i]._damage, _items[i]._defense, _items[i]._attacks, _items[i]._uses, _items[i].field_13, _items[i]._range, _items[i]._attackType, _items[i].field_16, _items[i].field17_attackTypeDefense, _items[i].field_18, _items[i].field_19, _items[i].field_1A); + } +} + +void EfhEngine::loadNewPortrait() { + debugC(7, kDebugEngine, "loadNewPortrait"); + + static int16 const unkConstRelatedToAnimImageSetId[19] = {0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2}; + _unkRelatedToAnimImageSetId = unkConstRelatedToAnimImageSetId[_techId]; + + if (_currentAnimImageSetId == 200 + _unkRelatedToAnimImageSetId) + return; + + findMapFile(_techId); + _currentAnimImageSetId = 200 + _unkRelatedToAnimImageSetId; + int imageSetId = _unkRelatedToAnimImageSetId + 13; + loadImageSet(imageSetId, _portraitBuf, _portraitSubFilesArray, _hiResImageBuf); +} + +void EfhEngine::loadAnimImageSet() { + debug("loadAnimImageSet"); + + if (_currentAnimImageSetId == _animImageSetId || _animImageSetId == 0xFF) + return; + + findMapFile(_techId); + + _unkAnimRelatedIndex = 0; + _currentAnimImageSetId = _animImageSetId; + + int16 animSetId = _animImageSetId + 17; + loadImageSet(animSetId, _portraitBuf, _portraitSubFilesArray, _hiResImageBuf); +} + +void EfhEngine::loadHistory() { + debug("loadHistory"); + + Common::String fileName = "history"; + readFileToBuffer(fileName, _history); +} + +void EfhEngine::loadTechMapImp(int16 fileId) { + debug("loadTechMapImp %d", fileId); + + if (fileId == 0xFF) + return; + + _techId = fileId; + findMapFile(_techId); + + // The original was loading the specific tech.%d and map.%d files. + // This is gone in our implementation as we pre-load all the files to save them inside the savegames + + // This is not present in the original. + // The purpose is to properly load the misc map data in arrays in order to use them without being a pain afterwards + loadMapArrays(_techId); + + loadImageSetToTileBank(1, _mapBitmapRefArr[_techId][0] + 1); + loadImageSetToTileBank(2, _mapBitmapRefArr[_techId][1] + 1); + + initMapMonsters(); + readImpFile(_techId, true); + displayAnimFrames(0xFE, false); +} + +void EfhEngine::loadPlacesFile(uint16 fullPlaceId, bool forceReloadFl) { + debug("loadPlacesFile %d %s", fullPlaceId, forceReloadFl ? "True" : "False"); + + if (fullPlaceId == 0xFF) + return; + + findMapFile(_techId); + _fullPlaceId = fullPlaceId; + uint16 minPlace = _lastMainPlaceId * 20; + uint16 maxPlace = minPlace + 19; + + if (_fullPlaceId < minPlace || _fullPlaceId > maxPlace || forceReloadFl) { + _lastMainPlaceId = _fullPlaceId / 20; + Common::String fileName = Common::String::format("places.%d", _lastMainPlaceId); + readFileToBuffer(fileName, _hiResImageBuf); + uncompressBuffer(_hiResImageBuf, _places); + } + copyCurrentPlaceToBuffer(_fullPlaceId % 20); +} + +void EfhEngine::readTileFact() { + debugC(7, kDebugEngine, "readTileFact"); + + Common::String fileName = "tilefact"; + uint8 tileFactBuff[864]; + readFileToBuffer(fileName, tileFactBuff); + uint8 *curPtr = tileFactBuff; + for (int i = 0; i < 432; ++i) { + _tileFact[i]._field0 = *curPtr++; + _tileFact[i]._field1 = *curPtr++; + } +} + +void EfhEngine::loadNPCS() { + debugC(7, kDebugEngine, "loadNPCS"); + + Common::String fileName = "npcs"; + uint8 npcLoading[13400]; + readFileToBuffer(fileName, npcLoading); + uint8 *curPtr = npcLoading; + + for (int i = 0; i < 99; ++i) { + for (int idx = 0; idx < 11; ++idx) + _npcBuf[i]._name[idx] = *curPtr++; + _npcBuf[i].field_B = *curPtr++; + _npcBuf[i].field_C = *curPtr++; + _npcBuf[i].field_D = *curPtr++; + _npcBuf[i].field_E = *curPtr++; + _npcBuf[i].field_F = *curPtr++; + _npcBuf[i].field_10 = *curPtr++; + _npcBuf[i].field_11 = *curPtr++; + _npcBuf[i].field_12 = READ_LE_INT16(curPtr); + _npcBuf[i].field_14 = READ_LE_INT16(curPtr + 2); + curPtr += 4; + _npcBuf[i]._xp = READ_LE_INT32(curPtr); + curPtr += 4; + for (int idx = 0; idx < 15; ++idx) { + _npcBuf[i]._activeScore[idx] = *curPtr++; + } + for (int idx = 0; idx < 11; ++idx) { + _npcBuf[i]._passiveScore[idx] = *curPtr++; + } + for (int idx = 0; idx < 11; ++idx) { + _npcBuf[i]._infoScore[idx] = *curPtr++; + } + _npcBuf[i].field_3F = *curPtr++; + _npcBuf[i].field_40 = *curPtr++; + for (int idx = 0; idx < 10; ++idx) { + _npcBuf[i]._inventory[idx]._ref = READ_LE_INT16(curPtr); + curPtr += 2; + _npcBuf[i]._inventory[idx]._stat1 = *curPtr++; + _npcBuf[i]._inventory[idx]._stat2 = *curPtr++; + } + _npcBuf[i]._possessivePronounSHL6 = *curPtr++; + _npcBuf[i]._speed = *curPtr++; + _npcBuf[i].field_6B = *curPtr++; + _npcBuf[i].field_6C = *curPtr++; + _npcBuf[i].field_6D = *curPtr++; + _npcBuf[i]._unkItemId = *curPtr++; + _npcBuf[i].field_6F = *curPtr++; + _npcBuf[i].field_70 = *curPtr++; + _npcBuf[i].field_71 = *curPtr++; + _npcBuf[i].field_72 = *curPtr++; + _npcBuf[i].field_73 = *curPtr++; + _npcBuf[i]._hitPoints = READ_LE_INT16(curPtr); + _npcBuf[i]._maxHP = READ_LE_INT16(curPtr + 2); + curPtr += 4; + _npcBuf[i].field_78 = *curPtr++; + _npcBuf[i].field_79 = READ_LE_INT16(curPtr); + _npcBuf[i].field_7B = READ_LE_INT16(curPtr + 2); + curPtr += 4; + _npcBuf[i].field_7D = *curPtr++; + _npcBuf[i].field_7E = *curPtr++; + _npcBuf[i].field_7F = *curPtr++; + _npcBuf[i].field_80 = *curPtr++; + _npcBuf[i].field_81 = *curPtr++; + _npcBuf[i].field_82 = *curPtr++; + _npcBuf[i].field_83 = *curPtr++; + _npcBuf[i].field_84 = *curPtr++; + _npcBuf[i].field_85 = *curPtr++; + } +} + +/** + * Pre-Loads MAP and TECH files. + * This is required in order to implement a clean savegame feature + */ +void EfhEngine::preLoadMaps() { + for (int i = 0; i < 19; ++i) { + Common::String fileName = Common::String::format("tech.%d", i); + readFileToBuffer(fileName, _hiResImageBuf); + uncompressBuffer(_hiResImageBuf, _techDataArr[i]); + + fileName = Common::String::format("map.%d", i); + readFileToBuffer(fileName, _hiResImageBuf); + uncompressBuffer(_hiResImageBuf, _mapArr[i]); + + _mapBitmapRefArr[i] = &_mapArr[i][0]; + } +} + +} // End of namespace Efh + diff --git a/engines/efh/metaengine.cpp b/engines/efh/metaengine.cpp index 8276fe4012da..cb6cf14a08be 100644 --- a/engines/efh/metaengine.cpp +++ b/engines/efh/metaengine.cpp @@ -177,6 +177,10 @@ void EfhMetaEngine::removeSaveState(const char *target, int slot) const { g_system->getSavefileManager()->removeSavefile(fileName); } +void EfhEngine::initGame(const ADGameDescription *gd) { + _platform = gd->platform; +} + } // End of namespace Efh #if PLUGIN_ENABLED_DYNAMIC(EFH) @@ -184,11 +188,3 @@ void EfhMetaEngine::removeSaveState(const char *target, int slot) const { #else REGISTER_PLUGIN_STATIC(EFH, PLUGIN_TYPE_ENGINE, Efh::EfhMetaEngine); #endif - -namespace Efh { - -void EfhEngine::initGame(const ADGameDescription *gd) { - _platform = gd->platform; -} - -} // End of namespace Efh diff --git a/engines/efh/module.mk b/engines/efh/module.mk index 158d389f1c3b..aee8803c5258 100644 --- a/engines/efh/module.mk +++ b/engines/efh/module.mk @@ -3,7 +3,9 @@ MODULE := engines/efh MODULE_OBJS = \ constants.o \ efh.o \ + files.o \ graphics.o \ + savegames.o \ utils.o \ metaengine.o diff --git a/engines/efh/savegames.cpp b/engines/efh/savegames.cpp new file mode 100644 index 000000000000..6401564e1034 --- /dev/null +++ b/engines/efh/savegames.cpp @@ -0,0 +1,225 @@ +/* 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/savefile.h" +#include "graphics/scaler.h" +#include "graphics/thumbnail.h" +#include "common/system.h" +#include "graphics/palette.h" + +#include "efh/efh.h" + +namespace Efh { + +Common::String EfhEngine::getSavegameFilename(int slot) { + return _targetName + Common::String::format("-%03d.SAV", slot); +} + +bool EfhEngine::canLoadGameStateCurrently() { + return true; +} + +bool EfhEngine::canSaveGameStateCurrently() { + return true; +} + +Common::Error EfhEngine::loadGameState(int slot) { + Common::InSaveFile *saveFile = g_system->getSavefileManager()->openForLoading(getSaveStateName(slot)); + if (!saveFile) + return Common::kReadingFailed; + + uint32 signature = saveFile->readUint32LE(); + byte version = saveFile->readByte(); + + if (signature != EFH_SAVE_HEADER || version > kSavegameVersion) + error("Invalid savegame"); + + // Skip savegame name + uint16 size = saveFile->readUint16LE(); + saveFile->skip(size); + + // Skip the thumbnail + Graphics::Surface *thumbnail; + Graphics::loadThumbnail(*saveFile, thumbnail); + delete (thumbnail); + + // Skip the savegame date + saveFile->skip(10); // year, month, day, hours, minutes (all int16) + + Common::Serializer s(saveFile, nullptr); + synchronize(s); + + delete saveFile; + + _oldMapPosX = _mapPosX; + _oldMapPosY = _mapPosY; + _unkRelatedToAnimImageSetId = 0; + + loadTechMapImp(_techId); + _lastMainPlaceId = 0xFFFF; + loadPlacesFile(_fullPlaceId, true); + + return Common::kNoError; +} + +Common::Error EfhEngine::saveGameState(int slot, const Common::String &desc, bool isAutosave) { + Common::OutSaveFile *out = _system->getSavefileManager()->openForSaving(getSaveStateName(slot)); + if (!out) + return Common::kCreatingFileFailed; + + out->writeUint32LE(EFH_SAVE_HEADER); + out->writeByte(kSavegameVersion); + + // Write savegame name + uint16 size = desc.size(); + out->writeUint16LE(size); + for (int i = 0; i < size; ++i) + out->writeByte(desc.c_str()[i]); + + // Get the active palette + uint8 thumbPalette[16 * 3]; + _system->getPaletteManager()->grabPalette(thumbPalette, 0, 16); + // Create a thumbnail and save it + Graphics::Surface *thumb = new Graphics::Surface(); + Graphics::Surface *sf = _mainSurface; + ::createThumbnail(thumb, (const byte *)sf->getPixels(), 320, 200, thumbPalette); + Graphics::saveThumbnail(*out, *thumb); + thumb->free(); + delete thumb; + + // Write out the save date/time + TimeDate td; + g_system->getTimeAndDate(td); + out->writeSint16LE(td.tm_year + 1900); + out->writeSint16LE(td.tm_mon + 1); + out->writeSint16LE(td.tm_mday); + out->writeSint16LE(td.tm_hour); + out->writeSint16LE(td.tm_min); + + Common::Serializer s(nullptr, out); + synchronize(s); + + out->finalize(); + delete out; + + return Common::kNoError; +} + +void EfhEngine::synchronize(Common::Serializer &s) { + s.syncAsSint16LE(_techId); + s.syncAsUint16LE(_fullPlaceId); + s.syncAsSint16LE(_guessAnimationAmount); + s.syncAsUint16LE(_largeMapFlag); + s.syncAsSint16LE(_teamCharId[0]); + s.syncAsSint16LE(_teamCharId[1]); + s.syncAsSint16LE(_teamCharId[2]); + + for (int i = 0; i < 3; ++i) { + s.syncAsSint16LE(_teamCharStatus[i]._status); + s.syncAsSint16LE(_teamCharStatus[i]._duration); + } + + s.syncAsSint16LE(_teamSize); + s.syncAsSint16LE(_unkArray2C8AA[0]); + s.syncAsSint16LE(_word2C872); + s.syncAsSint16LE(_imageSetSubFilesIdx); + s.syncAsSint16LE(_mapPosX); + s.syncAsSint16LE(_mapPosY); + s.syncAsSint16LE(_techDataId_MapPosX); + s.syncAsSint16LE(_techDataId_MapPosY); + + for (int i = 0; i < 19; ++i) { + int size = ARRAYSIZE(_techDataArr[i]); + for (int j = 0; j < size; ++j) + s.syncAsByte(_techDataArr[i][j]); + + size = ARRAYSIZE(_mapArr[i]); + for (int j = 0; j < size; ++j) + s.syncAsByte(_mapArr[i][j]); + + _mapBitmapRefArr[i] = &_mapArr[i][0]; + } + + // Dialog flags + for (int i = 0; i < 256; ++i) + s.syncAsByte(_history[i]); + + // NPCs + for (int i = 0; i < 99; ++i) { + for (int idx = 0; idx < 11; ++idx) + s.syncAsByte(_npcBuf[i]._name[idx]); + + s.syncAsByte(_npcBuf[i].field_B); + s.syncAsByte(_npcBuf[i].field_C); + s.syncAsByte(_npcBuf[i].field_D); + s.syncAsByte(_npcBuf[i].field_E); + s.syncAsByte(_npcBuf[i].field_F); + s.syncAsByte(_npcBuf[i].field_10); + s.syncAsByte(_npcBuf[i].field_11); + s.syncAsSint16LE(_npcBuf[i].field_12); + s.syncAsSint16LE(_npcBuf[i].field_14); + s.syncAsSint32LE(_npcBuf[i]._xp); + for (int idx = 0; idx < 15; ++idx) + s.syncAsByte(_npcBuf[i]._activeScore[idx]); + + for (int idx = 0; idx < 11; ++idx) + s.syncAsByte(_npcBuf[i]._passiveScore[idx]); + + for (int idx = 0; idx < 11; ++idx) + s.syncAsByte(_npcBuf[i]._infoScore[idx]); + + s.syncAsByte(_npcBuf[i].field_3F); + s.syncAsByte(_npcBuf[i].field_40); + for (int idx = 0; idx < 10; ++idx) { + s.syncAsSint16LE(_npcBuf[i]._inventory[idx]._ref); + s.syncAsByte(_npcBuf[i]._inventory[idx]._stat1); + s.syncAsByte(_npcBuf[i]._inventory[idx]._stat2); + } + s.syncAsByte(_npcBuf[i]._possessivePronounSHL6); + s.syncAsByte(_npcBuf[i]._speed); + s.syncAsByte(_npcBuf[i].field_6B); + s.syncAsByte(_npcBuf[i].field_6C); + s.syncAsByte(_npcBuf[i].field_6D); + s.syncAsByte(_npcBuf[i]._unkItemId); + s.syncAsByte(_npcBuf[i].field_6F); + s.syncAsByte(_npcBuf[i].field_70); + s.syncAsByte(_npcBuf[i].field_71); + s.syncAsByte(_npcBuf[i].field_72); + s.syncAsByte(_npcBuf[i].field_73); + s.syncAsSint16LE(_npcBuf[i]._hitPoints); + s.syncAsSint16LE(_npcBuf[i]._maxHP); + s.syncAsByte(_npcBuf[i].field_78); + s.syncAsSint16LE(_npcBuf[i].field_79); + s.syncAsSint16LE(_npcBuf[i].field_7B); + s.syncAsByte(_npcBuf[i].field_7D); + s.syncAsByte(_npcBuf[i].field_7E); + s.syncAsByte(_npcBuf[i].field_7F); + s.syncAsByte(_npcBuf[i].field_80); + s.syncAsByte(_npcBuf[i].field_81); + s.syncAsByte(_npcBuf[i].field_82); + s.syncAsByte(_npcBuf[i].field_83); + s.syncAsByte(_npcBuf[i].field_84); + s.syncAsByte(_npcBuf[i].field_85); + } +} + +} // End of namespace Efh + diff --git a/engines/efh/utils.cpp b/engines/efh/utils.cpp index a720686e3252..fb2b82a4b405 100644 --- a/engines/efh/utils.cpp +++ b/engines/efh/utils.cpp @@ -25,31 +25,6 @@ namespace Efh { -#if 0 -// Note : The original engine is using copyString(src, dest). It has been replaced either by a string assignment or a snprintf -void EfhEngine::copyString(char *srcStr, char *destStr) { - debugC(1, kDebugUtils, "copyString %s", srcStr); - char lastChar = 1; - int16 idx = 0; - - while (lastChar != 0) { - lastChar = destStr[idx] = srcStr[idx]; - ++idx; - } -} -#endif - -int32 EfhEngine::readFileToBuffer(Common::String &filename, uint8 *destBuffer) { - debugC(1, kDebugUtils, "readFileToBuffer %s", filename.c_str()); - Common::File f; - if (!f.open(filename)) - error("Unable to find file %s", filename.c_str()); - - int size = f.size(); - - return f.read(destBuffer, size); -} - void EfhEngine::setDefaultNoteDuration() { // Original implementation is based on the int1C, which is triggered at 18.2065Hz. // Every 4 times, it sets a flag (thus, approx every 220ms) @@ -85,7 +60,8 @@ void EfhEngine::decryptImpFile(bool techMapFl) { ++curPtr; } while (*curPtr != 0x60 && counter <= target); -// TODO: remove the dump part +#ifdef debug +// Dump the decompressed IMP file Common::DumpFile dump; if (!techMapFl) { dump.open("imp2_unc.dump"); @@ -96,6 +72,7 @@ void EfhEngine::decryptImpFile(bool techMapFl) { } dump.flush(); dump.close(); +#endif } void EfhEngine::loadImageSet(int16 imageSetId, uint8 *buffer, uint8 **subFilesArray, uint8 *destBuffer) { @@ -104,33 +81,6 @@ void EfhEngine::loadImageSet(int16 imageSetId, uint8 *buffer, uint8 **subFilesAr rImageFile(fileName, buffer, subFilesArray, destBuffer); } -void EfhEngine::rImageFile(Common::String filename, uint8 *targetBuffer, uint8 **subFilesArray, uint8 *packedBuffer) { - debugC(1, kDebugUtils, "rImageFile %s", filename.c_str()); - readFileToBuffer(filename, packedBuffer); - uint32 size = uncompressBuffer(packedBuffer, targetBuffer); - // TODO: Keep this dump for debug purposes only - Common::DumpFile dump; - dump.open(filename + ".dump"); - dump.write(targetBuffer, size); - dump.flush(); - dump.close(); - // End of dump - - // TODO: Refactoring: once uncompressed, the container contains for each image its width, its height, and raw data (4 Bpp) - // => Write a class to handle that more properly - uint8 *ptr = targetBuffer; - uint16 counter = 0; - while (READ_LE_INT16(ptr) != 0) { - subFilesArray[counter] = ptr; - ++counter; - int16 imageWidth = READ_LE_INT16(ptr); - ptr += 2; - int16 imageHeight = READ_LE_INT16(ptr); - ptr += 2; - ptr += (imageWidth * imageHeight); - } -} - uint32 EfhEngine::uncompressBuffer(uint8 *compressedBuf, uint8 *destBuf) { debugC(1, kDebugUtils, "uncompressBuffer"); if (compressedBuf == nullptr || destBuf == nullptr) From 22227d37e24405204dee7f40a04dfc282a0b8205 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Thu, 24 Nov 2022 14:04:38 +0100 Subject: [PATCH 174/412] EFH: take into account some more comments raised by sev during the first code review --- engines/efh/efh.cpp | 22 +++++----------------- engines/efh/efh.h | 14 +++++++------- engines/efh/files.cpp | 2 +- engines/efh/metaengine.cpp | 19 +++++++++++++++---- 4 files changed, 28 insertions(+), 29 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 01293e74dae5..f56906be20f4 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -205,7 +205,7 @@ EfhEngine::EfhEngine(OSystem *syst, const ADGameDescription *gd) : Engine(syst), _fontDescr._charHeight = 0; _fontDescr._extraHorizontalSpace = _fontDescr._extraVerticalSpace = 0; - _word31E9E = false; + _introDoneFl = false; _oldAnimImageSetId = -1; _animImageSetId = 0xFE; _paletteTransformationConstant = 10; @@ -356,22 +356,10 @@ EfhEngine::~EfhEngine() { delete _vgaGraphicsStruct2; } -bool EfhEngine::hasFeature(EngineFeature f) const { - return (f == kSupportsReturnToLauncher) || (f == kSupportsLoadingDuringRuntime) || (f == kSupportsSavingDuringRuntime); -} - -const char *EfhEngine::getCopyrightString() const { - return "Escape From Hell (C) Electronic Arts, 1990"; -} - -Common::Platform EfhEngine::getPlatform() const { - return _platform; -} - void EfhEngine::syncSoundSettings() { Engine::syncSoundSettings(); - // _sound->syncVolume(); + warning("TODO: _sound->syncVolume();"); } Common::Error EfhEngine::run() { @@ -583,7 +571,7 @@ Common::Error EfhEngine::run() { void EfhEngine::initialize() { _rnd = new Common::RandomSource("Hell"); - _rnd->setSeed(666); // Kick random number generator + _rnd->setSeed(g_system->getMillis()); // Kick random number generator _shouldQuit = false; } @@ -691,7 +679,7 @@ void EfhEngine::initEngine() { _fontDescr._charHeight = 8; _fontDescr._extraVerticalSpace = 3; _fontDescr._extraHorizontalSpace = 1; - _word31E9E = false; + _introDoneFl = false; // Pre-load stuff required for savegames preLoadMaps(); @@ -743,7 +731,7 @@ void EfhEngine::initEngine() { loadImageSet(6, _circleImageBuf, _circleImageSubFileArray, _hiResImageBuf); readImpFile(99, false); - _word31E9E = true; + _introDoneFl = true; restoreAnimImageSetId(); // Note: The original at this point saves int 24h and sets a new int24 to handle fatal failure diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 8d25d0dbb195..b4cdb33a08f1 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -246,18 +246,18 @@ class EfhEngine : public Engine { Common::RandomSource *_rnd; const ADGameDescription *_gameDescription; - uint32 getFeatures() const; - const char *getGameId() const; + void syncSoundSettings() override; + + // metaengine.cpp void initGame(const ADGameDescription *gd); + uint32 getFeatures() const; + const char *getGameId() const; Common::Platform getPlatform() const; - bool hasFeature(EngineFeature f) const override; const char *getCopyrightString() const; - void syncSoundSettings() override; - - // Savegames.cpp + // savegames.cpp Common::String getSavegameFilename(int slot); bool canLoadGameStateCurrently() override; bool canSaveGameStateCurrently() override; @@ -530,7 +530,7 @@ class EfhEngine : public Engine { uint8 _defaultBoxColor; FontDescr _fontDescr; - bool _word31E9E; + bool _introDoneFl; uint16 _textColor; int16 _oldAnimImageSetId; diff --git a/engines/efh/files.cpp b/engines/efh/files.cpp index 5c6a50d27e9d..90c166e75da8 100644 --- a/engines/efh/files.cpp +++ b/engines/efh/files.cpp @@ -74,7 +74,7 @@ void EfhEngine::readAnimInfo() { void EfhEngine::findMapFile(int16 mapId) { debugC(7, kDebugEngine, "findMapFile %d", mapId); - if (!_word31E9E) + if (!_introDoneFl) return; Common::String fileName = Common::String::format("map.%d", mapId); diff --git a/engines/efh/metaengine.cpp b/engines/efh/metaengine.cpp index cb6cf14a08be..122e2c4d649b 100644 --- a/engines/efh/metaengine.cpp +++ b/engines/efh/metaengine.cpp @@ -38,6 +38,21 @@ const char *EfhEngine::getGameId() const { return _gameDescription->gameId; } +void EfhEngine::initGame(const ADGameDescription *gd) { + _platform = gd->platform; +} + +bool EfhEngine::hasFeature(EngineFeature f) const { + return (f == kSupportsReturnToLauncher) || (f == kSupportsLoadingDuringRuntime) || (f == kSupportsSavingDuringRuntime); +} + +const char *EfhEngine::getCopyrightString() const { + return "Escape From Hell (C) Electronic Arts, 1990"; +} + +Common::Platform EfhEngine::getPlatform() const { + return _platform; +} } // End of namespace Efh namespace Efh { @@ -177,10 +192,6 @@ void EfhMetaEngine::removeSaveState(const char *target, int slot) const { g_system->getSavefileManager()->removeSavefile(fileName); } -void EfhEngine::initGame(const ADGameDescription *gd) { - _platform = gd->platform; -} - } // End of namespace Efh #if PLUGIN_ENABLED_DYNAMIC(EFH) From c833b8a55beb508cd5f1aab69a0d3f85e5a71f18 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Thu, 24 Nov 2022 23:46:56 +0100 Subject: [PATCH 175/412] EFH: Partial rewrite of file loading --- engines/efh/efh.cpp | 2 +- engines/efh/files.cpp | 166 ++++++++++++++++++++---------------------- 2 files changed, 81 insertions(+), 87 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index f56906be20f4..3ec7b22a06a6 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -6627,7 +6627,7 @@ void EfhEngine::loadEfhGame() { // The savegame is used to initialize the engine, so this part is reimplemented. // The check for existence is replaced by an error. - Common::String fileName = "savegame"; + Common::String fileName("savegame"); Common::File f; if (!f.open(fileName)) diff --git a/engines/efh/files.cpp b/engines/efh/files.cpp index 90c166e75da8..fc0090c0b071 100644 --- a/engines/efh/files.cpp +++ b/engines/efh/files.cpp @@ -38,32 +38,30 @@ void EfhEngine::readAnimInfo() { debugC(6, kDebugEngine, "readAnimInfo"); Common::String fileName = "animinfo"; - uint8 animInfoBuf[9000]; - memset(animInfoBuf, 0, 9000); - uint8 *curPtr = animInfoBuf; + Common::File f; + if (!f.open(fileName)) + error("Unable to find file %s", fileName.c_str()); - readFileToBuffer(fileName, animInfoBuf); for (int i = 0; i < 100; ++i) { for (int id = 0; id < 15; ++id) { - _animInfo[i]._unkAnimArray[id]._field[0] = *curPtr++; - _animInfo[i]._unkAnimArray[id]._field[1] = *curPtr++; - _animInfo[i]._unkAnimArray[id]._field[2] = *curPtr++; - _animInfo[i]._unkAnimArray[id]._field[3] = *curPtr++; + _animInfo[i]._unkAnimArray[id]._field[0] = f.readByte(); + _animInfo[i]._unkAnimArray[id]._field[1] = f.readByte(); + _animInfo[i]._unkAnimArray[id]._field[2] = f.readByte(); + _animInfo[i]._unkAnimArray[id]._field[3] = f.readByte(); debugC(6, kDebugEngine, "%d %d %d %d", _animInfo[i]._unkAnimArray[id]._field[0], _animInfo[i]._unkAnimArray[id]._field[1], _animInfo[i]._unkAnimArray[id]._field[2], _animInfo[i]._unkAnimArray[id]._field[3]); } Common::String debugStr = ""; for (int id = 0; id < 10; ++id) { - _animInfo[i]._field3C_startY[id] = *curPtr++; + _animInfo[i]._field3C_startY[id] = f.readByte(); debugStr += Common::String::format("%d ", _animInfo[i]._field3C_startY[id]); } debugC(6, kDebugEngine, "%s", debugStr.c_str()); debugStr = ""; for (int id = 0; id < 10; ++id) { - _animInfo[i]._field46_startX[id] = READ_LE_INT16(curPtr); - curPtr += 2; + _animInfo[i]._field46_startX[id] = f.readUint16LE(); debugStr += Common::String::format("%d ", _animInfo[i]._field46_startX[id]); } debugC(6, kDebugEngine, "%s", debugStr.c_str()); @@ -133,26 +131,26 @@ void EfhEngine::readItems() { debugC(7, kDebugEngine, "readItems"); Common::String fileName = "items"; - uint8 itemBuff[8100]; - readFileToBuffer(fileName, itemBuff); - uint8 *curPtr = itemBuff; + Common::File f; + if (!f.open(fileName)) + error("Unable to find file %s", fileName.c_str()); for (int i = 0; i < 300; ++i) { for (int16 idx = 0; idx < 15; ++idx) - _items[i]._name[idx] = *curPtr++; - - _items[i]._damage = *curPtr++; - _items[i]._defense = *curPtr++; - _items[i]._attacks = *curPtr++; - _items[i]._uses = *curPtr++; - _items[i].field_13 = *curPtr++; - _items[i]._range = *curPtr++; - _items[i]._attackType = *curPtr++; - _items[i].field_16 = *curPtr++; - _items[i].field17_attackTypeDefense = *curPtr++; - _items[i].field_18 = *curPtr++; - _items[i].field_19 = *curPtr++; - _items[i].field_1A = *curPtr++; + _items[i]._name[idx] = f.readByte(); + + _items[i]._damage = f.readByte(); + _items[i]._defense = f.readByte(); + _items[i]._attacks = f.readByte(); + _items[i]._uses = f.readByte(); + _items[i].field_13 = f.readByte(); + _items[i]._range = f.readByte(); + _items[i]._attackType = f.readByte(); + _items[i].field_16 = f.readByte(); + _items[i].field17_attackTypeDefense = f.readByte(); + _items[i].field_18 = f.readByte(); + _items[i].field_19 = f.readByte(); + _items[i].field_1A = f.readByte(); debugC(7, kDebugEngine, "%s\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x", _items[i]._name, _items[i]._damage, _items[i]._defense, _items[i]._attacks, _items[i]._uses, _items[i].field_13, _items[i]._range, _items[i]._attackType, _items[i].field_16, _items[i].field17_attackTypeDefense, _items[i].field_18, _items[i].field_19, _items[i].field_1A); } @@ -243,82 +241,78 @@ void EfhEngine::readTileFact() { debugC(7, kDebugEngine, "readTileFact"); Common::String fileName = "tilefact"; - uint8 tileFactBuff[864]; - readFileToBuffer(fileName, tileFactBuff); - uint8 *curPtr = tileFactBuff; + Common::File f; + if (!f.open(fileName)) + error("Unable to find file %s", fileName.c_str()); + for (int i = 0; i < 432; ++i) { - _tileFact[i]._field0 = *curPtr++; - _tileFact[i]._field1 = *curPtr++; + _tileFact[i]._field0 = f.readByte(); + _tileFact[i]._field1 = f.readByte(); } } void EfhEngine::loadNPCS() { debugC(7, kDebugEngine, "loadNPCS"); - Common::String fileName = "npcs"; - uint8 npcLoading[13400]; - readFileToBuffer(fileName, npcLoading); - uint8 *curPtr = npcLoading; + Common::String fileName("npcs"); + Common::File f; + if (!f.open(fileName)) + error("Unable to find file %s", fileName.c_str()); for (int i = 0; i < 99; ++i) { for (int idx = 0; idx < 11; ++idx) - _npcBuf[i]._name[idx] = *curPtr++; - _npcBuf[i].field_B = *curPtr++; - _npcBuf[i].field_C = *curPtr++; - _npcBuf[i].field_D = *curPtr++; - _npcBuf[i].field_E = *curPtr++; - _npcBuf[i].field_F = *curPtr++; - _npcBuf[i].field_10 = *curPtr++; - _npcBuf[i].field_11 = *curPtr++; - _npcBuf[i].field_12 = READ_LE_INT16(curPtr); - _npcBuf[i].field_14 = READ_LE_INT16(curPtr + 2); - curPtr += 4; - _npcBuf[i]._xp = READ_LE_INT32(curPtr); - curPtr += 4; + _npcBuf[i]._name[idx] = f.readByte(); + _npcBuf[i].field_B = f.readByte(); + _npcBuf[i].field_C = f.readByte(); + _npcBuf[i].field_D = f.readByte(); + _npcBuf[i].field_E = f.readByte(); + _npcBuf[i].field_F = f.readByte(); + _npcBuf[i].field_10 = f.readByte(); + _npcBuf[i].field_11 = f.readByte(); + _npcBuf[i].field_12 = f.readUint16LE(); + _npcBuf[i].field_14 = f.readUint16LE(); + _npcBuf[i]._xp = f.readUint32LE(); for (int idx = 0; idx < 15; ++idx) { - _npcBuf[i]._activeScore[idx] = *curPtr++; + _npcBuf[i]._activeScore[idx] = f.readByte(); } for (int idx = 0; idx < 11; ++idx) { - _npcBuf[i]._passiveScore[idx] = *curPtr++; + _npcBuf[i]._passiveScore[idx] = f.readByte(); } for (int idx = 0; idx < 11; ++idx) { - _npcBuf[i]._infoScore[idx] = *curPtr++; + _npcBuf[i]._infoScore[idx] = f.readByte(); } - _npcBuf[i].field_3F = *curPtr++; - _npcBuf[i].field_40 = *curPtr++; + _npcBuf[i].field_3F = f.readByte(); + _npcBuf[i].field_40 = f.readByte(); for (int idx = 0; idx < 10; ++idx) { - _npcBuf[i]._inventory[idx]._ref = READ_LE_INT16(curPtr); - curPtr += 2; - _npcBuf[i]._inventory[idx]._stat1 = *curPtr++; - _npcBuf[i]._inventory[idx]._stat2 = *curPtr++; + _npcBuf[i]._inventory[idx]._ref = f.readSint16LE(); + _npcBuf[i]._inventory[idx]._stat1 = f.readByte(); + _npcBuf[i]._inventory[idx]._stat2 = f.readByte(); } - _npcBuf[i]._possessivePronounSHL6 = *curPtr++; - _npcBuf[i]._speed = *curPtr++; - _npcBuf[i].field_6B = *curPtr++; - _npcBuf[i].field_6C = *curPtr++; - _npcBuf[i].field_6D = *curPtr++; - _npcBuf[i]._unkItemId = *curPtr++; - _npcBuf[i].field_6F = *curPtr++; - _npcBuf[i].field_70 = *curPtr++; - _npcBuf[i].field_71 = *curPtr++; - _npcBuf[i].field_72 = *curPtr++; - _npcBuf[i].field_73 = *curPtr++; - _npcBuf[i]._hitPoints = READ_LE_INT16(curPtr); - _npcBuf[i]._maxHP = READ_LE_INT16(curPtr + 2); - curPtr += 4; - _npcBuf[i].field_78 = *curPtr++; - _npcBuf[i].field_79 = READ_LE_INT16(curPtr); - _npcBuf[i].field_7B = READ_LE_INT16(curPtr + 2); - curPtr += 4; - _npcBuf[i].field_7D = *curPtr++; - _npcBuf[i].field_7E = *curPtr++; - _npcBuf[i].field_7F = *curPtr++; - _npcBuf[i].field_80 = *curPtr++; - _npcBuf[i].field_81 = *curPtr++; - _npcBuf[i].field_82 = *curPtr++; - _npcBuf[i].field_83 = *curPtr++; - _npcBuf[i].field_84 = *curPtr++; - _npcBuf[i].field_85 = *curPtr++; + _npcBuf[i]._possessivePronounSHL6 = f.readByte(); + _npcBuf[i]._speed = f.readByte(); + _npcBuf[i].field_6B = f.readByte(); + _npcBuf[i].field_6C = f.readByte(); + _npcBuf[i].field_6D = f.readByte(); + _npcBuf[i]._unkItemId = f.readByte(); + _npcBuf[i].field_6F = f.readByte(); + _npcBuf[i].field_70 = f.readByte(); + _npcBuf[i].field_71 = f.readByte(); + _npcBuf[i].field_72 = f.readByte(); + _npcBuf[i].field_73 = f.readByte(); + _npcBuf[i]._hitPoints = f.readSint16LE(); + _npcBuf[i]._maxHP = f.readSint16LE(); + _npcBuf[i].field_78 = f.readByte(); + _npcBuf[i].field_79 = f.readUint16LE(); + _npcBuf[i].field_7B = f.readUint16LE(); + _npcBuf[i].field_7D = f.readByte(); + _npcBuf[i].field_7E = f.readByte(); + _npcBuf[i].field_7F = f.readByte(); + _npcBuf[i].field_80 = f.readByte(); + _npcBuf[i].field_81 = f.readByte(); + _npcBuf[i].field_82 = f.readByte(); + _npcBuf[i].field_83 = f.readByte(); + _npcBuf[i].field_84 = f.readByte(); + _npcBuf[i].field_85 = f.readByte(); } } From 4605be8169b29cb0b063152f26e6e9031a28c5d2 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sat, 26 Nov 2022 07:52:17 +0100 Subject: [PATCH 176/412] EFH: Change uint8 to uint in some loops --- engines/efh/efh.cpp | 8 ++++---- engines/efh/graphics.cpp | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 3ec7b22a06a6..45e26da8de8e 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -749,18 +749,18 @@ void EfhEngine::initEngine() { void EfhEngine::initMapMonsters() { debug("initMapMonsters"); - for (uint8 monsterId = 0; monsterId < 64; ++monsterId) { + for (uint monsterId = 0; monsterId < 64; ++monsterId) { if (_mapMonsters[monsterId]._guess_fullPlaceId == 0xFF) continue; - for (uint8 counter = 0; counter < 9; ++counter) + for (uint counter = 0; counter < 9; ++counter) _mapMonsters[monsterId]._pictureRef[counter] = 0; uint8 groupSize = _mapMonsters[monsterId]._groupSize; if (groupSize == 0) groupSize = getRandom(10); - for (uint8 counter = 0; counter < groupSize; ++counter) { + for (uint counter = 0; counter < groupSize; ++counter) { uint rand100 = getRandom(100); uint16 pictureRef = kEncounters[_mapMonsters[monsterId]._monsterRef]._pictureRef; @@ -1826,7 +1826,7 @@ void EfhEngine::drawText(uint8 *srcPtr, int16 posX, int16 posY, int16 maxX, int1 void EfhEngine::displayMiddleLeftTempText(uint8 *impArray, bool flag) { debugC(3, kDebugEngine, "displayMiddleLeftTempText %s %s", (char *)impArray, flag ? "True" : "False"); - for (uint8 counter = 0; counter < 2; ++counter) { + for (uint counter = 0; counter < 2; ++counter) { if (counter == 0 || flag) { // clear middle-left text area drawColoredRect(16, 115, 111, 133, 0); diff --git a/engines/efh/graphics.cpp b/engines/efh/graphics.cpp index d77759d84811..ac1ee0305dad 100644 --- a/engines/efh/graphics.cpp +++ b/engines/efh/graphics.cpp @@ -211,7 +211,7 @@ void EfhEngine::drawString(const char *str, int16 startX, int16 startY, uint16 t // int16 var6 = _fontDescr._extraLines[0] + startY - 1; // Used in case 0x8000 } - for (uint8 curChar = *curPtr++; curChar != 0; curChar = *curPtr++) { + for (uint curChar = *curPtr++; curChar != 0; curChar = *curPtr++) { if (curChar == 0x0A) { startX = minX; startY += lineHeight; From 1f7fe868ad666964a2a727342b9c99d569eeacdc Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sat, 26 Nov 2022 07:55:43 +0100 Subject: [PATCH 177/412] EFH: Fix missing space in while statements --- engines/efh/efh.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 45e26da8de8e..fc25b9f6f9cf 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -387,7 +387,7 @@ Common::Error EfhEngine::run() { return Common::kNoError; uint32 lastMs = _system->getMillis(); - while(!_shouldQuit) { + while (!_shouldQuit) { _system->delayMillis(20); uint32 newMs = _system->getMillis(); @@ -1235,7 +1235,7 @@ void EfhEngine::handleWinSequence() { Common::KeyCode input = Common::KEYCODE_INVALID; - while(input != Common::KEYCODE_ESCAPE) { + while (input != Common::KEYCODE_ESCAPE) { displayRawDataAtPos(winSeqSubFilesArray1[0], 0, 0); displayFctFullScreen(); displayRawDataAtPos(winSeqSubFilesArray1[0], 0, 0); From 8f115830aa384ba874044d3d6ef8ac6c1be7286d Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sat, 26 Nov 2022 08:26:28 +0100 Subject: [PATCH 178/412] EFH: remove the use of int16 in most loops, fix a compilation warning --- engines/efh/efh.cpp | 244 +++++++++++++++++++-------------------- engines/efh/files.cpp | 8 +- engines/efh/graphics.cpp | 2 +- 3 files changed, 128 insertions(+), 126 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index fc25b9f6f9cf..720a5ccc992d 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -84,7 +84,7 @@ void AnimInfo::init() { } void ItemStruct::init() { - for (int16 idx = 0; idx < 15; ++idx) + for (uint idx = 0; idx < 15; ++idx) _name[idx] = 0; _damage = 0; @@ -465,7 +465,7 @@ Common::Error EfhEngine::run() { } break; case Common::KEYCODE_F5: { // Original is using CTRL-S - for (int16 counter = 0; counter < 2; ++counter) { + for (uint counter = 0; counter < 2; ++counter) { clearBottomTextZone(0); displayCenteredString("Are You Sure You Want To Save?", 24, 296, 160); if (counter == 0) @@ -488,7 +488,7 @@ Common::Error EfhEngine::run() { } break; case Common::KEYCODE_F7: { // Original is using CTRL-L - for (int16 counter = 0; counter < 2; ++counter) { + for (uint counter = 0; counter < 2; ++counter) { clearBottomTextZone(0); displayCenteredString("Are You Sure You Want To Load?", 24, 296, 160); if (counter == 0) @@ -878,13 +878,13 @@ uint16 EfhEngine::sub1C80A(int16 charId, int16 field18, bool flag) { void EfhEngine::drawGameScreenAndTempText(bool flag) { debugC(2, kDebugEngine, "drawGameScreenAndTempText %s", flag ? "True" : "False"); - #if 0 +#if 0 // This code is present in the original, but looks strictly useless. uint8 mapTileInfo = getMapTileInfo(_mapPosX, _mapPosY); int16 imageSetId = _currentTileBankImageSetId[mapTileInfo / 72]; int16 mapImageSetId = (imageSetId * 72) + (mapTileInfo % 72); - #endif +#endif for (int counter = 0; counter < 2; ++counter) { if (counter == 0 || flag) { @@ -961,7 +961,7 @@ void EfhEngine::drawMap(bool largeMapFl, int16 mapPosX, int16 mapPosY, int16 map } if (drawMonstersFl) { - for (int16 var16 = 0; var16 < 64; ++var16) { + for (uint var16 = 0; var16 < 64; ++var16) { if ((_largeMapFlag && _mapMonsters[var16]._guess_fullPlaceId == 0xFE) || (!_largeMapFlag && _mapMonsters[var16]._guess_fullPlaceId == _fullPlaceId)){ bool var4 = false; int16 posX = _mapMonsters[var16]._posX; @@ -970,7 +970,7 @@ void EfhEngine::drawMap(bool largeMapFl, int16 mapPosX, int16 mapPosY, int16 map if (posX < minX || posX > maxX || posY < minY || posY > maxY) continue; - for (int16 counterY = 0; counterY < 9 && !var4; ++counterY) { + for (uint counterY = 0; counterY < 9 && !var4; ++counterY) { if (_mapMonsters[var16]._pictureRef[counterY] > 0) var4 = true; } @@ -1010,7 +1010,7 @@ void EfhEngine::displayLargeMap(int16 posX, int16 posY) { void EfhEngine::drawScreen() { debugC(2, kDebugEngine, "drawScreen"); - for (int16 counter = 0; counter < 2; ++counter) { + for (uint counter = 0; counter < 2; ++counter) { _redrawNeededFl = false; if (!_largeMapFlag) { if (_fullPlaceId != 0xFF) @@ -1035,12 +1035,12 @@ void EfhEngine::drawScreen() { void EfhEngine::displayLowStatusScreen(bool flag) { debugC(6, kDebugEngine, "displayLowStatusScreen %s", flag ? "True" : "False"); - static char strName[5] = "Name"; - static char strDef[4] = "DEF"; - static char strHp[3] = "HP"; - static char strMaxHp[7] = "Max HP"; - static char strWeapon[7] = "Weapon"; - static char strDead[9] = "* DEAD *"; + const char strName[5] = "Name"; + const char strDef[4] = "DEF"; + const char strHp[3] = "HP"; + const char strMaxHp[7] = "Max HP"; + const char strWeapon[7] = "Weapon"; + const char strDead[9] = "* DEAD *"; for (int counter = 0; counter < 2; ++counter) { if (counter == 0 || flag) { @@ -1106,7 +1106,7 @@ uint8 *EfhEngine::script_readNumberArray(uint8 *srcBuffer, int16 destArraySize, debug("script_readNumberArray"); uint8 *buffer = srcBuffer; - for (int16 i = 0; i < destArraySize; ++i) { + for (int i = 0; i < destArraySize; ++i) { buffer++; buffer = script_getNumber(buffer, &destArray[i]); } @@ -1140,7 +1140,7 @@ void EfhEngine::removeObject(int16 charId, int16 objectId) { void EfhEngine::totalPartyKill() { debug("totalPartyKill"); - for (int16 counter = 0; counter < 3; ++counter) { + for (uint counter = 0; counter < 3; ++counter) { if (_teamCharId[counter] != -1) _npcBuf[counter]._hitPoints = 0; } @@ -1159,7 +1159,7 @@ void EfhEngine::removeCharacterFromTeam(int16 teamMemberId) { _teamCharStatus[teamMemberId]._status = 0; _teamCharStatus[teamMemberId]._duration = 0; - for (int16 var4 = teamMemberId; var4 < 2; ++var4) { + for (int var4 = teamMemberId; var4 < 2; ++var4) { _teamCharId[var4] = _teamCharId[var4 + 1]; _teamCharId[var4 + 1] = -1; } @@ -1171,7 +1171,7 @@ void EfhEngine::refreshTeamSize() { debug("refreshTeamSize"); _teamSize = 0; - for (int16 counter = 0; counter < 3; ++counter) { + for (uint counter = 0; counter < 3; ++counter) { if (_teamCharId[counter] != -1) ++_teamSize; } @@ -1180,7 +1180,7 @@ void EfhEngine::refreshTeamSize() { bool EfhEngine::isCharacterATeamMember(int16 id) { debug("isCharacterATeamMember %d", id); - for (int16 counter = 0; counter < _teamSize; ++counter) { + for (int counter = 0; counter < _teamSize; ++counter) { if (_teamCharId[counter] == id) return true; } @@ -1192,7 +1192,7 @@ bool EfhEngine::isTPK() { debug("isTPK"); int16 zeroedChar = 0; - for (int16 counter = 0; counter < _teamSize; ++counter) { + for (int counter = 0; counter < _teamSize; ++counter) { if (_npcBuf[_teamCharId[counter]]._hitPoints <= 0) ++zeroedChar; } @@ -1215,7 +1215,7 @@ void EfhEngine::handleWinSequence() { loadImageSet(64, winSeqBuf3, winSeqSubFilesArray1, decompBuffer); loadImageSet(65, winSeqBuf4, winSeqSubFilesArray2, decompBuffer); - for (int16 counter = 0; counter < 2; ++counter) { + for (uint counter = 0; counter < 2; ++counter) { displayRawDataAtPos(winSeqSubFilesArray1[0], 0, 0); displayRawDataAtPos(winSeqSubFilesArray2[0], 136, 48); if (counter == 0) @@ -1223,8 +1223,8 @@ void EfhEngine::handleWinSequence() { } getInput(12); - for (int16 animId = 1; animId < 8; ++animId) { - for (int16 counter = 0; counter < 2; ++counter) { + for (uint animId = 1; animId < 8; ++animId) { + for (uint counter = 0; counter < 2; ++counter) { displayRawDataAtPos(winSeqSubFilesArray1[0], 0, 0); displayRawDataAtPos(winSeqSubFilesArray2[animId], 136, 48); if (counter == 0) @@ -1284,7 +1284,7 @@ void EfhEngine::handleWinSequence() { bool EfhEngine::giveItemTo(int16 charId, int16 objectId, int16 altCharId) { debug("giveItemTo %d %d %d", charId, objectId, altCharId); - for (int16 newObjectId = 0; newObjectId < 10; ++newObjectId) { + for (uint newObjectId = 0; newObjectId < 10; ++newObjectId) { if (_npcBuf[charId]._inventory[newObjectId]._ref != 0x7FFF) continue; @@ -1325,13 +1325,13 @@ int16 EfhEngine::handleCharacterJoining() { debug("handleCharacterJoining"); static char strReplaceWho[13] = "Replace Who?"; - for (int16 counter = 0; counter < 3; ++counter) { + for (uint counter = 0; counter < 3; ++counter) { if (_teamCharId[counter] == -1) { return counter; } } - for (int16 counter = 0; counter < 2; ++counter) { + for (uint counter = 0; counter < 2; ++counter) { drawColoredRect(200, 112, 278, 132, 0); displayCenteredString(strReplaceWho, 200, 278, 117); if (counter == 0) @@ -1339,7 +1339,7 @@ int16 EfhEngine::handleCharacterJoining() { } int16 charId = chooseCharacterToReplace(); - for (int16 counter = 0; counter < 2; ++counter) { + for (uint counter = 0; counter < 2; ++counter) { drawColoredRect(200, 112, 278, 132, 0); if (counter == 0) displayFctFullScreen(); @@ -1554,8 +1554,8 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int16 posX, int16 posY, int16 if (flag) { int16 var110 = scriptNumberArray[0]; bool found = false; - for (int16 counter = 0; counter < _teamSize && !found; ++counter) { - for (int16 objectId = 0; objectId < 10; ++objectId) { + for (int counter = 0; counter < _teamSize && !found; ++counter) { + for (uint objectId = 0; objectId < 10; ++objectId) { if (_npcBuf[_teamCharId[counter]]._inventory[objectId]._ref == var110) { removeObject(_teamCharId[counter], objectId); found = true; @@ -1570,7 +1570,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int16 posX, int16 posY, int16 buffer = script_readNumberArray(buffer, 1, scriptNumberArray); if (flag) { int16 var110 = scriptNumberArray[0]; - for (int16 counter = 0; counter < _teamSize; ++counter) { + for (int counter = 0; counter < _teamSize; ++counter) { if (giveItemTo(_teamCharId[counter], var110, 0xFF)) break; } @@ -1581,8 +1581,8 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int16 posX, int16 posY, int16 if (flag) { int16 var110 = scriptNumberArray[0]; bool found = false; - for (int16 counter = 0; counter < _teamSize && !found; ++counter) { - for (int16 objectId = 0; objectId < 10; ++objectId) { + for (int counter = 0; counter < _teamSize && !found; ++counter) { + for (uint objectId = 0; objectId < 10; ++objectId) { if (_npcBuf[_teamCharId[counter]]._inventory[objectId]._ref == var110) { found = true; break; @@ -1659,7 +1659,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int16 posX, int16 posY, int16 int16 var110 = scriptNumberArray[0]; // TODO: This "if" is useless, it's doing just the same loop and if statement. Consider removing it. if (isCharacterATeamMember(var110)) { - for (int16 counter = 0; counter < 3; ++counter) { + for (uint counter = 0; counter < 3; ++counter) { if (_teamCharId[counter] == var110) { removeCharacterFromTeam(counter); break; @@ -1853,8 +1853,8 @@ void EfhEngine::sub15A28(int16 arg0, int16 arg2) { if (varC < 0) varC = 0; - for (int16 counter = 0; counter <= 23; counter += 2) { - for (int16 var8 = 0; var8 <= 23; ++var8) { + for (uint counter = 0; counter <= 23; counter += 2) { + for (uint var8 = 0; var8 <= 23; ++var8) { int16 var4 = counter + varE; int16 var2 = var8 + varC; _mapGameMap[var4][var2] = _curPlace[counter][var8]; @@ -1862,8 +1862,8 @@ void EfhEngine::sub15A28(int16 arg0, int16 arg2) { drawScreen(); } - for (int16 counter = 1; counter <= 23; counter += 2) { - for (int16 var8 = 0; var8 <= 23; ++var8) { + for (uint counter = 1; counter <= 23; counter += 2) { + for (uint var8 = 0; var8 <= 23; ++var8) { int16 var4 = counter + varE; int16 var2 = var8 + varC; _mapGameMap[var4][var2] = _curPlace[counter][var8]; @@ -1970,12 +1970,12 @@ int16 EfhEngine::sub151FD(int16 posX, int16 posY) { debug("sub151FD %d %d", posX, posY); if (_largeMapFlag) { - for (int16 counter = 0; counter < 100; ++counter) { + for (uint counter = 0; counter < 100; ++counter) { if (_mapUnknown[counter]._posX == posX && _mapUnknown[counter]._posY == posY && _mapUnknown[counter]._placeId == 0xFE) return counter; } } else { - for (int16 counter = 0; counter < 100; ++counter) { + for (uint counter = 0; counter < 100; ++counter) { if (_mapUnknown[counter]._posX == posX && _mapUnknown[counter]._posY == posY && _mapUnknown[counter]._placeId == _fullPlaceId) return counter; } @@ -2137,7 +2137,7 @@ void EfhEngine::handleNewRoundEffects() { if (!_word2C8D7) return; - for (int16 counter = 0; counter < _teamSize; ++counter) { + for (int counter = 0; counter < _teamSize; ++counter) { if (_teamCharStatus[counter]._status == 0) // normal continue; if (--_teamCharStatus[counter]._duration <= 0) { @@ -2149,7 +2149,7 @@ void EfhEngine::handleNewRoundEffects() { if (++regenCounter <= 8) return; - for (int16 counter = 0; counter < _teamSize; ++counter) { + for (int counter = 0; counter < _teamSize; ++counter) { if (++_npcBuf[_teamCharId[counter]]._hitPoints > _npcBuf[_teamCharId[counter]]._maxHP) _npcBuf[_teamCharId[counter]]._hitPoints = _npcBuf[_teamCharId[counter]]._maxHP; } @@ -2163,7 +2163,7 @@ bool EfhEngine::handleDeathMenu() { _imageSetSubFilesIdx = 213; drawScreen(); - for (int16 counter = 0; counter < 2; ++counter) { + for (uint counter = 0; counter < 2; ++counter) { clearBottomTextZone(0); displayCenteredString("Darkness Prevails...Death Has Taken You!", 24, 296, 153); setTextPos(100, 162); @@ -2296,7 +2296,7 @@ int8 EfhEngine::sub16B08(int16 monsterId) { if (_mapMonsters[monsterId]._posX == _mapPosX && _mapMonsters[monsterId]._posY == _mapPosY) return 0; - for (int16 counter = 0; counter < 64; ++counter) { + for (int counter = 0; counter < 64; ++counter) { if (counter == monsterId) continue; @@ -2481,7 +2481,7 @@ bool EfhEngine::checkTeamWeaponRange(int16 monsterId) { if (!_ongoingFightFl) return true; - for (int16 counter = 0; counter < 5; ++counter) { + for (uint counter = 0; counter < 5; ++counter) { if (_teamMonsterIdArray[counter] == monsterId && unkFct_checkMonsterField8(monsterId, false) && checkWeaponRange(monsterId, _mapMonsters[monsterId]._itemId_Weapon)) return false; } @@ -2523,7 +2523,7 @@ void EfhEngine::sub174A0() { int16 maxDisplayedMapX = CLIP(minDisplayedMapX + 20, 0, mapSize); int16 maxDisplayedMapY = CLIP(minDisplayedMapY + 17, 0, mapSize); - for (int16 monsterId = 0; monsterId < 64; ++monsterId) { + for (uint monsterId = 0; monsterId < 64; ++monsterId) { if (!checkPictureRefAvailability(monsterId)) continue; @@ -2692,7 +2692,7 @@ bool EfhEngine::checkPictureRefAvailability(int16 monsterId) { if (_mapMonsters[monsterId]._guess_fullPlaceId == 0xFF) return false; - for (int16 counter = 0; counter < 9; ++counter) { + for (uint counter = 0; counter < 9; ++counter) { if (_mapMonsters[monsterId]._pictureRef[counter] > 0) return true; } @@ -2718,7 +2718,7 @@ int16 EfhEngine::countPictureRef(int16 id, bool teamMemberFl) { else monsterId = id; - for (int16 counter = 0; counter < 9; ++counter) { + for (uint counter = 0; counter < 9; ++counter) { if (_mapMonsters[monsterId]._pictureRef[counter] > 0) ++count; } @@ -2802,8 +2802,8 @@ bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { } break; case 4: - for (int16 counter = 0; counter < _teamSize; ++counter) { - for (int16 charId = 0; charId < 10; ++charId) { + for (int counter = 0; counter < _teamSize; ++counter) { + for (uint charId = 0; charId < 10; ++charId) { if (_npcBuf[_teamCharId[counter]]._inventory[charId]._ref == _npcBuf[var58].field_11) { removeObject(_teamCharId[counter], charId); displayMonsterAnim(monsterId); @@ -2823,8 +2823,8 @@ bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { } break; case 6: - for (int16 counter = 0; counter < _teamSize; ++counter) { - for (int16 charId = 0; charId < 10; ++charId) { + for (int counter = 0; counter < _teamSize; ++counter) { + for (uint charId = 0; charId < 10; ++charId) { if (_npcBuf[_teamCharId[counter]]._inventory[charId]._ref == _npcBuf[var58].field_11) { displayMonsterAnim(monsterId); sub22AA8(_npcBuf[var58].field_14); @@ -2835,7 +2835,7 @@ bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { } break; case 7: - for (int16 counter = 0; counter < _teamSize; ++counter) { + for (int counter = 0; counter < _teamSize; ++counter) { if (_npcBuf[var58].field_11 == _teamCharId[counter]) { removeCharacterFromTeam(counter); displayMonsterAnim(monsterId); @@ -2846,13 +2846,13 @@ bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { } break; case 8: - for (int16 counter = 0; counter < _teamSize; ++counter) { + for (int counter = 0; counter < _teamSize; ++counter) { if (_npcBuf[var58].field_11 == _teamCharId[counter]) { displayMonsterAnim(monsterId); _enemyNamePt2 = _npcBuf[var58]._name; _characterNamePt2 = _npcBuf[_teamCharId[counter]]._name; snprintf(buffer, 80, "%s asks that %s leave your party.", _enemyNamePt2.c_str(), _characterNamePt2.c_str()); - for (int16 i = 0; i < 2; ++i) { + for (uint i = 0; i < 2; ++i) { clearBottomTextZone(0); _textColor = 0xE; displayCenteredString(buffer, 24, 296, 161); @@ -2873,7 +2873,7 @@ bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { } break; case 9: - for (int16 counter = 0; counter < _teamSize; ++counter) { + for (int counter = 0; counter < _teamSize; ++counter) { if (_npcBuf[var58].field_11 == _teamCharId[counter]) { displayMonsterAnim(monsterId); sub22AA8(_npcBuf[var58].field_14); @@ -2984,7 +2984,7 @@ void EfhEngine::sub22AA8(int16 arg0) { _word2C87A = false; } } else { - for (int16 counter = 0; counter < 2; ++counter) { + for (uint counter = 0; counter < 2; ++counter) { drawMapWindow(); if (counter == 0) displayFctFullScreen(); @@ -2995,7 +2995,7 @@ void EfhEngine::sub22AA8(int16 arg0) { var4 = var2; if (var4 != -1) { - for (int16 counter = 0; counter < 2; ++counter) { + for (uint counter = 0; counter < 2; ++counter) { if (varA) { displayCenteredString("[DONE]", 128, 303, 117); } else { @@ -3035,7 +3035,7 @@ bool EfhEngine::sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemI sub22AA8(_mapUnknown[var8]._field5); // word! return true; } else if (_mapUnknown[var8]._field3 == 0xFE) { - for (int16 counter = 0; counter < _teamSize; ++counter) { + for (int counter = 0; counter < _teamSize; ++counter) { if (_teamCharId[counter] == -1) continue; if (_teamCharId[counter] == _mapUnknown[var8]._field4) { @@ -3044,11 +3044,11 @@ bool EfhEngine::sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemI } } } else if (_mapUnknown[var8]._field3 == 0xFD) { - for (int16 counter = 0; counter < _teamSize; ++counter) { + for (int counter = 0; counter < _teamSize; ++counter) { if (_teamCharId[counter] == -1) continue; - for (int16 var2 = 0; var2 < 10; ++var2) { + for (uint var2 = 0; var2 < 10; ++var2) { if (_npcBuf[_teamCharId[counter]]._inventory[var2]._ref == _mapUnknown[var8]._field4) { sub22AA8(_mapUnknown[var8]._field5); return true; @@ -3062,7 +3062,7 @@ bool EfhEngine::sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemI if (_teamCharId[counter] == -1) continue; - for (int16 var2 = 0; var2 < 39; ++var2) { + for (uint var2 = 0; var2 < 39; ++var2) { if (_npcBuf[_teamCharId[counter]]._activeScore[var2] >= _mapUnknown[var8]._field4) { sub22AA8(_mapUnknown[var8]._field5); return true; @@ -3088,7 +3088,7 @@ bool EfhEngine::sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemI } } - for (int16 counter = 0; counter < 64; ++counter) { + for (uint counter = 0; counter < 64; ++counter) { if (!sub21820(counter, arg8, itemId)) return true; } @@ -3140,7 +3140,7 @@ int8 EfhEngine::sub15581(int16 mapPosX, int16 mapPosY, int16 arg4) { bool EfhEngine::sub1BC74(int16 monsterId, int16 teamMonsterId) { debug("sub1BC74 %d %d", monsterId, teamMonsterId); - for (int16 counter = 0; counter < teamMonsterId; ++counter) { + for (int counter = 0; counter < teamMonsterId; ++counter) { if (_teamMonsterIdArray[counter] == monsterId) return true; } @@ -3156,11 +3156,11 @@ void EfhEngine::sub1BCA7(int16 monsterTeamId) { _teamMonsterIdArray[0] = monsterTeamId; } - for (int16 counter2 = 1; counter2 <= 3; ++counter2) { + for (int counter2 = 1; counter2 <= 3; ++counter2) { if (counter >= 5) break; - for (int16 monsterId = 0; monsterId < 64; ++monsterId) { + for (uint monsterId = 0; monsterId < 64; ++monsterId) { if (_mapMonsters[monsterId]._guess_fullPlaceId == 0xFF) continue; @@ -3171,7 +3171,7 @@ void EfhEngine::sub1BCA7(int16 monsterTeamId) { continue; bool var6 = false; - for (int16 counter3 = 0; counter3 < 9; ++counter3) { + for (uint counter3 = 0; counter3 < 9; ++counter3) { if (_mapMonsters[monsterId]._pictureRef[counter3] > 0) { var6 = true; break; @@ -3191,14 +3191,14 @@ void EfhEngine::sub1BCA7(int16 monsterTeamId) { if (counter > 4) return; - for (int16 id = counter; id < 5; ++id) + for (uint id = counter; id < 5; ++id) _teamMonsterIdArray[id] = -1; } void EfhEngine::reset_stru32686() { debug("reset_stru32686"); - for (int16 counter1 = 0; counter1 < 5; ++counter1) { - for (int16 counter2 = 0; counter2 < 9; ++counter2) { + for (uint counter1 = 0; counter1 < 5; ++counter1) { + for (uint counter2 = 0; counter2 < 9; ++counter2) { _stru32686[counter1]._field0[counter2] = 0; _stru32686[counter1]._field2[counter2] = 0; } @@ -3231,7 +3231,7 @@ bool EfhEngine::isTeamMemberStatusNormal(int16 teamMemberId) { void EfhEngine::sub1CDFA() { debug("sub1CDFA"); // Initiatives - for (int16 counter = 0; counter < 3; ++counter) { + for (int counter = 0; counter < 3; ++counter) { if (_teamCharId[counter] != -1 && counter < _teamSize) { _stru3244C[counter]._field0 = counter + 1000; _stru3244C[counter]._field2 = _npcBuf[_teamCharId[counter]]._infoScore[3]; @@ -3241,7 +3241,7 @@ void EfhEngine::sub1CDFA() { } } - for (int16 counter = 0; counter < 5; ++counter) { + for (int counter = 0; counter < 5; ++counter) { if (_teamMonsterIdArray[counter] == -1) { _stru3244C[counter + 3]._field0 = -1; _stru3244C[counter + 3]._field2 = -1; @@ -3251,8 +3251,8 @@ void EfhEngine::sub1CDFA() { } } - for (int16 counter = 0; counter < 8; ++counter) { - for (int16 counter2 = 0; counter2 < 8; ++counter2) { + for (uint counter = 0; counter < 8; ++counter) { + for (uint counter2 = 0; counter2 < 8; ++counter2) { if (_stru3244C[counter]._field2 >= _stru3244C[counter2]._field2) continue; @@ -3265,7 +3265,7 @@ void EfhEngine::sub1CDFA() { void EfhEngine::redrawScreenForced() { debug("redrawScreenForced"); - for (int16 counter = 0; counter < 2; ++counter) { + for (uint counter = 0; counter < 2; ++counter) { drawScreen(); if (counter == 0) displayFctFullScreen(); @@ -3326,7 +3326,7 @@ int16 EfhEngine::sub1C956(int16 charId, int16 unkFied18Val, bool arg4) { } do { - for (int16 counter = 0; counter < 2; ++counter) { + for (uint counter = 0; counter < 2; ++counter) { drawCombatScreen(charId, true, false); if (_teamMonsterIdArray[1] != -1) sub1C219((uint8 *)"Select Monster Group:", 3, 0, false); @@ -3360,7 +3360,7 @@ int16 EfhEngine::sub1C956(int16 charId, int16 unkFied18Val, bool arg4) { void EfhEngine::sub1CAB6(int16 charId) { debug("sub1CAB6 %d", charId); - for (int16 counter = 0; counter < 2; ++counter) { + for (uint counter = 0; counter < 2; ++counter) { drawGameScreenAndTempText(false); displayLowStatusScreen(false); drawCombatScreen(charId, false, false); @@ -3373,7 +3373,7 @@ bool EfhEngine::sub1CB27() { debug("sub1CB27"); bool var4 = false; - for (int16 counter1 = 0; counter1 < _teamSize; ++counter1) { + for (int counter1 = 0; counter1 < _teamSize; ++counter1) { _teamLastAction[counter1] = 0; if (!isTeamMemberStatusNormal(counter1)) continue; @@ -3396,7 +3396,7 @@ bool EfhEngine::sub1CB27() { _teamLastAction[counter1] = 'H'; break; case Common::KEYCODE_r: // Run - for (int16 counter2 = 0; counter2 < _teamSize; ++counter2) { + for (int counter2 = 0; counter2 < _teamSize; ++counter2) { _teamLastAction[counter2] = 'R'; } return true; @@ -3482,19 +3482,19 @@ void EfhEngine::sub1BE9A(int16 monsterId) { int16 var4 = 1; // sub1BE9A - 1rst loop counter1_monsterId - Start - for (int16 counter1 = 0; counter1 < 5; ++counter1) { + for (uint counter1 = 0; counter1 < 5; ++counter1) { if (countMonsterGroupMembers(counter1)) continue; - for (int16 counter2 = 0; counter2 < 9; ++counter2) { + for (uint counter2 = 0; counter2 < 9; ++counter2) { _mapMonsters[_teamMonsterIdArray[counter1]]._pictureRef[counter2] = 0; _stru32686[counter1]._field0[counter2] = 0; _stru32686[counter1]._field2[counter2] = 0; } _teamMonsterIdArray[counter1] = -1; - for (int16 counter2 = counter1 + 1; counter2 < 5; ++counter2) { - for (int16 var8 = 0; var8 < 9; ++var8) { + for (uint counter2 = counter1 + 1; counter2 < 5; ++counter2) { + for (uint var8 = 0; var8 < 9; ++var8) { _stru32686[counter1]._field0[var8] = _stru32686[counter2]._field0[var8]; _stru32686[counter1]._field2[var8] = _stru32686[counter2]._field2[var8]; } @@ -3505,7 +3505,7 @@ void EfhEngine::sub1BE9A(int16 monsterId) { // sub1BE9A - 1rst loop counter1_monsterId - End var4 = -1; - for (int16 counter1 = 0; counter1 < 5; ++counter1) { + for (uint counter1 = 0; counter1 < 5; ++counter1) { if (_teamMonsterIdArray[counter1] == -1) { var4 = counter1; break; @@ -3514,18 +3514,18 @@ void EfhEngine::sub1BE9A(int16 monsterId) { if (var4 != -1) { // sub1BE9A - loop var2 - Start - for (int16 var2 = 1; var2 < 3; ++var2) { + for (int var2 = 1; var2 < 3; ++var2) { if (var4 >= 5) break; - for (int16 counter1 = 0; counter1 < 64; ++counter1) { + for (uint counter1 = 0; counter1 < 64; ++counter1) { if (_mapMonsters[counter1]._guess_fullPlaceId == 0xFF) continue; if (((_mapMonsters[counter1]._possessivePronounSHL6 & 0x3F) == 0x3F && !isCharacterATeamMember(_mapMonsters[counter1]._field_1)) || (_mapMonsters[counter1]._possessivePronounSHL6 & 0x3F) <= 0x3D) { if (checkIfMonsterOnSameLargeMapPlace(counter1)) { bool var6 = false; - for (int16 counter2 = 0; counter2 < 9; ++counter2) { + for (uint counter2 = 0; counter2 < 9; ++counter2) { if (_mapMonsters[counter1]._pictureRef[counter2] > 0) { var6 = true; break; @@ -3548,7 +3548,7 @@ void EfhEngine::sub1BE9A(int16 monsterId) { // Furthermore, it was accessing _stru32686[counter1]._field0[counter1] which doesn't make // sense... // I therefore decided to use another counter as it looks like an original misbehavior/bug. - for (int16 counter2 = 0; counter2 < 9; ++counter2) { + for (uint counter2 = 0; counter2 < 9; ++counter2) { _stru32686[counter1]._field0[counter2] = 0; } @@ -3567,7 +3567,7 @@ void EfhEngine::sub1BE9A(int16 monsterId) { // sub1BE9A - last loop counter1_monsterId - Start for (int16 counter1 = var4; counter1 < 5; ++counter1) { _teamMonsterIdArray[counter1] = -1; - for (int16 counter2 = 0; counter2 < 9; ++counter2) { + for (uint counter2 = 0; counter2 < 9; ++counter2) { _stru32686[counter1]._field0[counter2] = (int16)0x8000; } } @@ -3578,7 +3578,7 @@ int16 EfhEngine::getTeamMonsterAnimId() { debug("getTeamMonsterAnimId"); int16 retVal = 0xFF; - for (int16 counter = 0; counter < 5; ++counter) { + for (uint counter = 0; counter < 5; ++counter) { int16 monsterId = _teamMonsterIdArray[counter]; if (monsterId == -1) continue; @@ -3600,7 +3600,7 @@ int16 EfhEngine::countMonsterGroupMembers(int16 monsterGroup) { debugC(9, kDebugEngine, "countMonsterGroupMembers %d", monsterGroup); int16 result = 0; - for (int16 counter = 0; counter < 9; ++counter) { + for (uint counter = 0; counter < 9; ++counter) { if (isMonsterActive(monsterGroup, counter)) ++result; } @@ -3612,7 +3612,7 @@ void EfhEngine::sub1C4CA(bool whiteFl) { debug("sub1C4CA %s", whiteFl ? "True" : "False"); int16 textPosY = 20; - for (int16 counter = 0; counter < 5; ++counter) { + for (uint counter = 0; counter < 5; ++counter) { if (_teamMonsterIdArray[counter] == -1) continue; @@ -3707,7 +3707,7 @@ void EfhEngine::displayCombatMenu(int16 charId) { void EfhEngine::drawCombatScreen(int16 charId, bool whiteFl, bool forceDrawFl) { debug("drawCombatScreen %d %s %s", charId, whiteFl ? "True" : "False", forceDrawFl ? "True" : "False"); - for (int16 counter = 0; counter < 2; ++counter) { + for (uint counter = 0; counter < 2; ++counter) { if (counter == 0 || forceDrawFl) { drawMapWindow(); displayCenteredString("Combat", 128, 303, 9); @@ -3771,7 +3771,7 @@ int16 EfhEngine::sub1DEC8(int16 groupNumber) { if (monsterId == -1) return -1; - for (int16 counter = 0; counter < 9; ++counter) { + for (uint counter = 0; counter < 9; ++counter) { if (isMonsterActive(groupNumber, counter)) { var4 = counter; break; @@ -3980,7 +3980,7 @@ void EfhEngine::genericGenerateSound(int16 soundType, int16 repeatCount) { case 11: case 12: case 13: - for (int16 counter = 0; counter < repeatCount; ++counter) { + for (int counter = 0; counter < repeatCount; ++counter) { generateSound(17); } break; @@ -4010,7 +4010,7 @@ bool EfhEngine::hasAdequateDefense_2(int16 charId, uint8 attackType) { if (_items[itemId].field_16 == 0 && _items[itemId].field17_attackTypeDefense == attackType) return true; - for (int16 counter = 0; counter < 10; ++counter) { + for (uint counter = 0; counter < 10; ++counter) { if (_npcBuf[charId]._inventory[counter]._ref == 0x7FFF || _npcBuf[charId]._inventory[counter]._stat1 == 0x80) continue; @@ -4499,7 +4499,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { int16 var64 = _items[unk_monsterField5_itemId]._attacks *_npcBuf[_teamCharId[teamCharId]]._speed; // Action A - Loop var84 - Start - for (int16 var84 = 0; var84 < var64; ++var84) { + for (int var84 = 0; var84 < var64; ++var84) { if (getRandom(100) < charScore) { ++var62; if (!hasAdequateDefense(_teamMonsterIdArray[groupId], _items[unk_monsterField5_itemId]._attackType)) { @@ -4743,7 +4743,7 @@ void EfhEngine::sub1D8C2(int16 charId, int16 damage) { if (damage > 50) damage = 50; - for (int16 objectId = 0; objectId < 10; ++objectId) { + for (uint objectId = 0; objectId < 10; ++objectId) { if (_npcBuf[charId]._inventory[objectId]._ref == 0x7FFF || (_npcBuf[charId]._inventory[objectId]._stat1 & 0x80) == 0 && _items[_npcBuf[charId]._inventory[objectId]._ref]._defense == 0) continue; @@ -4812,7 +4812,7 @@ bool EfhEngine::handleFight(int16 monsterId) { int16 varInt = getTeamMonsterAnimId(); displayAnimFrames(varInt, true); - for (int16 counter = 0; counter < _teamSize; ++counter) { + for (int counter = 0; counter < _teamSize; ++counter) { _word32680[counter] = 100; _word32482[counter] = 65; } @@ -4825,7 +4825,7 @@ bool EfhEngine::handleFight(int16 monsterId) { return false; } - for (int16 counter = 0; counter < _teamSize; ++counter) { + for (int counter = 0; counter < _teamSize; ++counter) { if (_teamLastAction[counter] == 0x52) // 'R' mainLoopCond = true; } @@ -4833,7 +4833,7 @@ bool EfhEngine::handleFight(int16 monsterId) { sub1CDFA(); sub1C219(nullptr, 2, 1, false); - for (int16 counter = 0; counter < 8; ++counter) { + for (uint counter = 0; counter < 8; ++counter) { int16 monsterGroupIdOrMonsterId = _stru3244C[counter]._field0; if (monsterGroupIdOrMonsterId == -1) continue; @@ -4861,7 +4861,7 @@ bool EfhEngine::handleFight(int16 monsterId) { } } else if (unkFct_checkMonsterField8(monsterGroupIdOrMonsterId, true)) { // handleFight - Loop on var86 - Start - for (int16 var86 = 0; var86 < 9; ++var86) { + for (uint var86 = 0; var86 < 9; ++var86) { if (isMonsterActive(monsterGroupIdOrMonsterId, var86)) { int16 unk_monsterField5_itemId = _mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._itemId_Weapon; if (unk_monsterField5_itemId == 0xFF) @@ -4869,7 +4869,7 @@ bool EfhEngine::handleFight(int16 monsterId) { int16 teamMemberId = -1; int16 var54; if (_items[unk_monsterField5_itemId]._range < 3) { - for (int16 var84 = 0; var84 < 10; ++var84) { + for (uint var84 = 0; var84 < 10; ++var84) { teamMemberId = getRandom(_teamSize) - 1; if (checkWeaponRange(_teamMonsterIdArray[monsterGroupIdOrMonsterId], unk_monsterField5_itemId) && isTeamMemberStatusNormal(teamMemberId) && getRandom(100) < _word32680[teamMemberId]) { break; @@ -4898,7 +4898,7 @@ bool EfhEngine::handleFight(int16 monsterId) { int16 originalDamage = 0; int16 damagePointsAbsorbed = 0; int16 var64 = _mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._field_1 * _items[unk_monsterField5_itemId]._attacks; - for (int16 var84 = 0; var84 < var64; ++var84) { + for (int var84 = 0; var84 < var64; ++var84) { // handleFight - Loop var84 on var64 (objectId) - Start if (getRandom(100) > _word32482[var7E]) continue; @@ -5115,7 +5115,7 @@ void EfhEngine::displayMenuItemString(int16 menuBoxId, int16 thisBoxId, int16 mi void EfhEngine::displayStatusMenu(int16 windowId) { debug("displayStatusMenu %d", windowId); - for (int16 counter = 0; counter < 9; ++counter) { + for (uint counter = 0; counter < 9; ++counter) { drawColoredRect(80, 39 + 14 * counter, 134, 47 + 14 * counter, 0); } @@ -5170,7 +5170,7 @@ void EfhEngine::countRightWindowItems(int16 menuId, int16 charId) { } if (var4 == -1) { - for (int16 counter = 0; counter < 10; ++counter) { + for (uint counter = 0; counter < 10; ++counter) { if (_npcBuf[charId]._inventory[counter]._ref != 0x7FFF) { _word3273A[_menuItemCounter++] = counter; } @@ -5242,7 +5242,7 @@ void EfhEngine::displayCharacterSummary(int16 curMenuLine, int16 npcId) { return; } - for (int16 counter = 0; counter < _menuItemCounter; ++counter) { + for (int counter = 0; counter < _menuItemCounter; ++counter) { if (_menuDepth == 0) setTextColorGrey(); else { @@ -5316,7 +5316,7 @@ void EfhEngine::displayCharacterInformationOrSkills(int16 curMenuLine, int16 cha return; } - for (int16 counter = 0; counter < _menuItemCounter; ++counter) { + for (int counter = 0; counter < _menuItemCounter; ++counter) { if (counter == curMenuLine) setTextColorWhite(); int16 textPosY = 38 + counter * 9; @@ -5413,7 +5413,7 @@ int16 EfhEngine::displayString_3(const char *str, bool animFl, int16 charId, int int16 retVal = 0; - for (int16 counter = 0; counter < 2; ++counter) { + for (uint counter = 0; counter < 2; ++counter) { unk_StatusMenu(windowId, menuId, curMenuLine, charId, true, false); displayWindow(_windowWithBorderBuf, 19, 113, _hiResImageBuf); @@ -5473,7 +5473,7 @@ void EfhEngine::sub191FF(int16 charId, int16 objectId, int16 windowId, int16 men } else { int16 var2 = _items[itemId].field_18; if (var2 != 4) { - for (int16 counter = 0; counter < 10; ++counter) { + for (uint counter = 0; counter < 10; ++counter) { if (var2 == _items[_npcBuf[charId]._inventory[counter]._ref].field_18) equipCursedItem(charId, objectId, windowId, menuId, curMenuLine); } @@ -5554,7 +5554,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me int16 victims = 0; strncat((char *)_messageToBePrinted, " The item emits a low droning hum...", 400); if (getRandom(100) < 50) { - for (int16 counter = 0; counter < 9; ++counter) { + for (uint counter = 0; counter < 9; ++counter) { if (isMonsterActive(windowId, counter)) { ++victims; _stru32686[windowId]._field0[counter] = 1; @@ -5563,7 +5563,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me } } else { int16 NumberOfTargets = getRandom(9); - for (int16 counter = 0; counter < 9; ++counter) { + for (uint counter = 0; counter < 9; ++counter) { if (NumberOfTargets == 0) break; @@ -5593,7 +5593,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me strncat((char *)_messageToBePrinted, " The item emits a blue beam...", 400); int16 victim = 0; if (getRandom(100) < 50) { - for (int16 varA8 = 0; varA8 < 9; ++varA8) { + for (uint varA8 = 0; varA8 < 9; ++varA8) { if (isMonsterActive(windowId, varA8)) { ++victim; _stru32686[windowId]._field0[varA8] = 2; @@ -5602,7 +5602,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me } } else { int16 varAC = getRandom(9); - for (int16 varA8 = 0; varA8 < 9; ++varA8) { + for (uint varA8 = 0; varA8 < 9; ++varA8) { if (varAC == 0) break; @@ -5643,13 +5643,13 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me } else { strncat((char *)_messageToBePrinted, " A dark gray fiery whirlwind surrounds the poor victim...the power fades and death abounds!", 400); if (getRandom(100) < 50) { - for (int16 counter = 0; counter < 9; ++counter) { + for (uint counter = 0; counter < 9; ++counter) { if (getRandom(100) < 50) { _mapMonsters[_teamMonsterIdArray[windowId]]._pictureRef[counter] = 0; } } } else { - for (int16 counter = 0; counter < 9; ++counter) { + for (uint counter = 0; counter < 9; ++counter) { if (isMonsterActive(windowId, counter)) { if (getRandom(100) < 50) { _mapMonsters[_teamMonsterIdArray[windowId]]._pictureRef[counter] = 0; @@ -5667,12 +5667,12 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me } else { if (getRandom(100) < 50) { strncat((char *)_messageToBePrinted, " A dark fiery whirlwind surrounds the poor victim...the power fades and all targeted die!", 400); - for (int16 counter = 0; counter < 9; ++counter) { + for (uint counter = 0; counter < 9; ++counter) { _mapMonsters[_teamMonsterIdArray[windowId]]._pictureRef[counter] = 0; } } else { strncat((char *)_messageToBePrinted, " A dark fiery whirlwind surrounds the poor victim...the power fades and one victim dies!", 400); - for (int16 counter = 0; counter < 9; ++counter) { + for (uint counter = 0; counter < 9; ++counter) { if (isMonsterActive(windowId, counter)) { _mapMonsters[_teamMonsterIdArray[windowId]]._pictureRef[counter] = 0; } @@ -6470,7 +6470,7 @@ bool EfhEngine::checkMonsterCollision() { int16 var68 = 0; - for (int16 monsterId = 0; monsterId < 64; ++monsterId) { + for (uint monsterId = 0; monsterId < 64; ++monsterId) { if (!checkPictureRefAvailability(monsterId)) continue; @@ -6494,14 +6494,14 @@ bool EfhEngine::checkMonsterCollision() { _redrawNeededFl = true; int16 var6A = 0; - for (int16 var6C = 0; var6C < 9; ++var6C) { + for (uint var6C = 0; var6C < 9; ++var6C) { if (_mapMonsters[monsterId]._pictureRef[var6C]) ++var6A; } Common::String buffer = ""; do { - for (int16 var6C = 0; var6C < 2; ++var6C) { + for (uint var6C = 0; var6C < 2; ++var6C) { int16 var1 = _mapMonsters[monsterId]._possessivePronounSHL6 & 0x3F; Common::String dest; if (var1 <= 0x3D) { @@ -6736,8 +6736,8 @@ void EfhEngine::copyCurrentPlaceToBuffer(int16 id) { // Note that 576 = 24 * 24 uint8 *placesPtr = &_places[576 * id]; - for (int16 i = 0; i < 24; ++i) { - for (int16 j = 0; j < 24; ++j) { + for (uint i = 0; i < 24; ++i) { + for (uint j = 0; j < 24; ++j) { _curPlace[i][j] = placesPtr[i * 24 + j]; } } diff --git a/engines/efh/files.cpp b/engines/efh/files.cpp index fc0090c0b071..38b6984f2662 100644 --- a/engines/efh/files.cpp +++ b/engines/efh/files.cpp @@ -87,9 +87,11 @@ void EfhEngine::findMapFile(int16 mapId) { void EfhEngine::rImageFile(Common::String filename, uint8 *targetBuffer, uint8 **subFilesArray, uint8 *packedBuffer) { debugC(1, kDebugUtils, "rImageFile %s", filename.c_str()); readFileToBuffer(filename, packedBuffer); - uint32 size = uncompressBuffer(packedBuffer, targetBuffer); -#ifdef debug +#ifndef debug + uncompressBuffer(packedBuffer, targetBuffer); +#else + uint32 size = uncompressBuffer(packedBuffer, targetBuffer); // dump a decompressed image file Common::DumpFile dump; dump.open(filename + ".dump"); @@ -136,7 +138,7 @@ void EfhEngine::readItems() { error("Unable to find file %s", fileName.c_str()); for (int i = 0; i < 300; ++i) { - for (int16 idx = 0; idx < 15; ++idx) + for (uint idx = 0; idx < 15; ++idx) _items[i]._name[idx] = f.readByte(); _items[i]._damage = f.readByte(); diff --git a/engines/efh/graphics.cpp b/engines/efh/graphics.cpp index ac1ee0305dad..8e9a97213c94 100644 --- a/engines/efh/graphics.cpp +++ b/engines/efh/graphics.cpp @@ -299,7 +299,7 @@ void EfhEngine::drawChar(uint8 curChar, int16 posX, int16 posY) { int16 charId = curChar - 0x20; uint8 width = _fontDescr._widthArray[charId]; - for (int16 line = 0; line < 8; ++line) { + for (uint line = 0; line < 8; ++line) { int16 x = 0; for (int i = 7; i >= 7 - width; --i) { if (_fontDescr._fontData[charId]._lines[line] & (1 << i)) From d03b0043ddde839b73d18503948ee1e6abc5ee20 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sat, 26 Nov 2022 14:13:29 +0100 Subject: [PATCH 179/412] EFH: Fix formatting, remove an obsolete comment --- engines/efh/efh.cpp | 67 ++++++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 34 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 720a5ccc992d..2aa65620bdec 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -1324,7 +1324,7 @@ int16 EfhEngine::chooseCharacterToReplace() { int16 EfhEngine::handleCharacterJoining() { debug("handleCharacterJoining"); - static char strReplaceWho[13] = "Replace Who?"; + const char strReplaceWho[13] = "Replace Who?"; for (uint counter = 0; counter < 3; ++counter) { if (_teamCharId[counter] == -1) { return counter; @@ -3572,10 +3572,10 @@ void EfhEngine::sub1BE9A(int16 monsterId) { } } // sub1BE9A - last loop counter1_monsterId - End - } +} int16 EfhEngine::getTeamMonsterAnimId() { - debug("getTeamMonsterAnimId"); + debug("getTeamMonsterAnimId"); int16 retVal = 0xFF; for (uint counter = 0; counter < 5; ++counter) { @@ -3918,34 +3918,34 @@ void EfhEngine::generateSound5(int arg0) { void EfhEngine::generateSound(int16 soundType) { switch (soundType) { - case 5: - generateSound3(); - break; - case 9: - generateSound1(20, 888, 3000); - generateSound1(20, 888, 3000); - break; - case 10: - generateSound5(1); - break; - case 13: - generateSound2(256, 4096, 18); - break; - case 14: - generateSound2(20, 400, 100); - break; - case 15: - generateSound2(100, 888, 88); - break; - case 16: - generateSound1(2000, 6096, 1500); - break; - case 17: - generateSound4(1); - break; - default: - // Not implemented because not used by the engine - break; + case 5: + generateSound3(); + break; + case 9: + generateSound1(20, 888, 3000); + generateSound1(20, 888, 3000); + break; + case 10: + generateSound5(1); + break; + case 13: + generateSound2(256, 4096, 18); + break; + case 14: + generateSound2(20, 400, 100); + break; + case 15: + generateSound2(100, 888, 88); + break; + case 16: + generateSound1(2000, 6096, 1500); + break; + case 17: + generateSound4(1); + break; + default: + // Not implemented because not used by the engine + break; } } @@ -5099,7 +5099,7 @@ void EfhEngine::displayMenuItemString(int16 menuBoxId, int16 thisBoxId, int16 mi else setTextColorGrey(); - snprintf(buffer, 20,"> %s <", str); + snprintf(buffer, 20, "> %s <", str); displayCenteredString(buffer, minX, maxX, minY); setTextColorRed(); } else { @@ -5914,7 +5914,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me } break; case 25: { - int16 teamCharId; + int16 teamCharId; if (argA == 2) { displayString_3("Who will use this item?", false, charId, windowId, menuId, curMenuLine); teamCharId = selectOtherCharFromTeam(); @@ -6571,7 +6571,6 @@ bool EfhEngine::checkMonsterCollision() { var68 = true; break; default: -// warning("STUB: checkMonsterCollision - Missing mapping ?"); break; } } while (!var68); From bc7de3a10a483d38ae1746ceb0fd4c845340e037 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Mon, 28 Nov 2022 08:19:58 +0100 Subject: [PATCH 180/412] EFH: Split some more functions from efh.cpp --- engines/efh/efh.cpp | 1096 ---------------------------------------- engines/efh/efh.h | 22 +- engines/efh/fight.cpp | 651 ++++++++++++++++++++++++ engines/efh/module.mk | 2 + engines/efh/script.cpp | 500 ++++++++++++++++++ 5 files changed, 1166 insertions(+), 1105 deletions(-) create mode 100644 engines/efh/fight.cpp create mode 100644 engines/efh/script.cpp diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 2aa65620bdec..46a5c9da2d9b 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -1102,33 +1102,6 @@ void EfhEngine::displayLowStatusScreen(bool flag) { } } -uint8 *EfhEngine::script_readNumberArray(uint8 *srcBuffer, int16 destArraySize, int16 *destArray) { - debug("script_readNumberArray"); - - uint8 *buffer = srcBuffer; - for (int i = 0; i < destArraySize; ++i) { - buffer++; - buffer = script_getNumber(buffer, &destArray[i]); - } - - return buffer; -} - -uint8 *EfhEngine::script_getNumber(uint8 *srcBuffer, int16 *retval) { - debug("script_getNumber"); - - uint8 *buffer = srcBuffer; - int16 var2 = 0; - for (;;) { - uint8 curChar = *buffer; - if (curChar < 0x30 || curChar > 0x39) { - *retval = var2; - return buffer; - } - var2 = var2 * 10 + curChar - 0x30; - buffer++; - } -} void EfhEngine::removeObject(int16 charId, int16 objectId) { debug("removeObject %d %d", charId, objectId); @@ -1352,450 +1325,6 @@ int16 EfhEngine::handleCharacterJoining() { return 2; } -int16 EfhEngine::script_parse(uint8 *stringBuffer, int16 posX, int16 posY, int16 maxX, int16 maxY, bool flag) { - debug("script_parse %s %d-%d %d-%d %s", (char *) stringBuffer, posX, posY, maxX, maxY, flag ? "True" : "False"); - - bool doneFlag = false; - int16 var_F2 = -1; - int16 var_F0 = 0xFF; - int16 var_EE = 0xFF; - uint16 curLineNb = 0; - int16 numbLines = (1 + maxY - posY) / 9; - int16 width = maxX - posX; - int16 spaceWidth = getStringWidth(" "); - uint8 *buffer = stringBuffer; - char nextWord[80]; - char curLine[150]; - memset(nextWord, 0, sizeof(nextWord)); - memset(curLine, 0, sizeof(curLine)); - int16 curWordPos = 0; - setTextPos(posX, curLineNb * 9 + posY); - - while (!doneFlag) { - uint8 curChar = *buffer; - if (curChar != 0x5E && curChar != 0x20 && curChar != 0 && curChar != 0x7C) { - var_F2 = 0; - nextWord[curWordPos++] = curChar; - ++buffer; - continue; - } - - if (curChar != 0x5E) { - if (curChar == 0) - doneFlag = true; - else if (curChar == 0x7C) - var_F2 = 0; - - nextWord[curWordPos] = 0; - int16 widthNextWord = getStringWidth(nextWord); - int16 widthCurrentLine = spaceWidth + getStringWidth(curLine); - - if (widthCurrentLine + widthNextWord > width || curChar == 0x7C) { - if (curLineNb >= numbLines) { - doneFlag = true; - } else { - if (var_F2 == 0) - displayStringAtTextPos(curLine); - - *curLine = 0; - strncpy(curLine, nextWord, 80); - strncat(curLine, " ",2); - ++curLineNb; - setTextPos(posX, posY + curLineNb * 9); - curWordPos = 0; - } - } else { - strncat(curLine, nextWord, 80); - strncat(curLine, " ", 2); - curWordPos = 0; - } - ++buffer; - continue; - } - - // At this point, curChar == 0x5E - ++buffer; - int16 opCode = 0; - buffer = script_getNumber(buffer, &opCode); - int16 scriptNumberArray[10]; - memset(scriptNumberArray, 0, sizeof(scriptNumberArray)); - - switch (opCode) { - case 0x00: - // Enter room { full Place Id, posX, posY } - buffer = script_readNumberArray(buffer, 3, scriptNumberArray); - if (flag) { - if (_largeMapFlag) { - _largeMapFlag = false; - _techDataId_MapPosX = _mapPosX; - _techDataId_MapPosY = _mapPosY; - } - _oldMapPosX = _mapPosX = scriptNumberArray[1]; - _oldMapPosY = _mapPosY = scriptNumberArray[2]; - loadPlacesFile(scriptNumberArray[0], false); - _word2C880 = true; - _redrawNeededFl = true; - } - break; - case 0x01: - // Exit room { } - if (flag) { - _largeMapFlag = true; - _oldMapPosX = _mapPosX = _techDataId_MapPosX; - _oldMapPosY = _mapPosY = _techDataId_MapPosY; - _word2C880 = true; - _redrawNeededFl = true; - } - break; - case 0x02: - // Change map. { map number, posX, posY } - buffer = script_readNumberArray(buffer, 3, scriptNumberArray); - if (flag) { - if (_word2C8D7) - writeTechAndMapFiles(); - _oldMapPosX = _mapPosX = scriptNumberArray[1]; - _oldMapPosY = _mapPosY = scriptNumberArray[2]; - loadTechMapImp(scriptNumberArray[0]); - _largeMapFlag = true; - _word2C880 = true; - _redrawNeededFl = true; - doneFlag = true; - } - break; - case 0x03: - buffer = script_readNumberArray(buffer, 4, scriptNumberArray); - if (flag) { - int16 var110 = scriptNumberArray[2] - scriptNumberArray[0]; - int16 var10E = scriptNumberArray[3] - scriptNumberArray[1]; - - _mapPosX = getRandom(var110) + scriptNumberArray[0] - 1; - _mapPosY = getRandom(var10E) + scriptNumberArray[1] - 1; - _word2C880 = true; - _redrawNeededFl = true; - } - break; - case 0x04: - buffer = script_readNumberArray(buffer, 2, scriptNumberArray); - if (flag) { - _mapPosX = scriptNumberArray[0]; - _mapPosY = scriptNumberArray[1]; - _word2C880 = true; - _redrawNeededFl = true; - } - break; - case 0x05: - buffer = script_readNumberArray(buffer, 4, scriptNumberArray); - if (flag) { - int16 var110 = _teamCharId[scriptNumberArray[0]]; - if (var110 != -1) { - int16 var10E = scriptNumberArray[1]; - _npcBuf[var110]._activeScore[var10E] += scriptNumberArray[2] & 0xFF; - _npcBuf[var110]._activeScore[var10E] -= scriptNumberArray[3] & 0xFF; - } - } - break; - case 0x06: - buffer = script_readNumberArray(buffer, 2, scriptNumberArray); - if (flag) { - int16 var110 = _teamCharId[scriptNumberArray[0]]; - if (var110 != -1) { - int16 var10E = scriptNumberArray[1]; - _npcBuf[var110]._activeScore[var10E] = scriptNumberArray[1]; - } - } - break; - case 0x07: - if (flag) { - totalPartyKill(); - // emptyFunction(2); - } - break; - case 0x08: - buffer = script_readNumberArray(buffer, 1, scriptNumberArray); - if (flag && scriptNumberArray[0] != -1) { - _npcBuf[_teamCharId[scriptNumberArray[0]]]._hitPoints = 0; - } - break; - case 0x09: - buffer = script_readNumberArray(buffer, 2, scriptNumberArray); - if (flag) { - int16 var110 = _teamCharId[scriptNumberArray[0]]; - if (var110 != -1) { - int16 var10E = getRandom(scriptNumberArray[1]); - _npcBuf[var110]._hitPoints += var10E; - if (_npcBuf[var110]._hitPoints > _npcBuf[var110]._maxHP) - _npcBuf[var110]._hitPoints = _npcBuf[var110]._maxHP; - } - } - break; - case 0x0A: - buffer = script_readNumberArray(buffer, 1, scriptNumberArray); - if (flag) { - int16 var110 = _teamCharId[scriptNumberArray[0]]; - if (var110 != -1) { - _npcBuf[var110]._hitPoints = _npcBuf[var110]._maxHP; - } - } - break; - case 0x0B: - buffer = script_readNumberArray(buffer, 2, scriptNumberArray); - if (flag) { - int16 var110 = _teamCharId[scriptNumberArray[0]]; - if (var110 != -1) { - int16 var10E = getRandom(scriptNumberArray[1]); - _npcBuf[var110]._hitPoints -= var10E; - if (_npcBuf[var110]._hitPoints < 0) - _npcBuf[var110]._hitPoints = 0; - } - } - break; - case 0x0C: - buffer = script_readNumberArray(buffer, 2, scriptNumberArray); - if (flag) { - int16 var110 = scriptNumberArray[0]; - bool found = false; - for (int counter = 0; counter < _teamSize && !found; ++counter) { - for (uint objectId = 0; objectId < 10; ++objectId) { - if (_npcBuf[_teamCharId[counter]]._inventory[objectId]._ref == var110) { - removeObject(_teamCharId[counter], objectId); - found = true; - break; - } - } - } - } - break; - case 0x0D: - // Put item in inventory { objectId } - buffer = script_readNumberArray(buffer, 1, scriptNumberArray); - if (flag) { - int16 var110 = scriptNumberArray[0]; - for (int counter = 0; counter < _teamSize; ++counter) { - if (giveItemTo(_teamCharId[counter], var110, 0xFF)) - break; - } - } - break; - case 0x0E: - buffer = script_readNumberArray(buffer, 3, scriptNumberArray); - if (flag) { - int16 var110 = scriptNumberArray[0]; - bool found = false; - for (int counter = 0; counter < _teamSize && !found; ++counter) { - for (uint objectId = 0; objectId < 10; ++objectId) { - if (_npcBuf[_teamCharId[counter]]._inventory[objectId]._ref == var110) { - found = true; - break; - } - } - } - - if (found) - var_F0 = scriptNumberArray[1]; - else - var_F0 = scriptNumberArray[2]; - } - break; - case 0x0F: - buffer = script_readNumberArray(buffer, 3, scriptNumberArray); - if (flag) { - int16 var110 = scriptNumberArray[0]; - if (isCharacterATeamMember(var110)) - var_F0 = scriptNumberArray[1]; - else - var_F0 = scriptNumberArray[2]; - } - break; - case 0x10: - buffer = script_readNumberArray(buffer, 1, scriptNumberArray); - if (flag) - var_F0 = scriptNumberArray[0]; - - break; - case 0x11: - if (flag) - _unkArray2C8AA[0] = 0; - break; - case 0x12: - // Guess : disable special tile { } - if (flag) { - int16 var110 = sub151FD(_mapPosX, _mapPosY); - if (var110 != -1) - _mapUnknown[var110]._posX = 0xFF; - } - break; - case 0x13: - buffer = script_readNumberArray(buffer, 3, scriptNumberArray); - if (flag && _largeMapFlag) { - _word2C87A = true; - loadPlacesFile(scriptNumberArray[0], false); - sub15A28(scriptNumberArray[1], scriptNumberArray[2]); - sub2455E(scriptNumberArray[0], scriptNumberArray[1], scriptNumberArray[2]); - var_F0 = -1; - } - break; - case 0x14: - // Add character to team { charId } - buffer = script_readNumberArray(buffer, 1, scriptNumberArray); - if (flag) { - int16 var110 = scriptNumberArray[0]; - if (!isCharacterATeamMember(var110)) - var_EE = var110; - var_F0 = -1; - } - break; - case 0x15: - buffer = script_readNumberArray(buffer, 2, scriptNumberArray); - if (flag) { - _oldMapPosX = _mapPosX = scriptNumberArray[0]; - _oldMapPosY = _mapPosY = scriptNumberArray[1]; - _largeMapFlag = true; - _redrawNeededFl = true; - } - break; - case 0x16: - buffer = script_readNumberArray(buffer, 1, scriptNumberArray); - if (flag) { - int16 var110 = scriptNumberArray[0]; - // TODO: This "if" is useless, it's doing just the same loop and if statement. Consider removing it. - if (isCharacterATeamMember(var110)) { - for (uint counter = 0; counter < 3; ++counter) { - if (_teamCharId[counter] == var110) { - removeCharacterFromTeam(counter); - break; - } - } - } - } - break; - case 0x17: - buffer = script_readNumberArray(buffer, 1, scriptNumberArray); - if (flag) { - int16 var110 = scriptNumberArray[0]; - displayAnimFrames(var110, true); - } - break; - case 0x18: - buffer = script_readNumberArray(buffer, 2, scriptNumberArray); - if (flag) { - int16 var110 = scriptNumberArray[1] - scriptNumberArray[0] + 1; - bool found = false; - var110 = getRandom(var110) + scriptNumberArray[0] - 1; - int16 counter; - for (counter = 0; counter < _teamSize; ++counter) { - if (giveItemTo(_teamCharId[counter], var110, 0xFF)) { - found = true; - break; - } - } - - if (!found) { - drawMapWindow(); - displayFctFullScreen(); - drawMapWindow(); - var110 = sub1C219((uint8 *)"Nothing...", 1, 2, true); - displayFctFullScreen(); - } else { - _enemyNamePt2 = _npcBuf[_teamCharId[counter]]._name; - _nameBuffer = _items[var110]._name; - snprintf(curLine, 150, "%s finds a %s!", _enemyNamePt2.c_str(), _nameBuffer.c_str()); - drawMapWindow(); - displayFctFullScreen(); - drawMapWindow(); - var110 = sub1C219((uint8 *)curLine, 1, 2, true); - displayFctFullScreen(); - } - - var110 = sub151FD(_mapPosX, _mapPosY); - if (var110 != -1) { - _mapUnknown[var110]._posX = 0xFF; - } - _redrawNeededFl = true; - } - break; - case 0x19: - buffer = script_readNumberArray(buffer, 3, scriptNumberArray); - if (flag) { - if (_largeMapFlag) { - _mapGameMap[scriptNumberArray[0]][scriptNumberArray[1]] = scriptNumberArray[2] & 0xFF; - } else { - _curPlace[scriptNumberArray[0]][scriptNumberArray[1]] = scriptNumberArray[2] & 0xFF; - } - } - break; - case 0x1A: - buffer = script_readNumberArray(buffer, 2, scriptNumberArray); - if (flag) { - int16 var110 = sub151FD(scriptNumberArray[0], scriptNumberArray[1]); - if (var110 != -1) { - _mapUnknown[var110]._posX = 0xFF; - } - } - break; - case 0x1B: - buffer = script_readNumberArray(buffer, 3, scriptNumberArray); - if (flag) { - int16 var110 = sub151FD(scriptNumberArray[0], scriptNumberArray[1]); - if (var110 != -1) { - _mapUnknown[var110]._posX = 0xFF; - } - _mapUnknown[scriptNumberArray[2]]._posX = scriptNumberArray[0]; - _mapUnknown[scriptNumberArray[2]]._posY = scriptNumberArray[1]; - } - break; - case 0x1C: - buffer = script_readNumberArray(buffer, 1, scriptNumberArray); - if (flag) { - _history[scriptNumberArray[0]] = 0xFF; - } - break; - case 0x1D: - buffer = script_readNumberArray(buffer, 1, scriptNumberArray); - if (flag) { - _history[scriptNumberArray[0]] = 0; - } - break; - case 0x1E: - // Dialog with condition { historyId, dialogId1, dialogId2 } - buffer = script_readNumberArray(buffer, 3, scriptNumberArray); - if (flag) { - if (_history[scriptNumberArray[0]] == 0) - var_F0 = scriptNumberArray[2]; - else - var_F0 = scriptNumberArray[1]; - } - break; - case 0x1F: - buffer = script_readNumberArray(buffer, 1, scriptNumberArray); - if (flag) - _unkArray2C8AA[0] = scriptNumberArray[0]; - - break; - case 0x20: - if (flag) { - handleWinSequence(); - _system->quit(); - } - default: - break; - } - } - - if (*curLine != 0 && curLineNb < numbLines && var_F2 == 0) - displayStringAtTextPos(curLine); - - if (var_EE != 0xFF) { - displayLowStatusScreen(true); - int16 teamSlot = handleCharacterJoining(); - if (teamSlot > -1) { - _teamCharId[teamSlot] = var_EE; - } - refreshTeamSize(); - } - - return var_F0; -} - void EfhEngine::drawText(uint8 *srcPtr, int16 posX, int16 posY, int16 maxX, int16 maxY, bool flag) { debugC(7, kDebugEngine, "drawText %d-%d %d-%d %s", posX, posY, maxX, maxY, flag ? "True" : "False"); @@ -3724,44 +3253,6 @@ void EfhEngine::drawCombatScreen(int16 charId, bool whiteFl, bool forceDrawFl) { } } -void EfhEngine::handleFight_checkEndEffect(int16 charId) { - debug("handleFight_checkEndEffect %d", charId); - - // In the original, this function is part of handleFight. - // It has been split for readability purposes. - if (_teamCharStatus[charId]._status == 0) - return; - if (--_teamCharStatus[charId]._duration != 0) - return; - - // At this point : The status is different to 0 (normal) and the effect duration is finally 0 (end of effect) - _enemyNamePt2 = _npcBuf[_teamCharId[charId]]._name; - if ((_npcBuf[_teamCharId[charId]]._possessivePronounSHL6 >> 6) == 2) { - _enemyNamePt1 = "The "; - } else { - _enemyNamePt1 = ""; - } - - // End of effect message depends on the type of effect - switch (_teamCharStatus[charId]._status) { - case 1: - snprintf((char *)_messageToBePrinted, 400, "%s%s wakes up!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str()); - break; - case 2: - snprintf((char *)_messageToBePrinted, 400, "%s%s thaws out!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str()); - break; - default: - snprintf((char *)_messageToBePrinted, 400, "%s%s recovers!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str()); - break; - } - - // The character status is back to normal - _teamCharStatus[charId]._status = 0; - - // Finally, display the message - sub1C219(_messageToBePrinted, 1, 2, true); -} - int16 EfhEngine::sub1DEC8(int16 groupNumber) { debug("sub1DEC8 %d", groupNumber); @@ -4436,284 +3927,6 @@ void EfhEngine::addReactionText(int16 id) { strncat((char *)_messageToBePrinted, buffer, 80); } -void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { - debug("handleFight_lastAction_A %d", teamCharId); - - // In the original, this function is part of handleFight. - // It has been split for readability purposes. - - int16 unk_monsterField5_itemId = sub1C80A(_teamCharId[teamCharId], 9, true); - if (unk_monsterField5_itemId == 0x7FFF) - unk_monsterField5_itemId = 0x3F; - int16 monsterGroupNumber = _teamNextAttack[teamCharId]; - if (monsterGroupNumber == 0x64) - monsterGroupNumber = 0; - - if (monsterGroupNumber == -1) - return; - int16 var58; - if (_items[unk_monsterField5_itemId]._range == 4) - var58 = 5; - else - var58 = monsterGroupNumber + 1; - - int16 var54; - int16 teamMemberId; - if (_items[unk_monsterField5_itemId]._range < 3) { - teamMemberId = sub1DEC8(monsterGroupNumber); - var54 = teamMemberId + 1; - } else { - teamMemberId = 0; - var54 = 9; - } - - if (teamMemberId != -1) { - bool var6E = true; - for (int16 groupId = monsterGroupNumber; groupId < var58; ++groupId) { - if (_teamMonsterIdArray[groupId] == -1) - continue; - - for (int16 var7E = teamMemberId; var7E < var54; ++var7E) { - if (isMonsterActive(groupId, var7E) && var6E) { - int16 var5C; - if (unkFct_checkMonsterField8(groupId, true)) { - sub1E028(groupId, 9, true); - _unkArray2C8AA[0] += 500; - var5C = -1; - } else - var5C = 0; - - int16 var76 = getRandom(_mapMonsters[_teamMonsterIdArray[groupId]]._field_6); - int16 varInt = _teamCharId[teamCharId]; - int16 var51 = _npcBuf[varInt]._possessivePronounSHL6; - var51 >>= 6; - int16 var70 = var51; - varInt = _teamMonsterIdArray[groupId]; - int16 var5E = kEncounters[_mapMonsters[varInt]._monsterRef]._nameArticle; - int16 charScore = getCharacterScore(_teamCharId[teamCharId], unk_monsterField5_itemId); - int16 var80 = _mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E]; - int16 var62 = 0; - int16 hitPoints = 0; - int16 originalDamage = 0; - int16 damagePointsAbsorbed = 0; - int16 var64 = _items[unk_monsterField5_itemId]._attacks *_npcBuf[_teamCharId[teamCharId]]._speed; - - // Action A - Loop var84 - Start - for (int var84 = 0; var84 < var64; ++var84) { - if (getRandom(100) < charScore) { - ++var62; - if (!hasAdequateDefense(_teamMonsterIdArray[groupId], _items[unk_monsterField5_itemId]._attackType)) { - int16 var7C = getRandom(_items[unk_monsterField5_itemId]._damage); - varInt = var7C - var76; - if (varInt > 0) { - originalDamage += varInt; - damagePointsAbsorbed += var76; - } else { - damagePointsAbsorbed += var7C; - } - } - } - } - // Action A - Loop var84 - End - - if (originalDamage < 0) - originalDamage = 0; - - hitPoints = originalDamage + damagePointsAbsorbed; - - if (!checkSpecialItemsOnCurrentPlace(unk_monsterField5_itemId)) - var62 = 0; - - if (var62 > 0) { - _mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] -= originalDamage; - if (var62 > 1) { - snprintf(_attackBuffer, 20, "%d times ", var62); - } else { - *_attackBuffer = 0; - } - } - int16 var68 = _items[unk_monsterField5_itemId]._attackType + 1; - int16 var6A = getRandom(3) - 1; - if (var5E == 2) { - snprintf(_characterNamePt1, 5, "The "); - } else { - *_characterNamePt1 = 0; - } - - if (var70 == 2) { - _enemyNamePt1 = "The "; - } else { - _enemyNamePt1 = ""; - } - - _characterNamePt2 = kEncounters[_mapMonsters[_teamMonsterIdArray[groupId]]._monsterRef]._name; - _enemyNamePt2 = _npcBuf[_teamCharId[teamCharId]]._name; - _nameBuffer = _items[unk_monsterField5_itemId]._name; - if (checkSpecialItemsOnCurrentPlace(unk_monsterField5_itemId)) { - // Action A - Check damages - Start - if (var62 == 0) { - snprintf((char *)_messageToBePrinted, 400, "%s%s %s at %s%s with %s %s, but misses!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2.c_str(), kPossessive[var70], _nameBuffer.c_str()); - } else if (hitPoints <= 0){ - snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s, but does no damage!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2.c_str(), _attackBuffer, kPossessive[var70], _nameBuffer.c_str()); - } else if (hitPoints == 1) { - snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s for 1 point", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2.c_str(), _attackBuffer, kPossessive[var70], _nameBuffer.c_str()); - if (_mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] <= 0) { - getDeathTypeDescription(groupId, teamCharId + 1000); - getXPAndSearchCorpse(_teamCharId[teamCharId], _enemyNamePt1, _enemyNamePt2, _teamMonsterIdArray[groupId]); - } else { - strncat((char *)_messageToBePrinted, "!", 2); - } - } else { - snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s for %d points", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2.c_str(), _attackBuffer, kPossessive[var70], _nameBuffer.c_str(), hitPoints); - if (_mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] <= 0) { - getDeathTypeDescription(groupId, teamCharId + 1000); - getXPAndSearchCorpse(_teamCharId[teamCharId], _enemyNamePt1, _enemyNamePt2, _teamMonsterIdArray[groupId]); - } else { - strncat((char *)_messageToBePrinted, "!", 2); - } - } - // Action A - Check damages - End - - // Action A - Add reaction text - Start - if (var62 != 0 && originalDamage > 0 && getRandom(100) <= 35 && _mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] > 0) { - if (_mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] - 5 <= originalDamage) { - addReactionText(0); - } else if (_mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] < var80 / 8) { - addReactionText(1); - } else if (_mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] < var80 / 4) { - addReactionText(2); - } else if (_mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] < var80 / 2) { - addReactionText(3); - } else if (_mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] < var80 / 3) { - // CHECKME: Doesn't make any sense to check /3 after /2... I don't get it - addReactionText(4); - } else if (var80 / 8 >= originalDamage) { - addReactionText(5); - } else if (originalDamage == 0 && getRandom(100) < 35) { - addReactionText(6); - } - } - // Action A - Add reaction text - End - - // Action A - Add armor absorb text - Start - if (var76 && var62 && _mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] > 0) { - char buffer[80]; - memset(buffer, 0, 80); - if (damagePointsAbsorbed <= 1) - snprintf(buffer, 80, " %s%s's armor absorbs 1 point!", _characterNamePt1, _characterNamePt2.c_str()); - else - snprintf(buffer, 80, " %s%s's armor absorbs %d points!", _characterNamePt1, _characterNamePt2.c_str(), damagePointsAbsorbed); - - strncat((char *)_messageToBePrinted, buffer, 80); - } - // Action A - Add armor absorb text - End - - if (var5C) - strncat((char *)_messageToBePrinted, " Your actions do not go un-noticed...", 400); - - // Action A - Check item durability - Start - varInt = _teamCharId[teamCharId]; - var64 = sub1C80A(varInt, 9, false); - if (var64 != 0x7FFF && (_npcBuf[varInt]._inventory[var64]._stat1 & 0x7F) != 0x7F) { - var51 = _npcBuf[varInt]._inventory[var64]._stat1 & 0x7F; - --var51; - if (var51 <= 0) { - char buffer[80]; - memset(buffer, 0, 80); - snprintf(buffer, 80, " * %s%s's %s breaks!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), _nameBuffer.c_str()); - strncat((char *)_messageToBePrinted, buffer, 80); - setCharacterObjectToBroken(varInt, var64); - var6E = false; - } else { - _npcBuf[varInt]._inventory[var64]._stat1 = (_npcBuf[varInt]._inventory[var64]._stat1 & 80) + var51; - } - } - // Action A - Check item durability - End - - // Action A - Check effect - Start - if (_items[unk_monsterField5_itemId].field_16 == 1 && _mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] > 0) { - if (getRandom(100) < 35) { - _stru32686[var7E]._field0[groupId] = 1; - _stru32686[var7E]._field2[groupId] = getRandom(10); - char buffer[80]; - memset(buffer, 0, 80); - snprintf(buffer, 80, " %s%s falls asleep!", _characterNamePt1, _characterNamePt2.c_str()); - strncat((char *)_messageToBePrinted, buffer, 80); - } - } else if (_items[unk_monsterField5_itemId].field_16 == 2 && _mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] > 0) { - _stru32686[var7E]._field0[groupId] = 2; - _stru32686[var7E]._field2[groupId] = getRandom(10); - char buffer[80]; - memset(buffer, 0, 80); - snprintf(buffer, 80, " %s%s is frozen!", _characterNamePt1, _characterNamePt2.c_str()); - strncat((char *)_messageToBePrinted, buffer, 80); - } - // Action A - Check effect - End - } else { - snprintf((char *)_messageToBePrinted, 400, "%s%s tries to use %s %s, but it doesn't work!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPossessive[var70], _nameBuffer.c_str()); - } - - genericGenerateSound(_items[unk_monsterField5_itemId]._attackType, var62); - sub1C219(_messageToBePrinted, 1, 2, true); - } - } - } - } -} - -void EfhEngine::handleFight_lastAction_D(int16 teamCharId) { - debug("handleFight_lastAction_D %d", teamCharId); - - _word32482[teamCharId] -= 40; - _enemyNamePt2 = _npcBuf[_teamCharId[teamCharId]]._name; - int16 var70 = _npcBuf[_teamCharId[teamCharId]]._possessivePronounSHL6 >> 6; - - if (var70 == 2) - _enemyNamePt1 = "The "; - else - _enemyNamePt1 = ""; - - snprintf((char *)_messageToBePrinted, 400, "%s%s prepares to defend %sself!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPersonal[var70]); - sub1C219(_messageToBePrinted, 1, 2, true); -} - -void EfhEngine::handleFight_lastAction_H(int16 teamCharId) { - debug("handleFight_lastAction_H %d", teamCharId); - - // In the original, this function is part of handleFight. - // It has been split for readability purposes. - - _word32680[teamCharId] -= 50; - _enemyNamePt2 = _npcBuf[_teamCharId[teamCharId]]._name; - int16 var70 = _npcBuf[_teamCharId[teamCharId]]._possessivePronounSHL6 >> 6; - - if (var70 == 2) - _enemyNamePt1 = "The "; - else - _enemyNamePt1 = ""; - - snprintf((char *)_messageToBePrinted, 400, "%s%s attempts to hide %sself!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPersonal[var70]); - sub1C219(_messageToBePrinted, 1, 2, true); -} - -void EfhEngine::handleFight_lastAction_U(int16 teamCharId) { - debug("handleFight_lastAction_U %d", teamCharId); - - // In the original, this function is part of handleFight. - // It has been split for readability purposes. - int16 unk_monsterField5_itemId = _npcBuf[_teamCharId[teamCharId]]._inventory[_word31780[teamCharId]]._ref; - _enemyNamePt2 = _npcBuf[_teamCharId[teamCharId]]._name; - _nameBuffer = _items[unk_monsterField5_itemId]._name; - int16 var70 = _npcBuf[_teamCharId[teamCharId]]._possessivePronounSHL6 >> 6; - if (var70 == 2) - _enemyNamePt1 = "The "; - else - _enemyNamePt1 = ""; - - snprintf((char *)_messageToBePrinted, 400, "%s%s uses %s %s! ", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPossessive[var70], _nameBuffer.c_str()); - sub1C219(_messageToBePrinted, 1, 2, true); -} - char EfhEngine::getFightMessageLastCharacter(char *message) { debug("getFightMessageLastCharacter %s", message); @@ -4778,315 +3991,6 @@ void EfhEngine::sub1D8C2(int16 charId, int16 damage) { } } -bool EfhEngine::handleFight(int16 monsterId) { - debug("handleFight %d", monsterId); - - int16 var8C = 0; - _ongoingFightFl = true; - - sub1BE89(monsterId); - - if (_teamMonsterIdArray[0] == -1) { - resetTeamMonsterIdArray(); - _ongoingFightFl = false; - displayAnimFrames(0xFE, true); - return true; - } - - drawCombatScreen(0, false, true); - - for (bool mainLoopCond = false; !mainLoopCond;) { - if (isTPK()) { - resetTeamMonsterIdArray(); - _ongoingFightFl = false; - displayAnimFrames(0xFE, true); - return false; - } - - if (_teamMonsterIdArray[0] == -1) { - resetTeamMonsterIdArray(); - _ongoingFightFl = false; - displayAnimFrames(0xFE, true); - return true; - } - - int16 varInt = getTeamMonsterAnimId(); - displayAnimFrames(varInt, true); - for (int counter = 0; counter < _teamSize; ++counter) { - _word32680[counter] = 100; - _word32482[counter] = 65; - } - - if (!sub1CB27()) { - resetTeamMonsterIdArray(); - _ongoingFightFl = false; - totalPartyKill(); - displayAnimFrames(0xFE, true); - return false; - } - - for (int counter = 0; counter < _teamSize; ++counter) { - if (_teamLastAction[counter] == 0x52) // 'R' - mainLoopCond = true; - } - - sub1CDFA(); - sub1C219(nullptr, 2, 1, false); - - for (uint counter = 0; counter < 8; ++counter) { - int16 monsterGroupIdOrMonsterId = _stru3244C[counter]._field0; - if (monsterGroupIdOrMonsterId == -1) - continue; - if (monsterGroupIdOrMonsterId > 999) { // Team Member - monsterGroupIdOrMonsterId -= 1000; - if (!isTeamMemberStatusNormal(monsterGroupIdOrMonsterId)) { - handleFight_checkEndEffect(monsterGroupIdOrMonsterId); - } else { - switch (_teamLastAction[monsterGroupIdOrMonsterId]) { - case 0x41:// 'A'ttack - handleFight_lastAction_A(monsterGroupIdOrMonsterId); - break; - case 0x44: // 'D'efend - handleFight_lastAction_D(monsterGroupIdOrMonsterId); - break; - case 0x48: // 'H'ide - handleFight_lastAction_H(monsterGroupIdOrMonsterId); - break; - case 0x55: // 'U'se - handleFight_lastAction_U(monsterGroupIdOrMonsterId); - break; - default: - break; - } - } - } else if (unkFct_checkMonsterField8(monsterGroupIdOrMonsterId, true)) { - // handleFight - Loop on var86 - Start - for (uint var86 = 0; var86 < 9; ++var86) { - if (isMonsterActive(monsterGroupIdOrMonsterId, var86)) { - int16 unk_monsterField5_itemId = _mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._itemId_Weapon; - if (unk_monsterField5_itemId == 0xFF) - unk_monsterField5_itemId = 0x3F; - int16 teamMemberId = -1; - int16 var54; - if (_items[unk_monsterField5_itemId]._range < 3) { - for (uint var84 = 0; var84 < 10; ++var84) { - teamMemberId = getRandom(_teamSize) - 1; - if (checkWeaponRange(_teamMonsterIdArray[monsterGroupIdOrMonsterId], unk_monsterField5_itemId) && isTeamMemberStatusNormal(teamMemberId) && getRandom(100) < _word32680[teamMemberId]) { - break; - } - teamMemberId = -1; - } - var54 = teamMemberId + 1; - } else { - teamMemberId = 0; - var54 = _teamSize; - } - if (teamMemberId != -1) { - // handleFight - Loop on var7E - Start - for (int16 var7E = teamMemberId; var7E < var54; ++var7E) { - if (_teamCharId[var7E] == -1 || !isTeamMemberStatusNormal(var7E)) - continue; - - int16 var76 = getRandom(getEquipmentDefense(_teamCharId[var7E], false)); - varInt = _teamMonsterIdArray[monsterGroupIdOrMonsterId]; - int16 var70 = kEncounters[_mapMonsters[varInt]._monsterRef]._nameArticle; - int16 var5E = _npcBuf[_teamCharId[var7E]]._possessivePronounSHL6 >> 6; - varInt = _items[unk_monsterField5_itemId].field_13; - _word32482[var7E] += (varInt * 5); - int16 var62 = 0; - int16 hitPoints = 0; - int16 originalDamage = 0; - int16 damagePointsAbsorbed = 0; - int16 var64 = _mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._field_1 * _items[unk_monsterField5_itemId]._attacks; - for (int var84 = 0; var84 < var64; ++var84) { - // handleFight - Loop var84 on var64 (objectId) - Start - if (getRandom(100) > _word32482[var7E]) - continue; - - ++var62; - - if (hasAdequateDefense_2(_teamCharId[var7E], _items[unk_monsterField5_itemId]._attackType)) - continue; - - int16 var7C = getRandom(_items[unk_monsterField5_itemId]._damage); - varInt = var7C - var76; - - if (varInt > 0) { - damagePointsAbsorbed += var76; - originalDamage += varInt; - } else { - damagePointsAbsorbed += var7C; - } - // handleFight - Loop var84 on var64 (objectId) - End - } - - if (originalDamage < 0) - originalDamage = 0; - - hitPoints = originalDamage + damagePointsAbsorbed; - if (!checkSpecialItemsOnCurrentPlace(unk_monsterField5_itemId)) - var62 = 0; - - if (var62 > 0) { - _npcBuf[_teamCharId[var7E]]._hitPoints -= originalDamage; - if (var62 > 1) - snprintf(_attackBuffer, 20, "%d times ", var62); - else - *_attackBuffer = 0; - } - - int16 var68 = _items[unk_monsterField5_itemId]._attackType + 1; - int16 var6A = getRandom(3); - if (var5E == 2) - snprintf(_characterNamePt1, 5, "The "); - else - *_characterNamePt1 = 0; - - if (var7E == 2) - _enemyNamePt1 = "The "; - else - _enemyNamePt1 = ""; - - _enemyNamePt2 = kEncounters[_mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._monsterRef]._name; - _characterNamePt2 = _npcBuf[_teamCharId[var7E]]._name; - _nameBuffer = _items[unk_monsterField5_itemId]._name; - if (checkSpecialItemsOnCurrentPlace(unk_monsterField5_itemId)) { - // handleFight - check damages - Start - if (var62 == 0) { - snprintf((char *)_messageToBePrinted, 400, "%s%s %s at %s%s with %s %s, but misses!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2.c_str(), kPossessive[var70], _nameBuffer.c_str()); - } else if (hitPoints <= 0) { - snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s, but does no damage!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2.c_str(), _attackBuffer, kPossessive[var70], _nameBuffer.c_str()); - } else if (hitPoints == 1) { - snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s for 1 point", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2.c_str(), _attackBuffer, kPossessive[var70], _nameBuffer.c_str()); - if (_npcBuf[_teamCharId[var7E]]._hitPoints <= 0) - getDeathTypeDescription(var7E + 1000, monsterGroupIdOrMonsterId); - else - strncat((char *)_messageToBePrinted, "!", 2); - } else { - snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s for %d points", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2.c_str(), _attackBuffer, kPossessive[var70], _nameBuffer.c_str(), hitPoints); - if (_npcBuf[_teamCharId[var7E]]._hitPoints <= 0) - getDeathTypeDescription(var7E + 1000, monsterGroupIdOrMonsterId); - else - strncat((char *)_messageToBePrinted, "!", 2); - } - // handleFight - check damages - End - - // handleFight - Add reaction text - start - if (var62 != 0 && originalDamage > 0 && getRandom(100) <= 35 && _npcBuf[_teamCharId[var7E]]._hitPoints > 0) { - if (_npcBuf[_teamCharId[var7E]]._hitPoints - 5 <= originalDamage) { - addReactionText(0); - } else if (_npcBuf[_teamCharId[var7E]]._hitPoints < _npcBuf[_teamCharId[var7E]]._maxHP / 8) { - addReactionText(1); - } else if (_npcBuf[_teamCharId[var7E]]._hitPoints < _npcBuf[_teamCharId[var7E]]._maxHP / 4) { - addReactionText(2); - } else if (_npcBuf[_teamCharId[var7E]]._hitPoints < _npcBuf[_teamCharId[var7E]]._maxHP / 2) { - addReactionText(3); - } else if (_npcBuf[_teamCharId[var7E]]._hitPoints < _npcBuf[_teamCharId[var7E]]._maxHP / 3) { - // CHECKME: Doesn't make any sense to check /3 after /2... I don't get it - addReactionText(4); - } else if (_npcBuf[_teamCharId[var7E]]._maxHP / 8 >= originalDamage) { - addReactionText(5); - } else if (originalDamage == 0 && getRandom(100) < 35) { - addReactionText(6); - } - } - // handleFight - Add reaction text - end - - // handleFight - Check armor - start - if (var76 != 0 && var62 != 0 && _npcBuf[_teamCharId[var7E]]._hitPoints > 0) { - char buffer[80]; - memset(buffer, 0, 80); - if (damagePointsAbsorbed <= 1) - snprintf(buffer, 80, " %s%s's armor absorbs 1 point!", _characterNamePt1, _characterNamePt2.c_str()); - else - snprintf(buffer, 80, " %s%s's armor absorbs %d points!", _characterNamePt1, _characterNamePt2.c_str(), damagePointsAbsorbed); - - strncat((char *)_messageToBePrinted, buffer, 80); - varInt = (originalDamage + damagePointsAbsorbed) / 10; - sub1D8C2(_teamCharId[var7E], varInt); - } - // handleFight - Check armor - end - - // handleFight - Check effect - start - char buffer[80]; - memset(buffer, 0, 80); - switch (_items[unk_monsterField5_itemId].field_16) { - case 1: - if (getRandom(100) < 20) { - _teamCharStatus[var7E]._status = 1; - _teamCharStatus[var7E]._duration = getRandom(10); - snprintf(buffer, 80, " %s%s falls asleep!", _characterNamePt1, _characterNamePt2.c_str()); - strncat((char *)_messageToBePrinted, buffer, 80); - } - break; - case 2: - if (getRandom(100) < 20) { - _teamCharStatus[var7E]._status = 2; - _teamCharStatus[var7E]._duration = getRandom(10); - snprintf(buffer, 80, " %s%s is frozen!", _characterNamePt1, _characterNamePt2.c_str()); - strncat((char *)_messageToBePrinted, buffer, 80); - } - break; - case 5: - case 6: - if (getRandom(100) < 20) { - snprintf(buffer, 80, " %s%s's life energy is gone!", _characterNamePt1, _characterNamePt2.c_str()); - strncat((char *)_messageToBePrinted, buffer, 80); - _npcBuf[_teamCharId[var7E]]._hitPoints = 0; - } - break; - default: - break; - } - // handleFight - Check effect - end - } else { - snprintf((char *)_messageToBePrinted, 400, "%s%s tries to use %s %s, but it doesn't work!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPossessive[var70], _nameBuffer.c_str()); - } - genericGenerateSound(_items[unk_monsterField5_itemId]._attackType, var62); - sub1C219(_messageToBePrinted, 1, 2, true); - } - // handleFight - Loop on var7E - End - } - } else if (_mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._pictureRef[var86] > 0 && _stru32686[monsterGroupIdOrMonsterId]._field0[var86]) { - --_stru32686[monsterGroupIdOrMonsterId]._field2[var86]; - if (_stru32686[monsterGroupIdOrMonsterId]._field2[var86] <= 0) { - _enemyNamePt2 = kEncounters[_mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._monsterRef]._name; - int16 var70 = kEncounters[_mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._monsterRef]._nameArticle; - if (var70 == 2) - _enemyNamePt1 = "The "; - else - _enemyNamePt1 = ""; - - switch (_stru32686[monsterGroupIdOrMonsterId]._field0[var86]) { - case 1: - snprintf((char *)_messageToBePrinted, 400, "%s%s wakes up!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str()); - break; - case 2: - snprintf((char *)_messageToBePrinted, 400, "%s%s thaws out!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str()); - break; - default: - snprintf((char *)_messageToBePrinted, 400, "%s%s recovers!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str()); - break; - } - _stru32686[monsterGroupIdOrMonsterId]._field0[var86] = 0; - sub1C219(_messageToBePrinted, 1, 2, true); - } - } - } - // handleFight - Loop on var86 - End - } - } - - sub174A0(); - sub1BE9A(monsterId); - } - - resetTeamMonsterIdArray(); - _ongoingFightFl = false; - displayAnimFrames(0xFE, true); - return true; -} - void EfhEngine::displayMenuItemString(int16 menuBoxId, int16 thisBoxId, int16 minX, int16 maxX, int16 minY, const char *str) { debug("displayMenuItemString %d %d %d->%d %d %s", menuBoxId, thisBoxId, minX, maxX, minY, str); diff --git a/engines/efh/efh.h b/engines/efh/efh.h index b4cdb33a08f1..8dca9fa52548 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -304,8 +304,6 @@ class EfhEngine : public Engine { void displaySmallMap(int16 posX, int16 posY); void displayLargeMap(int16 posX, int16 posY); void drawScreen(); - uint8 *script_readNumberArray(uint8 *buffer, int16 destArraySize, int16 *destArray); - uint8 *script_getNumber(uint8 *srcBuffer, int16 *retval); void removeObject(int16 charId, int16 objectId); void totalPartyKill(); void removeCharacterFromTeam(int16 teamMemberId); @@ -316,7 +314,6 @@ class EfhEngine : public Engine { bool giveItemTo(int16 charId, int16 objectId, int16 altCharId); int16 chooseCharacterToReplace(); int16 handleCharacterJoining(); - int16 script_parse(uint8 *str, int16 posX, int16 posY, int16 maxX, int16 maxY, bool flag); void drawText(uint8 *impPtr, int16 posX, int16 posY, int16 maxX, int16 maxY, bool flag); void displayMiddleLeftTempText(uint8 *impArray, bool flag); void sub15A28(int16 arg0, int16 arg2); @@ -375,7 +372,6 @@ class EfhEngine : public Engine { void sub1C4CA(bool WhiteFl); void displayCombatMenu(int16 charId); void drawCombatScreen(int16 charId, bool whiteFl, bool forceDrawFl); - void handleFight_checkEndEffect(int16 charId); int16 sub1DEC8(int16 groupNumber); int16 getCharacterScore(int16 charId, int16 itemId); bool checkSpecialItemsOnCurrentPlace(int16 itemId); @@ -392,13 +388,8 @@ class EfhEngine : public Engine { bool characterSearchesMonsterCorpse(int16 charId, int16 monsterId); void getXPAndSearchCorpse(int16 charId, Common::String namePt1, Common::String namePt2, int16 monsterId); void addReactionText(int16 id); - void handleFight_lastAction_A(int16 teamCharId); - void handleFight_lastAction_D(int16 teamCharId); - void handleFight_lastAction_H(int16 teamCharId); - void handleFight_lastAction_U(int16 teamCharId); char getFightMessageLastCharacter(char *message); void sub1D8C2(int16 charId, int16 damage); - bool handleFight(int16 monsterId); void displayMenuItemString(int16 menuBoxId, int16 thisBoxId, int16 minX, int16 maxX, int16 minY, const char *str); void displayStatusMenu(int16 windowId); void countRightWindowItems(int16 menuId, int16 charId); @@ -422,6 +413,14 @@ class EfhEngine : public Engine { int16 handleStatusMenu(int16 gameMode, int16 charId); bool checkMonsterCollision(); + // Fight + bool handleFight(int16 monsterId); + void handleFight_checkEndEffect(int16 charId); + void handleFight_lastAction_A(int16 teamCharId); + void handleFight_lastAction_D(int16 teamCharId); + void handleFight_lastAction_H(int16 teamCharId); + void handleFight_lastAction_U(int16 teamCharId); + // Files int32 readFileToBuffer(Common::String &filename, uint8 *destBuffer); void readAnimInfo(); @@ -474,6 +473,11 @@ class EfhEngine : public Engine { // Savegames void synchronize(Common::Serializer &s); + // Script + uint8 *script_readNumberArray(uint8 *buffer, int16 destArraySize, int16 *destArray); + uint8 *script_getNumber(uint8 *srcBuffer, int16 *retval); + int16 script_parse(uint8 *str, int16 posX, int16 posY, int16 maxX, int16 maxY, bool flag); + // Utils void setDefaultNoteDuration(); void decryptImpFile(bool techMapFl); diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp new file mode 100644 index 000000000000..0c1a6a10210e --- /dev/null +++ b/engines/efh/fight.cpp @@ -0,0 +1,651 @@ +/* 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 "efh/efh.h" + +namespace Efh { + +bool EfhEngine::handleFight(int16 monsterId) { + debug("handleFight %d", monsterId); + + int16 var8C = 0; + _ongoingFightFl = true; + + sub1BE89(monsterId); + + if (_teamMonsterIdArray[0] == -1) { + resetTeamMonsterIdArray(); + _ongoingFightFl = false; + displayAnimFrames(0xFE, true); + return true; + } + + drawCombatScreen(0, false, true); + + for (bool mainLoopCond = false; !mainLoopCond;) { + if (isTPK()) { + resetTeamMonsterIdArray(); + _ongoingFightFl = false; + displayAnimFrames(0xFE, true); + return false; + } + + if (_teamMonsterIdArray[0] == -1) { + resetTeamMonsterIdArray(); + _ongoingFightFl = false; + displayAnimFrames(0xFE, true); + return true; + } + + int16 varInt = getTeamMonsterAnimId(); + displayAnimFrames(varInt, true); + for (int counter = 0; counter < _teamSize; ++counter) { + _word32680[counter] = 100; + _word32482[counter] = 65; + } + + if (!sub1CB27()) { + resetTeamMonsterIdArray(); + _ongoingFightFl = false; + totalPartyKill(); + displayAnimFrames(0xFE, true); + return false; + } + + for (int counter = 0; counter < _teamSize; ++counter) { + if (_teamLastAction[counter] == 0x52) // 'R' + mainLoopCond = true; + } + + sub1CDFA(); + sub1C219(nullptr, 2, 1, false); + + for (uint counter = 0; counter < 8; ++counter) { + int16 monsterGroupIdOrMonsterId = _stru3244C[counter]._field0; + if (monsterGroupIdOrMonsterId == -1) + continue; + if (monsterGroupIdOrMonsterId > 999) { // Team Member + monsterGroupIdOrMonsterId -= 1000; + if (!isTeamMemberStatusNormal(monsterGroupIdOrMonsterId)) { + handleFight_checkEndEffect(monsterGroupIdOrMonsterId); + } else { + switch (_teamLastAction[monsterGroupIdOrMonsterId]) { + case 0x41: // 'A'ttack + handleFight_lastAction_A(monsterGroupIdOrMonsterId); + break; + case 0x44: // 'D'efend + handleFight_lastAction_D(monsterGroupIdOrMonsterId); + break; + case 0x48: // 'H'ide + handleFight_lastAction_H(monsterGroupIdOrMonsterId); + break; + case 0x55: // 'U'se + handleFight_lastAction_U(monsterGroupIdOrMonsterId); + break; + default: + break; + } + } + } else if (unkFct_checkMonsterField8(monsterGroupIdOrMonsterId, true)) { + // handleFight - Loop on var86 - Start + for (uint var86 = 0; var86 < 9; ++var86) { + if (isMonsterActive(monsterGroupIdOrMonsterId, var86)) { + int16 unk_monsterField5_itemId = _mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._itemId_Weapon; + if (unk_monsterField5_itemId == 0xFF) + unk_monsterField5_itemId = 0x3F; + int16 teamMemberId = -1; + int16 var54; + if (_items[unk_monsterField5_itemId]._range < 3) { + for (uint var84 = 0; var84 < 10; ++var84) { + teamMemberId = getRandom(_teamSize) - 1; + if (checkWeaponRange(_teamMonsterIdArray[monsterGroupIdOrMonsterId], unk_monsterField5_itemId) && isTeamMemberStatusNormal(teamMemberId) && getRandom(100) < _word32680[teamMemberId]) { + break; + } + teamMemberId = -1; + } + var54 = teamMemberId + 1; + } else { + teamMemberId = 0; + var54 = _teamSize; + } + if (teamMemberId != -1) { + // handleFight - Loop on var7E - Start + for (int16 var7E = teamMemberId; var7E < var54; ++var7E) { + if (_teamCharId[var7E] == -1 || !isTeamMemberStatusNormal(var7E)) + continue; + + int16 var76 = getRandom(getEquipmentDefense(_teamCharId[var7E], false)); + varInt = _teamMonsterIdArray[monsterGroupIdOrMonsterId]; + int16 var70 = kEncounters[_mapMonsters[varInt]._monsterRef]._nameArticle; + int16 var5E = _npcBuf[_teamCharId[var7E]]._possessivePronounSHL6 >> 6; + varInt = _items[unk_monsterField5_itemId].field_13; + _word32482[var7E] += (varInt * 5); + int16 var62 = 0; + int16 hitPoints = 0; + int16 originalDamage = 0; + int16 damagePointsAbsorbed = 0; + int16 var64 = _mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._field_1 * _items[unk_monsterField5_itemId]._attacks; + for (int var84 = 0; var84 < var64; ++var84) { + // handleFight - Loop var84 on var64 (objectId) - Start + if (getRandom(100) > _word32482[var7E]) + continue; + + ++var62; + + if (hasAdequateDefense_2(_teamCharId[var7E], _items[unk_monsterField5_itemId]._attackType)) + continue; + + int16 var7C = getRandom(_items[unk_monsterField5_itemId]._damage); + varInt = var7C - var76; + + if (varInt > 0) { + damagePointsAbsorbed += var76; + originalDamage += varInt; + } else { + damagePointsAbsorbed += var7C; + } + // handleFight - Loop var84 on var64 (objectId) - End + } + + if (originalDamage < 0) + originalDamage = 0; + + hitPoints = originalDamage + damagePointsAbsorbed; + if (!checkSpecialItemsOnCurrentPlace(unk_monsterField5_itemId)) + var62 = 0; + + if (var62 > 0) { + _npcBuf[_teamCharId[var7E]]._hitPoints -= originalDamage; + if (var62 > 1) + snprintf(_attackBuffer, 20, "%d times ", var62); + else + *_attackBuffer = 0; + } + + int16 var68 = _items[unk_monsterField5_itemId]._attackType + 1; + int16 var6A = getRandom(3); + if (var5E == 2) + snprintf(_characterNamePt1, 5, "The "); + else + *_characterNamePt1 = 0; + + if (var7E == 2) + _enemyNamePt1 = "The "; + else + _enemyNamePt1 = ""; + + _enemyNamePt2 = kEncounters[_mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._monsterRef]._name; + _characterNamePt2 = _npcBuf[_teamCharId[var7E]]._name; + _nameBuffer = _items[unk_monsterField5_itemId]._name; + if (checkSpecialItemsOnCurrentPlace(unk_monsterField5_itemId)) { + // handleFight - check damages - Start + if (var62 == 0) { + snprintf((char *)_messageToBePrinted, 400, "%s%s %s at %s%s with %s %s, but misses!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2.c_str(), kPossessive[var70], _nameBuffer.c_str()); + } else if (hitPoints <= 0) { + snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s, but does no damage!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2.c_str(), _attackBuffer, kPossessive[var70], _nameBuffer.c_str()); + } else if (hitPoints == 1) { + snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s for 1 point", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2.c_str(), _attackBuffer, kPossessive[var70], _nameBuffer.c_str()); + if (_npcBuf[_teamCharId[var7E]]._hitPoints <= 0) + getDeathTypeDescription(var7E + 1000, monsterGroupIdOrMonsterId); + else + strncat((char *)_messageToBePrinted, "!", 2); + } else { + snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s for %d points", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2.c_str(), _attackBuffer, kPossessive[var70], _nameBuffer.c_str(), hitPoints); + if (_npcBuf[_teamCharId[var7E]]._hitPoints <= 0) + getDeathTypeDescription(var7E + 1000, monsterGroupIdOrMonsterId); + else + strncat((char *)_messageToBePrinted, "!", 2); + } + // handleFight - check damages - End + + // handleFight - Add reaction text - start + if (var62 != 0 && originalDamage > 0 && getRandom(100) <= 35 && _npcBuf[_teamCharId[var7E]]._hitPoints > 0) { + if (_npcBuf[_teamCharId[var7E]]._hitPoints - 5 <= originalDamage) { + addReactionText(0); + } else if (_npcBuf[_teamCharId[var7E]]._hitPoints < _npcBuf[_teamCharId[var7E]]._maxHP / 8) { + addReactionText(1); + } else if (_npcBuf[_teamCharId[var7E]]._hitPoints < _npcBuf[_teamCharId[var7E]]._maxHP / 4) { + addReactionText(2); + } else if (_npcBuf[_teamCharId[var7E]]._hitPoints < _npcBuf[_teamCharId[var7E]]._maxHP / 2) { + addReactionText(3); + } else if (_npcBuf[_teamCharId[var7E]]._hitPoints < _npcBuf[_teamCharId[var7E]]._maxHP / 3) { + // CHECKME: Doesn't make any sense to check /3 after /2... I don't get it + addReactionText(4); + } else if (_npcBuf[_teamCharId[var7E]]._maxHP / 8 >= originalDamage) { + addReactionText(5); + } else if (originalDamage == 0 && getRandom(100) < 35) { + addReactionText(6); + } + } + // handleFight - Add reaction text - end + + // handleFight - Check armor - start + if (var76 != 0 && var62 != 0 && _npcBuf[_teamCharId[var7E]]._hitPoints > 0) { + char buffer[80]; + memset(buffer, 0, 80); + if (damagePointsAbsorbed <= 1) + snprintf(buffer, 80, " %s%s's armor absorbs 1 point!", _characterNamePt1, _characterNamePt2.c_str()); + else + snprintf(buffer, 80, " %s%s's armor absorbs %d points!", _characterNamePt1, _characterNamePt2.c_str(), damagePointsAbsorbed); + + strncat((char *)_messageToBePrinted, buffer, 80); + varInt = (originalDamage + damagePointsAbsorbed) / 10; + sub1D8C2(_teamCharId[var7E], varInt); + } + // handleFight - Check armor - end + + // handleFight - Check effect - start + char buffer[80]; + memset(buffer, 0, 80); + switch (_items[unk_monsterField5_itemId].field_16) { + case 1: + if (getRandom(100) < 20) { + _teamCharStatus[var7E]._status = 1; + _teamCharStatus[var7E]._duration = getRandom(10); + snprintf(buffer, 80, " %s%s falls asleep!", _characterNamePt1, _characterNamePt2.c_str()); + strncat((char *)_messageToBePrinted, buffer, 80); + } + break; + case 2: + if (getRandom(100) < 20) { + _teamCharStatus[var7E]._status = 2; + _teamCharStatus[var7E]._duration = getRandom(10); + snprintf(buffer, 80, " %s%s is frozen!", _characterNamePt1, _characterNamePt2.c_str()); + strncat((char *)_messageToBePrinted, buffer, 80); + } + break; + case 5: + case 6: + if (getRandom(100) < 20) { + snprintf(buffer, 80, " %s%s's life energy is gone!", _characterNamePt1, _characterNamePt2.c_str()); + strncat((char *)_messageToBePrinted, buffer, 80); + _npcBuf[_teamCharId[var7E]]._hitPoints = 0; + } + break; + default: + break; + } + // handleFight - Check effect - end + } else { + snprintf((char *)_messageToBePrinted, 400, "%s%s tries to use %s %s, but it doesn't work!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPossessive[var70], _nameBuffer.c_str()); + } + genericGenerateSound(_items[unk_monsterField5_itemId]._attackType, var62); + sub1C219(_messageToBePrinted, 1, 2, true); + } + // handleFight - Loop on var7E - End + } + } else if (_mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._pictureRef[var86] > 0 && _stru32686[monsterGroupIdOrMonsterId]._field0[var86]) { + --_stru32686[monsterGroupIdOrMonsterId]._field2[var86]; + if (_stru32686[monsterGroupIdOrMonsterId]._field2[var86] <= 0) { + _enemyNamePt2 = kEncounters[_mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._monsterRef]._name; + int16 var70 = kEncounters[_mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._monsterRef]._nameArticle; + if (var70 == 2) + _enemyNamePt1 = "The "; + else + _enemyNamePt1 = ""; + + switch (_stru32686[monsterGroupIdOrMonsterId]._field0[var86]) { + case 1: + snprintf((char *)_messageToBePrinted, 400, "%s%s wakes up!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str()); + break; + case 2: + snprintf((char *)_messageToBePrinted, 400, "%s%s thaws out!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str()); + break; + default: + snprintf((char *)_messageToBePrinted, 400, "%s%s recovers!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str()); + break; + } + _stru32686[monsterGroupIdOrMonsterId]._field0[var86] = 0; + sub1C219(_messageToBePrinted, 1, 2, true); + } + } + } + // handleFight - Loop on var86 - End + } + } + + sub174A0(); + sub1BE9A(monsterId); + } + + resetTeamMonsterIdArray(); + _ongoingFightFl = false; + displayAnimFrames(0xFE, true); + return true; +} + +void EfhEngine::handleFight_checkEndEffect(int16 charId) { + debug("handleFight_checkEndEffect %d", charId); + + // In the original, this function is part of handleFight. + // It has been split for readability purposes. + if (_teamCharStatus[charId]._status == 0) + return; + if (--_teamCharStatus[charId]._duration != 0) + return; + + // At this point : The status is different to 0 (normal) and the effect duration is finally 0 (end of effect) + _enemyNamePt2 = _npcBuf[_teamCharId[charId]]._name; + if ((_npcBuf[_teamCharId[charId]]._possessivePronounSHL6 >> 6) == 2) { + _enemyNamePt1 = "The "; + } else { + _enemyNamePt1 = ""; + } + + // End of effect message depends on the type of effect + switch (_teamCharStatus[charId]._status) { + case 1: + snprintf((char *)_messageToBePrinted, 400, "%s%s wakes up!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str()); + break; + case 2: + snprintf((char *)_messageToBePrinted, 400, "%s%s thaws out!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str()); + break; + default: + snprintf((char *)_messageToBePrinted, 400, "%s%s recovers!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str()); + break; + } + + // The character status is back to normal + _teamCharStatus[charId]._status = 0; + + // Finally, display the message + sub1C219(_messageToBePrinted, 1, 2, true); +} + +void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { + debug("handleFight_lastAction_A %d", teamCharId); + + // In the original, this function is part of handleFight. + // It has been split for readability purposes. + + int16 unk_monsterField5_itemId = sub1C80A(_teamCharId[teamCharId], 9, true); + if (unk_monsterField5_itemId == 0x7FFF) + unk_monsterField5_itemId = 0x3F; + int16 monsterGroupNumber = _teamNextAttack[teamCharId]; + if (monsterGroupNumber == 0x64) + monsterGroupNumber = 0; + + if (monsterGroupNumber == -1) + return; + int16 var58; + if (_items[unk_monsterField5_itemId]._range == 4) + var58 = 5; + else + var58 = monsterGroupNumber + 1; + + int16 var54; + int16 teamMemberId; + if (_items[unk_monsterField5_itemId]._range < 3) { + teamMemberId = sub1DEC8(monsterGroupNumber); + var54 = teamMemberId + 1; + } else { + teamMemberId = 0; + var54 = 9; + } + + if (teamMemberId != -1) { + bool var6E = true; + for (int16 groupId = monsterGroupNumber; groupId < var58; ++groupId) { + if (_teamMonsterIdArray[groupId] == -1) + continue; + + for (int16 var7E = teamMemberId; var7E < var54; ++var7E) { + if (isMonsterActive(groupId, var7E) && var6E) { + int16 var5C; + if (unkFct_checkMonsterField8(groupId, true)) { + sub1E028(groupId, 9, true); + _unkArray2C8AA[0] += 500; + var5C = -1; + } else + var5C = 0; + + int16 var76 = getRandom(_mapMonsters[_teamMonsterIdArray[groupId]]._field_6); + int16 varInt = _teamCharId[teamCharId]; + int16 var51 = _npcBuf[varInt]._possessivePronounSHL6; + var51 >>= 6; + int16 var70 = var51; + varInt = _teamMonsterIdArray[groupId]; + int16 var5E = kEncounters[_mapMonsters[varInt]._monsterRef]._nameArticle; + int16 charScore = getCharacterScore(_teamCharId[teamCharId], unk_monsterField5_itemId); + int16 var80 = _mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E]; + int16 var62 = 0; + int16 hitPoints = 0; + int16 originalDamage = 0; + int16 damagePointsAbsorbed = 0; + int16 var64 = _items[unk_monsterField5_itemId]._attacks * _npcBuf[_teamCharId[teamCharId]]._speed; + + // Action A - Loop var84 - Start + for (int var84 = 0; var84 < var64; ++var84) { + if (getRandom(100) < charScore) { + ++var62; + if (!hasAdequateDefense(_teamMonsterIdArray[groupId], _items[unk_monsterField5_itemId]._attackType)) { + int16 var7C = getRandom(_items[unk_monsterField5_itemId]._damage); + varInt = var7C - var76; + if (varInt > 0) { + originalDamage += varInt; + damagePointsAbsorbed += var76; + } else { + damagePointsAbsorbed += var7C; + } + } + } + } + // Action A - Loop var84 - End + + if (originalDamage < 0) + originalDamage = 0; + + hitPoints = originalDamage + damagePointsAbsorbed; + + if (!checkSpecialItemsOnCurrentPlace(unk_monsterField5_itemId)) + var62 = 0; + + if (var62 > 0) { + _mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] -= originalDamage; + if (var62 > 1) { + snprintf(_attackBuffer, 20, "%d times ", var62); + } else { + *_attackBuffer = 0; + } + } + int16 var68 = _items[unk_monsterField5_itemId]._attackType + 1; + int16 var6A = getRandom(3) - 1; + if (var5E == 2) { + snprintf(_characterNamePt1, 5, "The "); + } else { + *_characterNamePt1 = 0; + } + + if (var70 == 2) { + _enemyNamePt1 = "The "; + } else { + _enemyNamePt1 = ""; + } + + _characterNamePt2 = kEncounters[_mapMonsters[_teamMonsterIdArray[groupId]]._monsterRef]._name; + _enemyNamePt2 = _npcBuf[_teamCharId[teamCharId]]._name; + _nameBuffer = _items[unk_monsterField5_itemId]._name; + if (checkSpecialItemsOnCurrentPlace(unk_monsterField5_itemId)) { + // Action A - Check damages - Start + if (var62 == 0) { + snprintf((char *)_messageToBePrinted, 400, "%s%s %s at %s%s with %s %s, but misses!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2.c_str(), kPossessive[var70], _nameBuffer.c_str()); + } else if (hitPoints <= 0) { + snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s, but does no damage!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2.c_str(), _attackBuffer, kPossessive[var70], _nameBuffer.c_str()); + } else if (hitPoints == 1) { + snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s for 1 point", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2.c_str(), _attackBuffer, kPossessive[var70], _nameBuffer.c_str()); + if (_mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] <= 0) { + getDeathTypeDescription(groupId, teamCharId + 1000); + getXPAndSearchCorpse(_teamCharId[teamCharId], _enemyNamePt1, _enemyNamePt2, _teamMonsterIdArray[groupId]); + } else { + strncat((char *)_messageToBePrinted, "!", 2); + } + } else { + snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s for %d points", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2.c_str(), _attackBuffer, kPossessive[var70], _nameBuffer.c_str(), hitPoints); + if (_mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] <= 0) { + getDeathTypeDescription(groupId, teamCharId + 1000); + getXPAndSearchCorpse(_teamCharId[teamCharId], _enemyNamePt1, _enemyNamePt2, _teamMonsterIdArray[groupId]); + } else { + strncat((char *)_messageToBePrinted, "!", 2); + } + } + // Action A - Check damages - End + + // Action A - Add reaction text - Start + if (var62 != 0 && originalDamage > 0 && getRandom(100) <= 35 && _mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] > 0) { + if (_mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] - 5 <= originalDamage) { + addReactionText(0); + } else if (_mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] < var80 / 8) { + addReactionText(1); + } else if (_mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] < var80 / 4) { + addReactionText(2); + } else if (_mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] < var80 / 2) { + addReactionText(3); + } else if (_mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] < var80 / 3) { + // CHECKME: Doesn't make any sense to check /3 after /2... I don't get it + addReactionText(4); + } else if (var80 / 8 >= originalDamage) { + addReactionText(5); + } else if (originalDamage == 0 && getRandom(100) < 35) { + addReactionText(6); + } + } + // Action A - Add reaction text - End + + // Action A - Add armor absorb text - Start + if (var76 && var62 && _mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] > 0) { + char buffer[80]; + memset(buffer, 0, 80); + if (damagePointsAbsorbed <= 1) + snprintf(buffer, 80, " %s%s's armor absorbs 1 point!", _characterNamePt1, _characterNamePt2.c_str()); + else + snprintf(buffer, 80, " %s%s's armor absorbs %d points!", _characterNamePt1, _characterNamePt2.c_str(), damagePointsAbsorbed); + + strncat((char *)_messageToBePrinted, buffer, 80); + } + // Action A - Add armor absorb text - End + + if (var5C) + strncat((char *)_messageToBePrinted, " Your actions do not go un-noticed...", 400); + + // Action A - Check item durability - Start + varInt = _teamCharId[teamCharId]; + var64 = sub1C80A(varInt, 9, false); + if (var64 != 0x7FFF && (_npcBuf[varInt]._inventory[var64]._stat1 & 0x7F) != 0x7F) { + var51 = _npcBuf[varInt]._inventory[var64]._stat1 & 0x7F; + --var51; + if (var51 <= 0) { + char buffer[80]; + memset(buffer, 0, 80); + snprintf(buffer, 80, " * %s%s's %s breaks!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), _nameBuffer.c_str()); + strncat((char *)_messageToBePrinted, buffer, 80); + setCharacterObjectToBroken(varInt, var64); + var6E = false; + } else { + _npcBuf[varInt]._inventory[var64]._stat1 = (_npcBuf[varInt]._inventory[var64]._stat1 & 80) + var51; + } + } + // Action A - Check item durability - End + + // Action A - Check effect - Start + if (_items[unk_monsterField5_itemId].field_16 == 1 && _mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] > 0) { + if (getRandom(100) < 35) { + _stru32686[var7E]._field0[groupId] = 1; + _stru32686[var7E]._field2[groupId] = getRandom(10); + char buffer[80]; + memset(buffer, 0, 80); + snprintf(buffer, 80, " %s%s falls asleep!", _characterNamePt1, _characterNamePt2.c_str()); + strncat((char *)_messageToBePrinted, buffer, 80); + } + } else if (_items[unk_monsterField5_itemId].field_16 == 2 && _mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] > 0) { + _stru32686[var7E]._field0[groupId] = 2; + _stru32686[var7E]._field2[groupId] = getRandom(10); + char buffer[80]; + memset(buffer, 0, 80); + snprintf(buffer, 80, " %s%s is frozen!", _characterNamePt1, _characterNamePt2.c_str()); + strncat((char *)_messageToBePrinted, buffer, 80); + } + // Action A - Check effect - End + } else { + snprintf((char *)_messageToBePrinted, 400, "%s%s tries to use %s %s, but it doesn't work!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPossessive[var70], _nameBuffer.c_str()); + } + + genericGenerateSound(_items[unk_monsterField5_itemId]._attackType, var62); + sub1C219(_messageToBePrinted, 1, 2, true); + } + } + } + } +} + +void EfhEngine::handleFight_lastAction_D(int16 teamCharId) { + debug("handleFight_lastAction_D %d", teamCharId); + + _word32482[teamCharId] -= 40; + _enemyNamePt2 = _npcBuf[_teamCharId[teamCharId]]._name; + int16 var70 = _npcBuf[_teamCharId[teamCharId]]._possessivePronounSHL6 >> 6; + + if (var70 == 2) + _enemyNamePt1 = "The "; + else + _enemyNamePt1 = ""; + + snprintf((char *)_messageToBePrinted, 400, "%s%s prepares to defend %sself!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPersonal[var70]); + sub1C219(_messageToBePrinted, 1, 2, true); +} + +void EfhEngine::handleFight_lastAction_H(int16 teamCharId) { + debug("handleFight_lastAction_H %d", teamCharId); + + // In the original, this function is part of handleFight. + // It has been split for readability purposes. + + _word32680[teamCharId] -= 50; + _enemyNamePt2 = _npcBuf[_teamCharId[teamCharId]]._name; + int16 var70 = _npcBuf[_teamCharId[teamCharId]]._possessivePronounSHL6 >> 6; + + if (var70 == 2) + _enemyNamePt1 = "The "; + else + _enemyNamePt1 = ""; + + snprintf((char *)_messageToBePrinted, 400, "%s%s attempts to hide %sself!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPersonal[var70]); + sub1C219(_messageToBePrinted, 1, 2, true); +} + +void EfhEngine::handleFight_lastAction_U(int16 teamCharId) { + debug("handleFight_lastAction_U %d", teamCharId); + + // In the original, this function is part of handleFight. + // It has been split for readability purposes. + int16 unk_monsterField5_itemId = _npcBuf[_teamCharId[teamCharId]]._inventory[_word31780[teamCharId]]._ref; + _enemyNamePt2 = _npcBuf[_teamCharId[teamCharId]]._name; + _nameBuffer = _items[unk_monsterField5_itemId]._name; + int16 var70 = _npcBuf[_teamCharId[teamCharId]]._possessivePronounSHL6 >> 6; + if (var70 == 2) + _enemyNamePt1 = "The "; + else + _enemyNamePt1 = ""; + + snprintf((char *)_messageToBePrinted, 400, "%s%s uses %s %s! ", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPossessive[var70], _nameBuffer.c_str()); + sub1C219(_messageToBePrinted, 1, 2, true); +} + +} // End of namespace Efh diff --git a/engines/efh/module.mk b/engines/efh/module.mk index aee8803c5258..c5e7ac247dd9 100644 --- a/engines/efh/module.mk +++ b/engines/efh/module.mk @@ -3,9 +3,11 @@ MODULE := engines/efh MODULE_OBJS = \ constants.o \ efh.o \ + fight.o \ files.o \ graphics.o \ savegames.o \ + script.o \ utils.o \ metaengine.o diff --git a/engines/efh/script.cpp b/engines/efh/script.cpp new file mode 100644 index 000000000000..8712f7725d91 --- /dev/null +++ b/engines/efh/script.cpp @@ -0,0 +1,500 @@ +/* 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/system.h" +#include "efh/efh.h" + +namespace Efh { + +uint8 *EfhEngine::script_readNumberArray(uint8 *srcBuffer, int16 destArraySize, int16 *destArray) { + debug("script_readNumberArray"); + + uint8 *buffer = srcBuffer; + for (int i = 0; i < destArraySize; ++i) { + buffer++; + buffer = script_getNumber(buffer, &destArray[i]); + } + + return buffer; +} + +uint8 *EfhEngine::script_getNumber(uint8 *srcBuffer, int16 *retval) { + debug("script_getNumber"); + + uint8 *buffer = srcBuffer; + int16 var2 = 0; + for (;;) { + uint8 curChar = *buffer; + if (curChar < 0x30 || curChar > 0x39) { + *retval = var2; + return buffer; + } + var2 = var2 * 10 + curChar - 0x30; + buffer++; + } +} + +int16 EfhEngine::script_parse(uint8 *stringBuffer, int16 posX, int16 posY, int16 maxX, int16 maxY, bool flag) { + debug("script_parse %s %d-%d %d-%d %s", (char *)stringBuffer, posX, posY, maxX, maxY, flag ? "True" : "False"); + + bool doneFlag = false; + int16 var_F2 = -1; + int16 var_F0 = 0xFF; + int16 var_EE = 0xFF; + uint16 curLineNb = 0; + int16 numbLines = (1 + maxY - posY) / 9; + int16 width = maxX - posX; + int16 spaceWidth = getStringWidth(" "); + uint8 *buffer = stringBuffer; + char nextWord[80]; + char curLine[150]; + memset(nextWord, 0, sizeof(nextWord)); + memset(curLine, 0, sizeof(curLine)); + int16 curWordPos = 0; + setTextPos(posX, curLineNb * 9 + posY); + + while (!doneFlag) { + uint8 curChar = *buffer; + if (curChar != 0x5E && curChar != 0x20 && curChar != 0 && curChar != 0x7C) { + var_F2 = 0; + nextWord[curWordPos++] = curChar; + ++buffer; + continue; + } + + if (curChar != 0x5E) { + if (curChar == 0) + doneFlag = true; + else if (curChar == 0x7C) + var_F2 = 0; + + nextWord[curWordPos] = 0; + int16 widthNextWord = getStringWidth(nextWord); + int16 widthCurrentLine = spaceWidth + getStringWidth(curLine); + + if (widthCurrentLine + widthNextWord > width || curChar == 0x7C) { + if (curLineNb >= numbLines) { + doneFlag = true; + } else { + if (var_F2 == 0) + displayStringAtTextPos(curLine); + + *curLine = 0; + strncpy(curLine, nextWord, 80); + strncat(curLine, " ", 2); + ++curLineNb; + setTextPos(posX, posY + curLineNb * 9); + curWordPos = 0; + } + } else { + strncat(curLine, nextWord, 80); + strncat(curLine, " ", 2); + curWordPos = 0; + } + ++buffer; + continue; + } + + // At this point, curChar == 0x5E + ++buffer; + int16 opCode = 0; + buffer = script_getNumber(buffer, &opCode); + int16 scriptNumberArray[10]; + memset(scriptNumberArray, 0, sizeof(scriptNumberArray)); + + switch (opCode) { + case 0x00: + // Enter room { full Place Id, posX, posY } + buffer = script_readNumberArray(buffer, 3, scriptNumberArray); + if (flag) { + if (_largeMapFlag) { + _largeMapFlag = false; + _techDataId_MapPosX = _mapPosX; + _techDataId_MapPosY = _mapPosY; + } + _oldMapPosX = _mapPosX = scriptNumberArray[1]; + _oldMapPosY = _mapPosY = scriptNumberArray[2]; + loadPlacesFile(scriptNumberArray[0], false); + _word2C880 = true; + _redrawNeededFl = true; + } + break; + case 0x01: + // Exit room { } + if (flag) { + _largeMapFlag = true; + _oldMapPosX = _mapPosX = _techDataId_MapPosX; + _oldMapPosY = _mapPosY = _techDataId_MapPosY; + _word2C880 = true; + _redrawNeededFl = true; + } + break; + case 0x02: + // Change map. { map number, posX, posY } + buffer = script_readNumberArray(buffer, 3, scriptNumberArray); + if (flag) { + if (_word2C8D7) + writeTechAndMapFiles(); + _oldMapPosX = _mapPosX = scriptNumberArray[1]; + _oldMapPosY = _mapPosY = scriptNumberArray[2]; + loadTechMapImp(scriptNumberArray[0]); + _largeMapFlag = true; + _word2C880 = true; + _redrawNeededFl = true; + doneFlag = true; + } + break; + case 0x03: + buffer = script_readNumberArray(buffer, 4, scriptNumberArray); + if (flag) { + int16 var110 = scriptNumberArray[2] - scriptNumberArray[0]; + int16 var10E = scriptNumberArray[3] - scriptNumberArray[1]; + + _mapPosX = getRandom(var110) + scriptNumberArray[0] - 1; + _mapPosY = getRandom(var10E) + scriptNumberArray[1] - 1; + _word2C880 = true; + _redrawNeededFl = true; + } + break; + case 0x04: + buffer = script_readNumberArray(buffer, 2, scriptNumberArray); + if (flag) { + _mapPosX = scriptNumberArray[0]; + _mapPosY = scriptNumberArray[1]; + _word2C880 = true; + _redrawNeededFl = true; + } + break; + case 0x05: + buffer = script_readNumberArray(buffer, 4, scriptNumberArray); + if (flag) { + int16 var110 = _teamCharId[scriptNumberArray[0]]; + if (var110 != -1) { + int16 var10E = scriptNumberArray[1]; + _npcBuf[var110]._activeScore[var10E] += scriptNumberArray[2] & 0xFF; + _npcBuf[var110]._activeScore[var10E] -= scriptNumberArray[3] & 0xFF; + } + } + break; + case 0x06: + buffer = script_readNumberArray(buffer, 2, scriptNumberArray); + if (flag) { + int16 var110 = _teamCharId[scriptNumberArray[0]]; + if (var110 != -1) { + int16 var10E = scriptNumberArray[1]; + _npcBuf[var110]._activeScore[var10E] = scriptNumberArray[1]; + } + } + break; + case 0x07: + if (flag) { + totalPartyKill(); + // emptyFunction(2); + } + break; + case 0x08: + buffer = script_readNumberArray(buffer, 1, scriptNumberArray); + if (flag && scriptNumberArray[0] != -1) { + _npcBuf[_teamCharId[scriptNumberArray[0]]]._hitPoints = 0; + } + break; + case 0x09: + buffer = script_readNumberArray(buffer, 2, scriptNumberArray); + if (flag) { + int16 var110 = _teamCharId[scriptNumberArray[0]]; + if (var110 != -1) { + int16 var10E = getRandom(scriptNumberArray[1]); + _npcBuf[var110]._hitPoints += var10E; + if (_npcBuf[var110]._hitPoints > _npcBuf[var110]._maxHP) + _npcBuf[var110]._hitPoints = _npcBuf[var110]._maxHP; + } + } + break; + case 0x0A: + buffer = script_readNumberArray(buffer, 1, scriptNumberArray); + if (flag) { + int16 var110 = _teamCharId[scriptNumberArray[0]]; + if (var110 != -1) { + _npcBuf[var110]._hitPoints = _npcBuf[var110]._maxHP; + } + } + break; + case 0x0B: + buffer = script_readNumberArray(buffer, 2, scriptNumberArray); + if (flag) { + int16 var110 = _teamCharId[scriptNumberArray[0]]; + if (var110 != -1) { + int16 var10E = getRandom(scriptNumberArray[1]); + _npcBuf[var110]._hitPoints -= var10E; + if (_npcBuf[var110]._hitPoints < 0) + _npcBuf[var110]._hitPoints = 0; + } + } + break; + case 0x0C: + buffer = script_readNumberArray(buffer, 2, scriptNumberArray); + if (flag) { + int16 var110 = scriptNumberArray[0]; + bool found = false; + for (int counter = 0; counter < _teamSize && !found; ++counter) { + for (uint objectId = 0; objectId < 10; ++objectId) { + if (_npcBuf[_teamCharId[counter]]._inventory[objectId]._ref == var110) { + removeObject(_teamCharId[counter], objectId); + found = true; + break; + } + } + } + } + break; + case 0x0D: + // Put item in inventory { objectId } + buffer = script_readNumberArray(buffer, 1, scriptNumberArray); + if (flag) { + int16 var110 = scriptNumberArray[0]; + for (int counter = 0; counter < _teamSize; ++counter) { + if (giveItemTo(_teamCharId[counter], var110, 0xFF)) + break; + } + } + break; + case 0x0E: + buffer = script_readNumberArray(buffer, 3, scriptNumberArray); + if (flag) { + int16 var110 = scriptNumberArray[0]; + bool found = false; + for (int counter = 0; counter < _teamSize && !found; ++counter) { + for (uint objectId = 0; objectId < 10; ++objectId) { + if (_npcBuf[_teamCharId[counter]]._inventory[objectId]._ref == var110) { + found = true; + break; + } + } + } + + if (found) + var_F0 = scriptNumberArray[1]; + else + var_F0 = scriptNumberArray[2]; + } + break; + case 0x0F: + buffer = script_readNumberArray(buffer, 3, scriptNumberArray); + if (flag) { + int16 var110 = scriptNumberArray[0]; + if (isCharacterATeamMember(var110)) + var_F0 = scriptNumberArray[1]; + else + var_F0 = scriptNumberArray[2]; + } + break; + case 0x10: + buffer = script_readNumberArray(buffer, 1, scriptNumberArray); + if (flag) + var_F0 = scriptNumberArray[0]; + + break; + case 0x11: + if (flag) + _unkArray2C8AA[0] = 0; + break; + case 0x12: + // Guess : disable special tile { } + if (flag) { + int16 var110 = sub151FD(_mapPosX, _mapPosY); + if (var110 != -1) + _mapUnknown[var110]._posX = 0xFF; + } + break; + case 0x13: + buffer = script_readNumberArray(buffer, 3, scriptNumberArray); + if (flag && _largeMapFlag) { + _word2C87A = true; + loadPlacesFile(scriptNumberArray[0], false); + sub15A28(scriptNumberArray[1], scriptNumberArray[2]); + sub2455E(scriptNumberArray[0], scriptNumberArray[1], scriptNumberArray[2]); + var_F0 = -1; + } + break; + case 0x14: + // Add character to team { charId } + buffer = script_readNumberArray(buffer, 1, scriptNumberArray); + if (flag) { + int16 var110 = scriptNumberArray[0]; + if (!isCharacterATeamMember(var110)) + var_EE = var110; + var_F0 = -1; + } + break; + case 0x15: + buffer = script_readNumberArray(buffer, 2, scriptNumberArray); + if (flag) { + _oldMapPosX = _mapPosX = scriptNumberArray[0]; + _oldMapPosY = _mapPosY = scriptNumberArray[1]; + _largeMapFlag = true; + _redrawNeededFl = true; + } + break; + case 0x16: + buffer = script_readNumberArray(buffer, 1, scriptNumberArray); + if (flag) { + int16 var110 = scriptNumberArray[0]; + // TODO: This "if" is useless, it's doing just the same loop and if statement. Consider removing it. + if (isCharacterATeamMember(var110)) { + for (uint counter = 0; counter < 3; ++counter) { + if (_teamCharId[counter] == var110) { + removeCharacterFromTeam(counter); + break; + } + } + } + } + break; + case 0x17: + buffer = script_readNumberArray(buffer, 1, scriptNumberArray); + if (flag) { + int16 var110 = scriptNumberArray[0]; + displayAnimFrames(var110, true); + } + break; + case 0x18: + buffer = script_readNumberArray(buffer, 2, scriptNumberArray); + if (flag) { + int16 var110 = scriptNumberArray[1] - scriptNumberArray[0] + 1; + bool found = false; + var110 = getRandom(var110) + scriptNumberArray[0] - 1; + int16 counter; + for (counter = 0; counter < _teamSize; ++counter) { + if (giveItemTo(_teamCharId[counter], var110, 0xFF)) { + found = true; + break; + } + } + + if (!found) { + drawMapWindow(); + displayFctFullScreen(); + drawMapWindow(); + var110 = sub1C219((uint8 *)"Nothing...", 1, 2, true); + displayFctFullScreen(); + } else { + _enemyNamePt2 = _npcBuf[_teamCharId[counter]]._name; + _nameBuffer = _items[var110]._name; + snprintf(curLine, 150, "%s finds a %s!", _enemyNamePt2.c_str(), _nameBuffer.c_str()); + drawMapWindow(); + displayFctFullScreen(); + drawMapWindow(); + var110 = sub1C219((uint8 *)curLine, 1, 2, true); + displayFctFullScreen(); + } + + var110 = sub151FD(_mapPosX, _mapPosY); + if (var110 != -1) { + _mapUnknown[var110]._posX = 0xFF; + } + _redrawNeededFl = true; + } + break; + case 0x19: + buffer = script_readNumberArray(buffer, 3, scriptNumberArray); + if (flag) { + if (_largeMapFlag) { + _mapGameMap[scriptNumberArray[0]][scriptNumberArray[1]] = scriptNumberArray[2] & 0xFF; + } else { + _curPlace[scriptNumberArray[0]][scriptNumberArray[1]] = scriptNumberArray[2] & 0xFF; + } + } + break; + case 0x1A: + buffer = script_readNumberArray(buffer, 2, scriptNumberArray); + if (flag) { + int16 var110 = sub151FD(scriptNumberArray[0], scriptNumberArray[1]); + if (var110 != -1) { + _mapUnknown[var110]._posX = 0xFF; + } + } + break; + case 0x1B: + buffer = script_readNumberArray(buffer, 3, scriptNumberArray); + if (flag) { + int16 var110 = sub151FD(scriptNumberArray[0], scriptNumberArray[1]); + if (var110 != -1) { + _mapUnknown[var110]._posX = 0xFF; + } + _mapUnknown[scriptNumberArray[2]]._posX = scriptNumberArray[0]; + _mapUnknown[scriptNumberArray[2]]._posY = scriptNumberArray[1]; + } + break; + case 0x1C: + buffer = script_readNumberArray(buffer, 1, scriptNumberArray); + if (flag) { + _history[scriptNumberArray[0]] = 0xFF; + } + break; + case 0x1D: + buffer = script_readNumberArray(buffer, 1, scriptNumberArray); + if (flag) { + _history[scriptNumberArray[0]] = 0; + } + break; + case 0x1E: + // Dialog with condition { historyId, dialogId1, dialogId2 } + buffer = script_readNumberArray(buffer, 3, scriptNumberArray); + if (flag) { + if (_history[scriptNumberArray[0]] == 0) + var_F0 = scriptNumberArray[2]; + else + var_F0 = scriptNumberArray[1]; + } + break; + case 0x1F: + buffer = script_readNumberArray(buffer, 1, scriptNumberArray); + if (flag) + _unkArray2C8AA[0] = scriptNumberArray[0]; + + break; + case 0x20: + if (flag) { + handleWinSequence(); + _system->quit(); + } + default: + break; + } + } + + if (*curLine != 0 && curLineNb < numbLines && var_F2 == 0) + displayStringAtTextPos(curLine); + + if (var_EE != 0xFF) { + displayLowStatusScreen(true); + int16 teamSlot = handleCharacterJoining(); + if (teamSlot > -1) { + _teamCharId[teamSlot] = var_EE; + } + refreshTeamSize(); + } + + return var_F0; +} + +} // End of namespace Efh + From 452eedce4e7764edfa85d1f9553b0dd984539dd6 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Thu, 1 Dec 2022 08:51:03 +0100 Subject: [PATCH 181/412] EFH: move some more functions out of efh.cpp, some renaming --- engines/efh/efh.cpp | 187 +----------------------------------------- engines/efh/efh.h | 28 ++++--- engines/efh/fight.cpp | 88 +++++++++++++++++++- engines/efh/module.mk | 1 + engines/efh/sound.cpp | 124 ++++++++++++++++++++++++++++ 5 files changed, 229 insertions(+), 199 deletions(-) create mode 100644 engines/efh/sound.cpp diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 46a5c9da2d9b..bf57fa124364 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -263,7 +263,7 @@ EfhEngine::EfhEngine(OSystem *syst, const ADGameDescription *gd) : Engine(syst), _teamCharStatus[i]._status = 0; _teamCharStatus[i]._duration = 0; _unkArray2C8AA[i] = 0; - _word32680[i] = 0; + _teamPctVisible[i] = 0; _word32482[i] = 0; _teamNextAttack[i] = -1; _word31780[i] = 0; @@ -2666,88 +2666,6 @@ int8 EfhEngine::sub15581(int16 mapPosX, int16 mapPosY, int16 arg4) { return _tileFact[imageSetId]._field0; } -bool EfhEngine::sub1BC74(int16 monsterId, int16 teamMonsterId) { - debug("sub1BC74 %d %d", monsterId, teamMonsterId); - - for (int counter = 0; counter < teamMonsterId; ++counter) { - if (_teamMonsterIdArray[counter] == monsterId) - return true; - } - return false; -} - -void EfhEngine::sub1BCA7(int16 monsterTeamId) { - debug("sub1BCA7 %d", monsterTeamId); - - int16 counter = 0; - if (monsterTeamId != -1 && countPictureRef(monsterTeamId, false) > 0) { - counter = 1; - _teamMonsterIdArray[0] = monsterTeamId; - } - - for (int counter2 = 1; counter2 <= 3; ++counter2) { - if (counter >= 5) - break; - - for (uint monsterId = 0; monsterId < 64; ++monsterId) { - if (_mapMonsters[monsterId]._guess_fullPlaceId == 0xFF) - continue; - - if (((_mapMonsters[monsterId]._possessivePronounSHL6 & 0x3F) != 0x3F || isCharacterATeamMember(_mapMonsters[monsterId]._field_1)) && (_mapMonsters[monsterId]._possessivePronounSHL6 & 0x3F) > 0x3D) - continue; - - if (!checkIfMonsterOnSameLargeMapPlace(monsterId)) - continue; - - bool var6 = false; - for (uint counter3 = 0; counter3 < 9; ++counter3) { - if (_mapMonsters[monsterId]._pictureRef[counter3] > 0) { - var6 = true; - break; - } - } - - if (var6) { - if (computeMonsterGroupDistance(monsterId) <= counter2 && !sub1BC74(monsterId, counter)) { - _teamMonsterIdArray[counter] = monsterId; - if (++counter >= 5) - break; - } - } - } - } - - if (counter > 4) - return; - - for (uint id = counter; id < 5; ++id) - _teamMonsterIdArray[id] = -1; -} - -void EfhEngine::reset_stru32686() { - debug("reset_stru32686"); - for (uint counter1 = 0; counter1 < 5; ++counter1) { - for (uint counter2 = 0; counter2 < 9; ++counter2) { - _stru32686[counter1]._field0[counter2] = 0; - _stru32686[counter1]._field2[counter2] = 0; - } - } -} - -void EfhEngine::sub1BE89(int16 monsterId) { - debug("sub1BE89 %d", monsterId); - sub1BCA7(monsterId); - reset_stru32686(); -} - -void EfhEngine::resetTeamMonsterIdArray() { - debug("resetTeamMonsterIdArray"); - - for (int i = 0; i < 5; ++i) { - _teamMonsterIdArray[i] = -1; - } -} - bool EfhEngine::isTeamMemberStatusNormal(int16 teamMemberId) { debug("isTeamMemberStatusNormal %d", teamMemberId); @@ -3385,103 +3303,6 @@ bool EfhEngine::checkSpecialItemsOnCurrentPlace(int16 itemId) { } } -void EfhEngine::generateSound1(int arg0, int arg2, int duration) { - warning("STUB: generateSound1 %d %d %d", arg0, arg2, duration); -} - -void EfhEngine::generateSound2(int startFreq, int endFreq, int arg4) { - warning("STUB: generateSound2 %d %d %d", startFreq, endFreq, arg4); - - // Arg4 doesn't seem to be used. -} - -void EfhEngine::generateSound3() { - warning("STUB: generateSound3"); -} - -void EfhEngine::generateSound4(int arg0) { - warning("STUB: generateSound4 %d", arg0); -} - -void EfhEngine::generateSound5(int arg0) { - warning("STUB: generateSound5 %d", arg0); -} - -void EfhEngine::generateSound(int16 soundType) { - switch (soundType) { - case 5: - generateSound3(); - break; - case 9: - generateSound1(20, 888, 3000); - generateSound1(20, 888, 3000); - break; - case 10: - generateSound5(1); - break; - case 13: - generateSound2(256, 4096, 18); - break; - case 14: - generateSound2(20, 400, 100); - break; - case 15: - generateSound2(100, 888, 88); - break; - case 16: - generateSound1(2000, 6096, 1500); - break; - case 17: - generateSound4(1); - break; - default: - // Not implemented because not used by the engine - break; - } -} - -void EfhEngine::genericGenerateSound(int16 soundType, int16 repeatCount) { - if (repeatCount <= 0) - return; - - switch (soundType) { - case 0: - case 1: - case 2: - generateSound(5); - break; - case 3: - case 4: - case 6: - generateSound(9); - break; - case 5: - case 7: - generateSound(13); - break; - case 8: - case 9: - case 10: - generateSound(10); - generateSound(9); - break; - case 14: - generateSound(14); - break; - case 11: - case 12: - case 13: - for (int counter = 0; counter < repeatCount; ++counter) { - generateSound(17); - } - break; - case 15: - generateSound(16); - default: - break; - } -} - bool EfhEngine::hasAdequateDefense(int16 monsterId, uint8 attackType) { debug("hasAdequateDefense %d %d", monsterId, attackType); @@ -4636,9 +4457,9 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me strncat((char *)_messageToBePrinted, buffer1.c_str(), 80); } - _word32680[teamCharId] -= 50; - if (_word32680[teamCharId] < 0) - _word32680[teamCharId] = 0; + _teamPctVisible[teamCharId] -= 50; + if (_teamPctVisible[teamCharId] < 0) + _teamPctVisible[teamCharId] = 0; } varA6 = true; diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 8dca9fa52548..cff5abd15971 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -354,11 +354,6 @@ class EfhEngine : public Engine { void sub22AA8(int16 arg0); bool sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemId, int16 arg8, int16 imageSetId); int8 sub15581(int16 mapPosX, int16 mapPosY, int16 arg4); - bool sub1BC74(int16 monsterId, int16 teamMonsterId); - void sub1BCA7(int16 monsterTeamId); - void reset_stru32686(); - void sub1BE89(int16 monsterId); - void resetTeamMonsterIdArray(); bool isTeamMemberStatusNormal(int16 id); void sub1CDFA(); void redrawScreenForced(); @@ -375,13 +370,6 @@ class EfhEngine : public Engine { int16 sub1DEC8(int16 groupNumber); int16 getCharacterScore(int16 charId, int16 itemId); bool checkSpecialItemsOnCurrentPlace(int16 itemId); - void generateSound1(int arg0, int arg2, int duration); - void generateSound2(int startFreq, int endFreq, int arg4); - void generateSound3(); - void generateSound4(int arg0); - void generateSound5(int arg0); - void generateSound(int16 soundType); - void genericGenerateSound(int16 soundType, int16 repeatCount); bool hasAdequateDefense(int16 monsterId, uint8 attackType); bool hasAdequateDefense_2(int16 charId, uint8 attackType); void getDeathTypeDescription(int16 attackerId, int16 victimId); @@ -420,6 +408,11 @@ class EfhEngine : public Engine { void handleFight_lastAction_D(int16 teamCharId); void handleFight_lastAction_H(int16 teamCharId); void handleFight_lastAction_U(int16 teamCharId); + bool sub1BC74(int16 monsterId, int16 teamMonsterId); + void sub1BCA7(int16 monsterTeamId); + void reset_stru32686(); + void sub1BE89(int16 monsterId); + void resetTeamMonsterIdArray(); // Files int32 readFileToBuffer(Common::String &filename, uint8 *destBuffer); @@ -478,6 +471,15 @@ class EfhEngine : public Engine { uint8 *script_getNumber(uint8 *srcBuffer, int16 *retval); int16 script_parse(uint8 *str, int16 posX, int16 posY, int16 maxX, int16 maxY, bool flag); + // Sound + void generateSound1(int arg0, int arg2, int duration); + void generateSound2(int startFreq, int endFreq, int arg4); + void generateSound3(); + void generateSound4(int arg0); + void generateSound5(int arg0); + void generateSound(int16 soundType); + void genericGenerateSound(int16 soundType, int16 repeatCount); + // Utils void setDefaultNoteDuration(); void decryptImpFile(bool techMapFl); @@ -593,7 +595,7 @@ class EfhEngine : public Engine { bool _statusMenuActive; int16 _menuDepth; int16 _menuItemCounter; - int16 _word32680[3]; + int16 _teamPctVisible[3]; int16 _word32482[3]; int16 _teamNextAttack[3]; int16 _word31780[3]; diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index 0c1a6a10210e..9a69241cc0a0 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -58,7 +58,7 @@ bool EfhEngine::handleFight(int16 monsterId) { int16 varInt = getTeamMonsterAnimId(); displayAnimFrames(varInt, true); for (int counter = 0; counter < _teamSize; ++counter) { - _word32680[counter] = 100; + _teamPctVisible[counter] = 100; _word32482[counter] = 65; } @@ -116,7 +116,7 @@ bool EfhEngine::handleFight(int16 monsterId) { if (_items[unk_monsterField5_itemId]._range < 3) { for (uint var84 = 0; var84 < 10; ++var84) { teamMemberId = getRandom(_teamSize) - 1; - if (checkWeaponRange(_teamMonsterIdArray[monsterGroupIdOrMonsterId], unk_monsterField5_itemId) && isTeamMemberStatusNormal(teamMemberId) && getRandom(100) < _word32680[teamMemberId]) { + if (checkWeaponRange(_teamMonsterIdArray[monsterGroupIdOrMonsterId], unk_monsterField5_itemId) && isTeamMemberStatusNormal(teamMemberId) && getRandom(100) < _teamPctVisible[teamMemberId]) { break; } teamMemberId = -1; @@ -617,7 +617,7 @@ void EfhEngine::handleFight_lastAction_H(int16 teamCharId) { // In the original, this function is part of handleFight. // It has been split for readability purposes. - _word32680[teamCharId] -= 50; + _teamPctVisible[teamCharId] -= 50; _enemyNamePt2 = _npcBuf[_teamCharId[teamCharId]]._name; int16 var70 = _npcBuf[_teamCharId[teamCharId]]._possessivePronounSHL6 >> 6; @@ -648,4 +648,86 @@ void EfhEngine::handleFight_lastAction_U(int16 teamCharId) { sub1C219(_messageToBePrinted, 1, 2, true); } +bool EfhEngine::sub1BC74(int16 monsterId, int16 teamMonsterId) { + debug("sub1BC74 %d %d", monsterId, teamMonsterId); + + for (int counter = 0; counter < teamMonsterId; ++counter) { + if (_teamMonsterIdArray[counter] == monsterId) + return true; + } + return false; +} + +void EfhEngine::sub1BCA7(int16 monsterTeamId) { + debug("sub1BCA7 %d", monsterTeamId); + + int16 counter = 0; + if (monsterTeamId != -1 && countPictureRef(monsterTeamId, false) > 0) { + counter = 1; + _teamMonsterIdArray[0] = monsterTeamId; + } + + for (int counter2 = 1; counter2 <= 3; ++counter2) { + if (counter >= 5) + break; + + for (uint monsterId = 0; monsterId < 64; ++monsterId) { + if (_mapMonsters[monsterId]._guess_fullPlaceId == 0xFF) + continue; + + if (((_mapMonsters[monsterId]._possessivePronounSHL6 & 0x3F) != 0x3F || isCharacterATeamMember(_mapMonsters[monsterId]._field_1)) && (_mapMonsters[monsterId]._possessivePronounSHL6 & 0x3F) > 0x3D) + continue; + + if (!checkIfMonsterOnSameLargeMapPlace(monsterId)) + continue; + + bool var6 = false; + for (uint counter3 = 0; counter3 < 9; ++counter3) { + if (_mapMonsters[monsterId]._pictureRef[counter3] > 0) { + var6 = true; + break; + } + } + + if (var6) { + if (computeMonsterGroupDistance(monsterId) <= counter2 && !sub1BC74(monsterId, counter)) { + _teamMonsterIdArray[counter] = monsterId; + if (++counter >= 5) + break; + } + } + } + } + + if (counter > 4) + return; + + for (uint id = counter; id < 5; ++id) + _teamMonsterIdArray[id] = -1; +} + +void EfhEngine::reset_stru32686() { + debug("reset_stru32686"); + for (uint counter1 = 0; counter1 < 5; ++counter1) { + for (uint counter2 = 0; counter2 < 9; ++counter2) { + _stru32686[counter1]._field0[counter2] = 0; + _stru32686[counter1]._field2[counter2] = 0; + } + } +} + +void EfhEngine::sub1BE89(int16 monsterId) { + debug("sub1BE89 %d", monsterId); + sub1BCA7(monsterId); + reset_stru32686(); +} + +void EfhEngine::resetTeamMonsterIdArray() { + debug("resetTeamMonsterIdArray"); + + for (int i = 0; i < 5; ++i) { + _teamMonsterIdArray[i] = -1; + } +} + } // End of namespace Efh diff --git a/engines/efh/module.mk b/engines/efh/module.mk index c5e7ac247dd9..9cfeeb35953c 100644 --- a/engines/efh/module.mk +++ b/engines/efh/module.mk @@ -8,6 +8,7 @@ MODULE_OBJS = \ graphics.o \ savegames.o \ script.o \ + sound.o \ utils.o \ metaengine.o diff --git a/engines/efh/sound.cpp b/engines/efh/sound.cpp new file mode 100644 index 000000000000..8da1fa700789 --- /dev/null +++ b/engines/efh/sound.cpp @@ -0,0 +1,124 @@ +/* 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 "efh/efh.h" + +namespace Efh { + +void EfhEngine::generateSound1(int arg0, int arg2, int duration) { + warning("STUB: generateSound1 %d %d %d", arg0, arg2, duration); +} + +void EfhEngine::generateSound2(int startFreq, int endFreq, int arg4) { + warning("STUB: generateSound2 %d %d %d", startFreq, endFreq, arg4); + + // Arg4 doesn't seem to be used. +} + +void EfhEngine::generateSound3() { + warning("STUB: generateSound3"); +} + +void EfhEngine::generateSound4(int arg0) { + warning("STUB: generateSound4 %d", arg0); +} + +void EfhEngine::generateSound5(int arg0) { + warning("STUB: generateSound5 %d", arg0); +} + +void EfhEngine::generateSound(int16 soundType) { + switch (soundType) { + case 5: + generateSound3(); + break; + case 9: + generateSound1(20, 888, 3000); + generateSound1(20, 888, 3000); + break; + case 10: + generateSound5(1); + break; + case 13: + generateSound2(256, 4096, 18); + break; + case 14: + generateSound2(20, 400, 100); + break; + case 15: + generateSound2(100, 888, 88); + break; + case 16: + generateSound1(2000, 6096, 1500); + break; + case 17: + generateSound4(1); + break; + default: + // Not implemented because not used by the engine + break; + } +} + +void EfhEngine::genericGenerateSound(int16 soundType, int16 repeatCount) { + if (repeatCount <= 0) + return; + + switch (soundType) { + case 0: + case 1: + case 2: + generateSound(5); + break; + case 3: + case 4: + case 6: + generateSound(9); + break; + case 5: + case 7: + generateSound(13); + break; + case 8: + case 9: + case 10: + generateSound(10); + generateSound(9); + break; + case 14: + generateSound(14); + break; + case 11: + case 12: + case 13: + for (int counter = 0; counter < repeatCount; ++counter) { + generateSound(17); + } + break; + case 15: + generateSound(16); + default: + break; + } +} + +} // End of namespace Efh + From 88299f79675357da92a54f3d86d3a76ec1dc5e20 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sat, 3 Dec 2022 22:31:15 +0100 Subject: [PATCH 182/412] EFH: turn _messageToBePrinted into a Common::String --- engines/efh/efh.cpp | 299 +++++++++++++++++++---------------------- engines/efh/efh.h | 9 +- engines/efh/fight.cpp | 91 +++++-------- engines/efh/script.cpp | 26 ++-- 4 files changed, 189 insertions(+), 236 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index bf57fa124364..df5a37aa46ac 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -308,7 +308,7 @@ EfhEngine::EfhEngine(OSystem *syst, const ADGameDescription *gd) : Engine(syst), _word3273A[i] = 0; } - memset(_messageToBePrinted, 0, 400); + _messageToBePrinted = ""; for (int i = 0; i < 8; ++i) _stru3244C[i].init(); @@ -1330,7 +1330,7 @@ void EfhEngine::drawText(uint8 *srcPtr, int16 posX, int16 posY, int16 maxX, int1 uint16 stringIdx = 0; uint8 *impPtr = srcPtr; - memset(_messageToBePrinted, 0, 200); + _messageToBePrinted = ""; for (;;) { uint8 curChar = *impPtr; @@ -1339,12 +1339,14 @@ void EfhEngine::drawText(uint8 *srcPtr, int16 posX, int16 posY, int16 maxX, int1 break; if (curChar == 0x0D) { - _messageToBePrinted[stringIdx++] = ' '; + _messageToBePrinted += " "; + stringIdx++; ++impPtr; } else if (curChar == 0x0A) { ++impPtr; } else { - _messageToBePrinted[stringIdx++] = curChar; + _messageToBePrinted += curChar; + stringIdx++; ++impPtr; } } @@ -1427,8 +1429,8 @@ void EfhEngine::sub2455E(int16 arg0, int16 arg2, int16 arg4) { } } -int16 EfhEngine::sub1C219(uint8 *str, int16 menuType, int16 arg4, bool displayTeamWindowFl) { - debug("sub1C219 %s %d %d %s", (char *)str, menuType, arg4, displayTeamWindowFl ? "True" : "False"); +int16 EfhEngine::sub1C219(Common::String str, int16 menuType, int16 arg4, bool displayTeamWindowFl) { + debug("sub1C219 %s %d %d %s", str.c_str(), menuType, arg4, displayTeamWindowFl ? "True" : "False"); int16 varA = 0xFF; int16 minX, maxX, minY, maxY; @@ -1466,7 +1468,7 @@ int16 EfhEngine::sub1C219(uint8 *str, int16 menuType, int16 arg4, bool displayTe } drawColoredRect(minX, minY, maxX, maxY, 0); - if (str) + if (str.size()) varA = script_parse(str, minX, minY, maxX, maxY, true); if (displayTeamWindowFl) @@ -1478,7 +1480,7 @@ int16 EfhEngine::sub1C219(uint8 *str, int16 menuType, int16 arg4, bool displayTe _word2C87A = false; else { drawColoredRect(minX, minY, maxX, maxY, 0); - if (str) + if (str.size()) int16 varC = script_parse(str, minX, minY, maxX, maxY, false); } @@ -2442,8 +2444,8 @@ void EfhEngine::sub221D2(int16 monsterId) { void EfhEngine::sub22AA8(int16 arg0) { debug("sub22AA8 %d", arg0); - int16 var8, varA, varC, varE; - var8 = varA = varC = varE = 0; + int16 var8, varA, varC, stringIdx; + var8 = varA = varC = stringIdx = 0; if (arg0 <= 0xFE) { if (_tempTextPtr) { @@ -2465,8 +2467,8 @@ void EfhEngine::sub22AA8(int16 arg0) { if (var12 == nullptr) break; - if (varE == 0) - memset(_messageToBePrinted, 0, 400); + if (stringIdx == 0) + _messageToBePrinted = ""; do { switch (*var12) { case 0x00: @@ -2474,9 +2476,9 @@ void EfhEngine::sub22AA8(int16 arg0) { break; case 0x0D: case 0x20: - _messageToBePrinted[varE++] = 0x20; + _messageToBePrinted += " "; + stringIdx++; if (++varC >= 350) { - _messageToBePrinted[varE] = 0; var8 = -1; } break; @@ -2485,10 +2487,10 @@ void EfhEngine::sub22AA8(int16 arg0) { varA = -1; break; case 0x7C: - _messageToBePrinted[varE++] = 0x7C; + _messageToBePrinted += Common::String(0x7C); + stringIdx++; varC += 20; if (varC >= 350) { - _messageToBePrinted[varE] = 0; var8 = -1; } break; @@ -2496,7 +2498,8 @@ void EfhEngine::sub22AA8(int16 arg0) { var8 = -1; break; default: - _messageToBePrinted[varE++] = *var12; + _messageToBePrinted += Common::String(*var12); + stringIdx++; varC++; break; } @@ -2504,11 +2507,11 @@ void EfhEngine::sub22AA8(int16 arg0) { int16 var2 = 0xFF ; if (var8 != 0 || varA != 0) { var8 = 0; - _messageToBePrinted[varE] = 0; - varE = 0; + stringIdx = 0; varC = 0; - if (*_messageToBePrinted == 0x5E || *_messageToBePrinted == 0) { - if (*_messageToBePrinted == 0x5E) { + uint8 firstChar = _messageToBePrinted.firstChar(); + if (firstChar == 0x5E || firstChar == 0) { + if (firstChar == 0x5E) { var2 = script_parse(_messageToBePrinted, 0, 0, 319, 199, true); _word2C87A = false; } @@ -2776,7 +2779,7 @@ int16 EfhEngine::sub1C956(int16 charId, int16 unkFied18Val, bool arg4) { for (uint counter = 0; counter < 2; ++counter) { drawCombatScreen(charId, true, false); if (_teamMonsterIdArray[1] != -1) - sub1C219((uint8 *)"Select Monster Group:", 3, 0, false); + sub1C219("Select Monster Group:", 3, 0, false); if (counter == 0) displayFctFullScreen(); @@ -2884,7 +2887,7 @@ bool EfhEngine::sub1CB27() { case 28: case 29: case 30: - sub1C219((uint8 *)"Select Character:", 3, 1, false); + sub1C219("Select Character:", 3, 1, false); _teamNextAttack[counter1] = selectOtherCharFromTeam(); break; @@ -3160,7 +3163,7 @@ void EfhEngine::drawCombatScreen(int16 charId, bool whiteFl, bool forceDrawFl) { displayCenteredString("Combat", 128, 303, 9); drawColoredRect(200, 112, 278, 132, 0); displayCenteredString("'T' for Terrain", 128, 303, 117); - sub1C219(nullptr, 1, 0, false); + sub1C219("", 1, 0, false); sub1C4CA(whiteFl); displayCombatMenu(charId); displayLowStatusScreen(false); @@ -3373,20 +3376,18 @@ void EfhEngine::getDeathTypeDescription(int16 attackerId, int16 victimId) { } int16 rndDescrForDeathType = getRandom((3)) - 1; - char buffer[80]; - memset(buffer, 0, 80); - snprintf(buffer, 80, "DUDE IS TOAST!"); + Common::String tmpStr = "DUDE IS TOAST!"; switch (deathType) { case 0: switch (rndDescrForDeathType) { case 0: - snprintf(buffer, 80, ", killing %s!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", killing %s!", kPersonal[possessivePronoun]); break; case 1: - snprintf(buffer, 80, ", slaughtering %s!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", slaughtering %s!", kPersonal[possessivePronoun]); break; case 2: - snprintf(buffer, 80, ", annihilating %s!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", annihilating %s!", kPersonal[possessivePronoun]); break; default: break; @@ -3395,13 +3396,13 @@ void EfhEngine::getDeathTypeDescription(int16 attackerId, int16 victimId) { case 1: switch (rndDescrForDeathType) { case 0: - snprintf(buffer, 80, ", cutting %s in two!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", cutting %s in two!", kPersonal[possessivePronoun]); break; case 1: - snprintf(buffer, 80, ", dicing %s into small cubes!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", dicing %s into small cubes!", kPersonal[possessivePronoun]); break; case 2: - snprintf(buffer, 80, ", butchering %s into lamb chops!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", butchering %s into lamb chops!", kPersonal[possessivePronoun]); break; default: break; @@ -3410,13 +3411,13 @@ void EfhEngine::getDeathTypeDescription(int16 attackerId, int16 victimId) { case 2: switch (rndDescrForDeathType) { case 0: - snprintf(buffer, 80, ", piercing %s heart!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", piercing %s heart!", kPersonal[possessivePronoun]); break; case 1: - snprintf(buffer, 80, ", leaving %s a spouting mass of blood!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", leaving %s a spouting mass of blood!", kPersonal[possessivePronoun]); break; case 2: - snprintf(buffer, 80, ", popping %s like a zit!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", popping %s like a zit!", kPersonal[possessivePronoun]); break; default: break; @@ -3425,13 +3426,13 @@ void EfhEngine::getDeathTypeDescription(int16 attackerId, int16 victimId) { case 3: switch (rndDescrForDeathType) { case 0: - snprintf(buffer, 80, ", pulping %s head over a wide area!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", pulping %s head over a wide area!", kPersonal[possessivePronoun]); break; case 1: - snprintf(buffer, 80, ", smashing %s into a meat patty!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", smashing %s into a meat patty!", kPersonal[possessivePronoun]); break; case 2: - snprintf(buffer, 80, ", squashing %s like a ripe tomato!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", squashing %s like a ripe tomato!", kPersonal[possessivePronoun]); break; default: break; @@ -3440,13 +3441,13 @@ void EfhEngine::getDeathTypeDescription(int16 attackerId, int16 victimId) { case 4: switch (rndDescrForDeathType) { case 0: - snprintf(buffer, 80, ", totally incinerating %s!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", totally incinerating %s!", kPersonal[possessivePronoun]); break; case 1: - snprintf(buffer, 80, ", reducing %s to a pile of ash!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", reducing %s to a pile of ash!", kPersonal[possessivePronoun]); break; case 2: - snprintf(buffer, 80, ", leaving a blistered mass of flesh behind!"); + tmpStr = Common::String::format(", leaving a blistered mass of flesh behind!"); break; default: break; @@ -3456,13 +3457,13 @@ void EfhEngine::getDeathTypeDescription(int16 attackerId, int16 victimId) { switch (rndDescrForDeathType) { case 0: // The original has a typo: popscicle - snprintf(buffer, 80, ", turning %s into a popsicle!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", turning %s into a popsicle!", kPersonal[possessivePronoun]); break; case 1: - snprintf(buffer, 80, ", encasing %s in a block of ice!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", encasing %s in a block of ice!", kPersonal[possessivePronoun]); break; case 2: - snprintf(buffer, 80, ", shattering %s into shards!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", shattering %s into shards!", kPersonal[possessivePronoun]); break; default: break; @@ -3471,13 +3472,13 @@ void EfhEngine::getDeathTypeDescription(int16 attackerId, int16 victimId) { case 6: switch (rndDescrForDeathType) { case 0: - snprintf(buffer, 80, ", leaving pudding for brains"); + tmpStr = Common::String::format(", leaving pudding for brains"); break; case 1: - snprintf(buffer, 80, ", bursting %s head like a bubble!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", bursting %s head like a bubble!", kPersonal[possessivePronoun]); break; case 2: - snprintf(buffer, 80, ", turning %s into a mindless vegetable", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", turning %s into a mindless vegetable", kPersonal[possessivePronoun]); break; default: break; @@ -3486,13 +3487,13 @@ void EfhEngine::getDeathTypeDescription(int16 attackerId, int16 victimId) { case 7: switch (rndDescrForDeathType) { case 0: - snprintf(buffer, 80, ", reducing %s to an oozing pile of flesh!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", reducing %s to an oozing pile of flesh!", kPersonal[possessivePronoun]); break; case 1: - snprintf(buffer, 80, ", melting %s like an ice cube in hot coffee!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", melting %s like an ice cube in hot coffee!", kPersonal[possessivePronoun]); break; case 2: - snprintf(buffer, 80, ", vaporizing %s into a steaming cloud!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", vaporizing %s into a steaming cloud!", kPersonal[possessivePronoun]); break; default: break; @@ -3501,13 +3502,13 @@ void EfhEngine::getDeathTypeDescription(int16 attackerId, int16 victimId) { case 8: switch (rndDescrForDeathType) { case 0: - snprintf(buffer, 80, ", engulfing %s in black smoke puffs!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", engulfing %s in black smoke puffs!", kPersonal[possessivePronoun]); break; case 1: - snprintf(buffer, 80, ", sucking %s into eternity!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", sucking %s into eternity!", kPersonal[possessivePronoun]); break; case 2: - snprintf(buffer, 80, ", turning %s into a mindless zombie!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", turning %s into a mindless zombie!", kPersonal[possessivePronoun]); break; default: break; @@ -3518,13 +3519,13 @@ void EfhEngine::getDeathTypeDescription(int16 attackerId, int16 victimId) { case 11: switch (rndDescrForDeathType) { case 0: - snprintf(buffer, 80, ", completely disintegrating %s!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", completely disintegrating %s!", kPersonal[possessivePronoun]); break; case 1: - snprintf(buffer, 80, ", spreading %s into a fine mist!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", spreading %s into a fine mist!", kPersonal[possessivePronoun]); break; case 2: - snprintf(buffer, 80, ", leaving a smoking crater in %s place!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", leaving a smoking crater in %s place!", kPersonal[possessivePronoun]); break; default: break; @@ -3535,13 +3536,13 @@ void EfhEngine::getDeathTypeDescription(int16 attackerId, int16 victimId) { case 14: switch (rndDescrForDeathType) { case 0: - snprintf(buffer, 80, ", tearing a chunk out of %s back!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", tearing a chunk out of %s back!", kPersonal[possessivePronoun]); break; case 1: - snprintf(buffer, 80, ", blowing %s brains out!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", blowing %s brains out!", kPersonal[possessivePronoun]); break; case 2: - snprintf(buffer, 80, ", exploding %s entire chest!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", exploding %s entire chest!", kPersonal[possessivePronoun]); break; default: break; @@ -3550,13 +3551,13 @@ void EfhEngine::getDeathTypeDescription(int16 attackerId, int16 victimId) { case 15: switch (rndDescrForDeathType) { case 0: - snprintf(buffer, 80, ", choking %s to death!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", choking %s to death!", kPersonal[possessivePronoun]); break; case 1: - snprintf(buffer, 80, ", melting %s lungs!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", melting %s lungs!", kPersonal[possessivePronoun]); break; case 2: - snprintf(buffer, 80, ", leaving %s gasping for air as %s collapses!", kPersonal[possessivePronoun], kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", leaving %s gasping for air as %s collapses!", kPersonal[possessivePronoun], kPersonal[possessivePronoun]); break; default: break; @@ -3565,13 +3566,13 @@ void EfhEngine::getDeathTypeDescription(int16 attackerId, int16 victimId) { case 16: switch (rndDescrForDeathType) { case 0: - snprintf(buffer, 80, ", tearing a chunk out of %s back!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", tearing a chunk out of %s back!", kPersonal[possessivePronoun]); break; case 1: - snprintf(buffer, 80, ", piercing %s heart!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", piercing %s heart!", kPersonal[possessivePronoun]); break; case 2: - snprintf(buffer, 80, ", impaling %s brain!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", impaling %s brain!", kPersonal[possessivePronoun]); break; default: break; @@ -3581,7 +3582,7 @@ void EfhEngine::getDeathTypeDescription(int16 attackerId, int16 victimId) { break; } - strncat((char *)_messageToBePrinted, buffer, 80); + _messageToBePrinted += tmpStr; } bool EfhEngine::characterSearchesMonsterCorpse(int16 charId, int16 monsterId) { @@ -3599,8 +3600,7 @@ bool EfhEngine::characterSearchesMonsterCorpse(int16 charId, int16 monsterId) { if (!giveItemTo(charId, itemId, 0xFF)) return false; - Common::String buffer = Common::String::format(" and finds a %s!", _items[itemId]._name); - strncat((char *)_messageToBePrinted, buffer.c_str(), buffer.size() + 1); + _messageToBePrinted += Common::String::format(" and finds a %s!", _items[itemId]._name); return true; } @@ -3609,8 +3609,7 @@ void EfhEngine::getXPAndSearchCorpse(int16 charId, Common::String namePt1, Commo int16 xpLevel = getXPLevel(_npcBuf[charId]._xp); _npcBuf[charId]._xp += kEncounters[_mapMonsters[monsterId]._monsterRef]._xpGiven; - char buffer[80]; - snprintf(buffer, 80, " %s%s gains %d experience", namePt1.c_str(), namePt2.c_str(), kEncounters[_mapMonsters[monsterId]._monsterRef]._xpGiven); + if (getXPLevel(_npcBuf[charId]._xp) > xpLevel) { generateSound(15); int16 var2 = getRandom(20) + getRandom(_npcBuf[charId]._infoScore[4]); @@ -3622,9 +3621,10 @@ void EfhEngine::getXPAndSearchCorpse(int16 charId, Common::String namePt1, Commo _npcBuf[charId]._infoScore[3] += getRandom(3) - 1; _npcBuf[charId]._infoScore[4] += getRandom(3) - 1; } - strncat((char *)_messageToBePrinted, buffer, 80); + + _messageToBePrinted += Common::String::format(" %s%s gains %d experience", namePt1.c_str(), namePt2.c_str(), kEncounters[_mapMonsters[monsterId]._monsterRef]._xpGiven); if (!characterSearchesMonsterCorpse(charId, monsterId)) - strncat((char *)_messageToBePrinted, "!", 2); + _messageToBePrinted += "!"; } @@ -3632,20 +3632,18 @@ void EfhEngine::addReactionText(int16 id) { debug("addReactionText %d", id); int16 rand3 = getRandom(3); - char buffer[80]; - memset(buffer, 0, 80); switch (id) { case 0: switch (rand3) { case 1: - snprintf(buffer, 80, " %s%s reels from the blow!", _characterNamePt1, _characterNamePt2.c_str()); + _messageToBePrinted += Common::String::format(" %s%s reels from the blow!", _characterNamePt1, _characterNamePt2.c_str()); break; case 2: - snprintf(buffer, 80, " %s%s sways from the attack!", _characterNamePt1, _characterNamePt2.c_str()); + _messageToBePrinted += Common::String::format(" %s%s sways from the attack!", _characterNamePt1, _characterNamePt2.c_str()); break; case 3: - snprintf(buffer, 80, " %s%s looks dazed!", _characterNamePt1, _characterNamePt2.c_str()); + _messageToBePrinted += Common::String::format(" %s%s looks dazed!", _characterNamePt1, _characterNamePt2.c_str()); break; default: break; @@ -3654,13 +3652,13 @@ void EfhEngine::addReactionText(int16 id) { case 1: switch (rand3) { case 1: - snprintf(buffer, 80, " %s%s cries out in agony!", _characterNamePt1, _characterNamePt2.c_str()); + _messageToBePrinted += Common::String::format(" %s%s cries out in agony!", _characterNamePt1, _characterNamePt2.c_str()); break; case 2: - snprintf(buffer, 80, " %s%s screams from the abuse!", _characterNamePt1, _characterNamePt2.c_str()); + _messageToBePrinted += Common::String::format(" %s%s screams from the abuse!", _characterNamePt1, _characterNamePt2.c_str()); break; case 3: - snprintf(buffer, 80, " %s%s wails terribly!", _characterNamePt1, _characterNamePt2.c_str()); + _messageToBePrinted += Common::String::format(" %s%s wails terribly!", _characterNamePt1, _characterNamePt2.c_str()); break; default: break; @@ -3669,13 +3667,13 @@ void EfhEngine::addReactionText(int16 id) { case 2: switch (rand3) { case 1: - snprintf(buffer, 80, " %s%s is staggering!", _characterNamePt1, _characterNamePt2.c_str()); + _messageToBePrinted += Common::String::format(" %s%s is staggering!", _characterNamePt1, _characterNamePt2.c_str()); break; case 2: - snprintf(buffer, 80, " %s%s falters for a moment!", _characterNamePt1, _characterNamePt2.c_str()); + _messageToBePrinted += Common::String::format(" %s%s falters for a moment!", _characterNamePt1, _characterNamePt2.c_str()); break; case 3: - snprintf(buffer, 80, " %s%s is stumbling about!", _characterNamePt1, _characterNamePt2.c_str()); + _messageToBePrinted += Common::String::format(" %s%s is stumbling about!", _characterNamePt1, _characterNamePt2.c_str()); break; default: break; @@ -3684,13 +3682,13 @@ void EfhEngine::addReactionText(int16 id) { case 3: switch (rand3) { case 1: - snprintf(buffer, 80, " %s%s winces from the pain!", _characterNamePt1, _characterNamePt2.c_str()); + _messageToBePrinted += Common::String::format(" %s%s winces from the pain!", _characterNamePt1, _characterNamePt2.c_str()); break; case 2: - snprintf(buffer, 80, " %s%s cringes from the damage!", _characterNamePt1, _characterNamePt2.c_str()); + _messageToBePrinted += Common::String::format(" %s%s cringes from the damage!", _characterNamePt1, _characterNamePt2.c_str()); break; case 3: - snprintf(buffer, 80, " %s%s shrinks from the wound!", _characterNamePt1, _characterNamePt2.c_str()); + _messageToBePrinted += Common::String::format(" %s%s shrinks from the wound!", _characterNamePt1, _characterNamePt2.c_str()); break; default: break; @@ -3699,13 +3697,13 @@ void EfhEngine::addReactionText(int16 id) { case 4: switch (rand3) { case 1: - snprintf(buffer, 80, " %s%s screams!", _characterNamePt1, _characterNamePt2.c_str()); + _messageToBePrinted += Common::String::format(" %s%s screams!", _characterNamePt1, _characterNamePt2.c_str()); break; case 2: - snprintf(buffer, 80, " %s%s bellows!", _characterNamePt1, _characterNamePt2.c_str()); + _messageToBePrinted += Common::String::format(" %s%s bellows!", _characterNamePt1, _characterNamePt2.c_str()); break; case 3: - snprintf(buffer, 80, " %s%s shrills!", _characterNamePt1, _characterNamePt2.c_str()); + _messageToBePrinted += Common::String::format(" %s%s shrills!", _characterNamePt1, _characterNamePt2.c_str()); break; default: break; @@ -3714,13 +3712,13 @@ void EfhEngine::addReactionText(int16 id) { case 5: switch (rand3) { case 1: - snprintf(buffer, 80, " %s%s chortles!", _characterNamePt1, _characterNamePt2.c_str()); + _messageToBePrinted += Common::String::format(" %s%s chortles!", _characterNamePt1, _characterNamePt2.c_str()); break; case 2: - snprintf(buffer, 80, " %s%s seems amused!", _characterNamePt1, _characterNamePt2.c_str()); + _messageToBePrinted += Common::String::format(" %s%s seems amused!", _characterNamePt1, _characterNamePt2.c_str()); break; case 3: - snprintf(buffer, 80, " %s%s looks concerned!", _characterNamePt1, _characterNamePt2.c_str()); + _messageToBePrinted += Common::String::format(" %s%s looks concerned!", _characterNamePt1, _characterNamePt2.c_str()); break; default: break; @@ -3729,13 +3727,13 @@ void EfhEngine::addReactionText(int16 id) { case 6: switch (rand3) { case 1: - snprintf(buffer, 80, " %s%s laughs at the feeble attack!", _characterNamePt1, _characterNamePt2.c_str()); + _messageToBePrinted += Common::String::format(" %s%s laughs at the feeble attack!", _characterNamePt1, _characterNamePt2.c_str()); break; case 2: - snprintf(buffer, 80, " %s%s smiles at the pathetic attack!", _characterNamePt1, _characterNamePt2.c_str()); + _messageToBePrinted += Common::String::format(" %s%s smiles at the pathetic attack!", _characterNamePt1, _characterNamePt2.c_str()); break; case 3: - snprintf(buffer, 80, " %s%s laughs at the ineffective assault!", _characterNamePt1, _characterNamePt2.c_str()); + _messageToBePrinted += Common::String::format(" %s%s laughs at the ineffective assault!", _characterNamePt1, _characterNamePt2.c_str()); break; default: break; @@ -3745,29 +3743,12 @@ void EfhEngine::addReactionText(int16 id) { break; } - strncat((char *)_messageToBePrinted, buffer, 80); -} - -char EfhEngine::getFightMessageLastCharacter(char *message) { - debug("getFightMessageLastCharacter %s", message); - - char *ptr = message; - - if (ptr == nullptr || *ptr == 0) - return 0; - - char lastChar = *ptr; - while (*ptr != 0) { - lastChar = *ptr++; - } - - return lastChar; } void EfhEngine::sub1D8C2(int16 charId, int16 damage) { debug("sub1D8C2 %d %d", charId, damage); - int16 var42 = 0; + int16 destroyCounter = 0; int16 var40 = _npcBuf[charId]._possessivePronounSHL6 / 64; if (var40 > 2) { @@ -3788,14 +3769,12 @@ void EfhEngine::sub1D8C2(int16 charId, int16 damage) { Common::String buffer2 = _items[_npcBuf[charId]._inventory[objectId]._ref]._name; removeObject(charId, objectId); - if (var42 == 0) { - var42 = 1; - Common::String buffer = Common::String::format(", but %s ", kPossessive[var40]) + buffer2; - strncat((char *)_messageToBePrinted, buffer.c_str(), 40); + if (destroyCounter == 0) { + destroyCounter = 1; + _messageToBePrinted += Common::String::format(", but %s ", kPossessive[var40]) + buffer2; } else { - ++var42; - Common::String buffer = Common::String(", ") + buffer2; - strncat((char *)_messageToBePrinted, buffer.c_str(), 40); + ++destroyCounter; + _messageToBePrinted += Common::String(", ") + buffer2; } } @@ -3803,12 +3782,12 @@ void EfhEngine::sub1D8C2(int16 charId, int16 damage) { damage = var44; } - if (var42 == 0) { - strncat((char *)_messageToBePrinted, "!", 2); - } else if (var42 > 1 || getFightMessageLastCharacter((char *)_messageToBePrinted) == 's' || getFightMessageLastCharacter((char *)_messageToBePrinted) == 'S') { - strncat((char *)_messageToBePrinted, " are destroyed!", 17); + if (destroyCounter == 0) { + _messageToBePrinted += "!"; + } else if (destroyCounter > 1 || _messageToBePrinted.lastChar() == 's' || _messageToBePrinted.lastChar() == 'S') { + _messageToBePrinted += " are destroyed!"; } else { - strncat((char *)_messageToBePrinted, " is destroyed!", 16); + _messageToBePrinted += " is destroyed!"; } } @@ -4133,8 +4112,8 @@ void EfhEngine::sub18E80(int16 charId, int16 windowId, int16 menuId, int16 curMe } } -int16 EfhEngine::displayString_3(const char *str, bool animFl, int16 charId, int16 windowId, int16 menuId, int16 curMenuLine) { - debug("displayString_3 %s %s %d %d %d %d", str, animFl ? "True" : "False", charId, windowId, menuId, curMenuLine); +int16 EfhEngine::displayString_3(Common::String str, bool animFl, int16 charId, int16 windowId, int16 menuId, int16 curMenuLine) { + debug("displayString_3 %s %s %d %d %d %d", str.c_str(), animFl ? "True" : "False", charId, windowId, menuId, curMenuLine); int16 retVal = 0; @@ -4143,10 +4122,10 @@ int16 EfhEngine::displayString_3(const char *str, bool animFl, int16 charId, int displayWindow(_windowWithBorderBuf, 19, 113, _hiResImageBuf); if (counter == 0) { - script_parse((uint8 *)str, 28, 122, 105, 166, false); + script_parse(str, 28, 122, 105, 166, false); displayFctFullScreen(); } else { - retVal = script_parse((uint8 *)str, 28, 122, 105, 166, true); + retVal = script_parse(str, 28, 122, 105, 166, true); } } @@ -4277,7 +4256,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me displayString_3("The item emits a low droning hum...", false, charId, windowId, menuId, curMenuLine); } else { int16 victims = 0; - strncat((char *)_messageToBePrinted, " The item emits a low droning hum...", 400); + _messageToBePrinted += " The item emits a low droning hum..."; if (getRandom(100) < 50) { for (uint counter = 0; counter < 9; ++counter) { if (isMonsterActive(windowId, counter)) { @@ -4306,7 +4285,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me } else { buffer1 = Common::String::format("%d %s falls asleep!", victims, kEncounters[_mapMonsters[_teamMonsterIdArray[windowId]]._monsterRef]._name); } - strncat((char *)_messageToBePrinted, buffer1.c_str(), 400); + _messageToBePrinted += buffer1; } varA6 = true; @@ -4315,7 +4294,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me if (argA == 2) { displayString_3("The item grows very cold for a moment...", false, charId, windowId, menuId, curMenuLine); } else { - strncat((char *)_messageToBePrinted, " The item emits a blue beam...", 400); + _messageToBePrinted += " The item emits a blue beam..."; int16 victim = 0; if (getRandom(100) < 50) { for (uint varA8 = 0; varA8 < 9; ++varA8) { @@ -4346,7 +4325,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me } else { buffer1 = Common::String::format("%d %s is frozen in place!", victim, kEncounters[_mapMonsters[_teamMonsterIdArray[windowId]]._monsterRef]._name); } - strncat((char *)_messageToBePrinted, buffer1.c_str(), 80); + _messageToBePrinted += buffer1; // } @@ -4356,7 +4335,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me if (argA == 2) { displayString_3("A serene feeling passes through the air...", false, charId, windowId, menuId, curMenuLine); } else { - strncat((char *)_messageToBePrinted, " The combat pauses...as there is a moment of forgiveness...", 400); + _messageToBePrinted += " The combat pauses...as there is a moment of forgiveness..."; _unkArray2C8AA[0] = 0; } @@ -4366,7 +4345,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me if (argA == 2) { displayString_3("A dark sense fills your soul...then fades!", false, charId, windowId, menuId, curMenuLine); } else { - strncat((char *)_messageToBePrinted, " A dark gray fiery whirlwind surrounds the poor victim...the power fades and death abounds!", 400); + _messageToBePrinted += " A dark gray fiery whirlwind surrounds the poor victim...the power fades and death abounds!"; if (getRandom(100) < 50) { for (uint counter = 0; counter < 9; ++counter) { if (getRandom(100) < 50) { @@ -4391,12 +4370,12 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me displayString_3("A dark sense fills your soul...then fades!", false, charId, windowId, menuId, curMenuLine); } else { if (getRandom(100) < 50) { - strncat((char *)_messageToBePrinted, " A dark fiery whirlwind surrounds the poor victim...the power fades and all targeted die!", 400); + _messageToBePrinted += " A dark fiery whirlwind surrounds the poor victim...the power fades and all targeted die!"; for (uint counter = 0; counter < 9; ++counter) { _mapMonsters[_teamMonsterIdArray[windowId]]._pictureRef[counter] = 0; } } else { - strncat((char *)_messageToBePrinted, " A dark fiery whirlwind surrounds the poor victim...the power fades and one victim dies!", 400); + _messageToBePrinted += " A dark fiery whirlwind surrounds the poor victim...the power fades and one victim dies!"; for (uint counter = 0; counter < 9; ++counter) { if (isMonsterActive(windowId, counter)) { _mapMonsters[_teamMonsterIdArray[windowId]]._pictureRef[counter] = 0; @@ -4411,7 +4390,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me if (argA == 2) { displayString_3("There is no apparent affect!", false, charId, windowId, menuId, curMenuLine); } else { - strncat((char *)_messageToBePrinted, " The magic sparkles brilliant hues in the air!", 400); + _messageToBePrinted += " The magic sparkles brilliant hues in the air!"; sub1E028(windowId, _items[itemId].field17_attackTypeDefense, true); } varA6 = true; @@ -4430,7 +4409,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me if (argA == 2) { displayString_3(buffer1.c_str(), false, charId, windowId, menuId, curMenuLine); } else { - strncat((char *)_messageToBePrinted, buffer1.c_str(), 80); + _messageToBePrinted += buffer1; } _word32482[varAA] -= 50; if (_word32482[varAA] < 0) @@ -4454,7 +4433,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me if (argA == 2) { displayString_3(buffer1.c_str(), false, charId, windowId, menuId, curMenuLine); } else { - strncat((char *)_messageToBePrinted, buffer1.c_str(), 80); + _messageToBePrinted += buffer1; } _teamPctVisible[teamCharId] -= 50; @@ -4478,7 +4457,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me if (argA == 2) { displayString_3(buffer1.c_str(), false, charId, windowId, menuId, curMenuLine); } else { - strncat((char *)_messageToBePrinted, buffer1.c_str(), 80); + _messageToBePrinted += buffer1; retVal = true; } // emptyFunction(2); @@ -4488,7 +4467,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me if (argA == 2) { displayString_3(buffer1.c_str(), false, charId, windowId, menuId, curMenuLine); } else { - strncat((char *)_messageToBePrinted, buffer1.c_str(), 80); + _messageToBePrinted += buffer1; retVal = true; } } else { @@ -4496,7 +4475,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me if (argA == 2) { displayString_3(buffer1.c_str(), false, charId, windowId, menuId, curMenuLine); } else { - strncat((char *)_messageToBePrinted, buffer1.c_str(), 80); + _messageToBePrinted += buffer1; retVal = true; } } @@ -4515,7 +4494,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me if (argA == 2) { displayString_3(buffer1.c_str(), false, charId, windowId, menuId, curMenuLine); } else { - strncat((char *)_messageToBePrinted, buffer1.c_str(), 80); + _messageToBePrinted += buffer1; retVal = true; } // emptyFunction(2); @@ -4525,7 +4504,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me if (argA == 2) { displayString_3(buffer1.c_str(), false, charId, windowId, menuId, curMenuLine); } else { - strncat((char *)_messageToBePrinted, buffer1.c_str(), 80); + _messageToBePrinted += buffer1; retVal = true; } } else { @@ -4533,7 +4512,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me if (argA == 2) { displayString_3(buffer1.c_str(), false, charId, windowId, menuId, curMenuLine); } else { - strncat((char *)_messageToBePrinted, buffer1.c_str(), 80); + _messageToBePrinted += buffer1; retVal = true; } } @@ -4549,11 +4528,11 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me int16 teamCharId = windowId; if (teamCharId != 0x1B) { if (_teamCharStatus[teamCharId]._status == 2) { // frozen - strncat((char *)_messageToBePrinted, " The item makes a loud noise, awakening the character!", 80); + _messageToBePrinted += " The item makes a loud noise, awakening the character!"; _teamCharStatus[teamCharId]._status = 0; _teamCharStatus[teamCharId]._duration = 0; } else { - strncat((char *)_messageToBePrinted, " The item makes a loud noise, but has no effect!", 80); + _messageToBePrinted += " The item makes a loud noise, but has no effect!"; } } } @@ -4565,7 +4544,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me if (argA == 2) { displayString_3(buffer1.c_str(), false, charId, windowId, menuId, curMenuLine); } else { - strncat((char *)_messageToBePrinted, buffer1.c_str(), 80); + _messageToBePrinted += buffer1; } setCharacterObjectToBroken(charId, objectId); varA6 = true; @@ -4601,7 +4580,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me if (argA == 2) { displayString_3(buffer1.c_str(), false, charId, windowId, menuId, curMenuLine); } else { - strncat((char *)_messageToBePrinted, buffer1.c_str(), 80); + _messageToBePrinted += buffer1; retVal = true; } @@ -4630,7 +4609,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me if (argA == 2) { displayString_3(buffer1.c_str(), false, charId, windowId, menuId, curMenuLine); } else { - strncat((char *)_messageToBePrinted, buffer1.c_str(), 80); + _messageToBePrinted += buffer1; retVal = true; } } @@ -4661,7 +4640,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me if (argA == 2) { displayString_3(buffer1.c_str(), false, charId, windowId, menuId, curMenuLine); } else { - strncat((char *)_messageToBePrinted, buffer1.c_str(), 80); + _messageToBePrinted += buffer1; retVal = true; } } @@ -4674,7 +4653,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me if (argA == 2) { displayString_3(buffer1.c_str(), false, charId, windowId, menuId, curMenuLine); } else { - strncat((char *)_messageToBePrinted, buffer1.c_str(), 80); + _messageToBePrinted += buffer1; retVal = true; } totalPartyKill(); @@ -4696,7 +4675,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me if (argA == 2) { displayString_3(buffer1.c_str(), false, charId, windowId, menuId, curMenuLine); } else { - strncat((char *)_messageToBePrinted, buffer1.c_str(), 80); + _messageToBePrinted += buffer1; retVal = true; } // emptyFunction(2); @@ -4712,11 +4691,11 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me int16 teamCharId = windowId; if (teamCharId != 0x1B) { if (_teamCharStatus[teamCharId]._status == 0) { - strncat((char *)_messageToBePrinted, " The item makes a loud noise, awakening the character!", 80); + _messageToBePrinted += " The item makes a loud noise, awakening the character!"; _teamCharStatus[teamCharId]._status = 0; _teamCharStatus[teamCharId]._duration = 0; } else { - strncat((char *)_messageToBePrinted, " The item makes a loud noise, but has no effect!", 80); + _messageToBePrinted += " The item makes a loud noise, but has no effect!"; } } } @@ -4747,7 +4726,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me if (argA == 2) { displayString_3(buffer1.c_str(), false, charId, windowId, menuId, curMenuLine); } else { - strncat((char *)_messageToBePrinted, buffer1.c_str(), 80); + _messageToBePrinted += buffer1; retVal = true; } @@ -4778,7 +4757,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me if (argA == 2) { displayString_3(buffer1.c_str(), false, charId, windowId, menuId, curMenuLine); } else { - strncat((char *)_messageToBePrinted, buffer1.c_str(), 80); + _messageToBePrinted += buffer1; retVal = true; } @@ -4810,7 +4789,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me Common::KeyCode varAE = getLastCharAfterAnimCount(_guessAnimationAmount); displayString_3(buffer1.c_str(), false, charId, windowId, menuId, curMenuLine); } else { - strncat((char *)_messageToBePrinted, buffer1.c_str(), 80); + _messageToBePrinted += buffer1; } setCharacterObjectToBroken(charId, objectId); } else { diff --git a/engines/efh/efh.h b/engines/efh/efh.h index cff5abd15971..fa282c29a6ca 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -318,7 +318,7 @@ class EfhEngine : public Engine { void displayMiddleLeftTempText(uint8 *impArray, bool flag); void sub15A28(int16 arg0, int16 arg2); void sub2455E(int16 arg0, int16 arg1, int16 arg2); - int16 sub1C219(uint8 *str, int16 menuType, int16 arg4, bool displayTeamWindowFl); + int16 sub1C219(Common::String str, int16 menuType, int16 arg4, bool displayTeamWindowFl); int16 sub151FD(int16 posX, int16 posY); bool isPosOutOfMap(int16 mapPosX, int16 mapPosY); void goSouth(); @@ -376,7 +376,6 @@ class EfhEngine : public Engine { bool characterSearchesMonsterCorpse(int16 charId, int16 monsterId); void getXPAndSearchCorpse(int16 charId, Common::String namePt1, Common::String namePt2, int16 monsterId); void addReactionText(int16 id); - char getFightMessageLastCharacter(char *message); void sub1D8C2(int16 charId, int16 damage); void displayMenuItemString(int16 menuBoxId, int16 thisBoxId, int16 minX, int16 maxX, int16 minY, const char *str); void displayStatusMenu(int16 windowId); @@ -387,7 +386,7 @@ class EfhEngine : public Engine { void displayStatusMenuActions(int16 menuId, int16 curMenuLine, int16 npcId); void unk_StatusMenu(int16 windowId, int16 menuId, int16 curMenuLine, int16 charId, bool unusedFl, bool refreshFl); void sub18E80(int16 charId, int16 windowId, int16 menuId, int16 curMenuLine); - int16 displayString_3(const char *str, bool animFl, int16 charId, int16 windowId, int16 menuId, int16 curMenuLine); + int16 displayString_3(Common::String str, bool animFl, int16 charId, int16 windowId, int16 menuId, int16 curMenuLine); bool isItemCursed(int16 itemId); bool hasObjectEquipped(int16 charId, int16 objectId); void equipCursedItem(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine); @@ -469,7 +468,7 @@ class EfhEngine : public Engine { // Script uint8 *script_readNumberArray(uint8 *buffer, int16 destArraySize, int16 *destArray); uint8 *script_getNumber(uint8 *srcBuffer, int16 *retval); - int16 script_parse(uint8 *str, int16 posX, int16 posY, int16 maxX, int16 maxY, bool flag); + int16 script_parse(Common::String str, int16 posX, int16 posY, int16 maxX, int16 maxY, bool flag); // Sound void generateSound1(int arg0, int arg2, int duration); @@ -526,7 +525,7 @@ class EfhEngine : public Engine { Common::String _characterNamePt2; Common::String _nameBuffer; char _attackBuffer[20]; - uint8 _messageToBePrinted[400]; + Common::String _messageToBePrinted; uint8 *_mapBitmapRefArr[19]; UnkMapStruct _mapUnknown[100]; diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index 9a69241cc0a0..8f606c7fab24 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -76,7 +76,7 @@ bool EfhEngine::handleFight(int16 monsterId) { } sub1CDFA(); - sub1C219(nullptr, 2, 1, false); + sub1C219("", 2, 1, false); for (uint counter = 0; counter < 8; ++counter) { int16 monsterGroupIdOrMonsterId = _stru3244C[counter]._field0; @@ -198,21 +198,21 @@ bool EfhEngine::handleFight(int16 monsterId) { if (checkSpecialItemsOnCurrentPlace(unk_monsterField5_itemId)) { // handleFight - check damages - Start if (var62 == 0) { - snprintf((char *)_messageToBePrinted, 400, "%s%s %s at %s%s with %s %s, but misses!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2.c_str(), kPossessive[var70], _nameBuffer.c_str()); + _messageToBePrinted = Common::String::format("%s%s %s at %s%s with %s %s, but misses!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2.c_str(), kPossessive[var70], _nameBuffer.c_str()); } else if (hitPoints <= 0) { - snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s, but does no damage!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2.c_str(), _attackBuffer, kPossessive[var70], _nameBuffer.c_str()); + _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s, but does no damage!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2.c_str(), _attackBuffer, kPossessive[var70], _nameBuffer.c_str()); } else if (hitPoints == 1) { - snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s for 1 point", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2.c_str(), _attackBuffer, kPossessive[var70], _nameBuffer.c_str()); + _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s for 1 point", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2.c_str(), _attackBuffer, kPossessive[var70], _nameBuffer.c_str()); if (_npcBuf[_teamCharId[var7E]]._hitPoints <= 0) getDeathTypeDescription(var7E + 1000, monsterGroupIdOrMonsterId); else - strncat((char *)_messageToBePrinted, "!", 2); + _messageToBePrinted += "!"; } else { - snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s for %d points", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2.c_str(), _attackBuffer, kPossessive[var70], _nameBuffer.c_str(), hitPoints); + _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s for %d points", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2.c_str(), _attackBuffer, kPossessive[var70], _nameBuffer.c_str(), hitPoints); if (_npcBuf[_teamCharId[var7E]]._hitPoints <= 0) getDeathTypeDescription(var7E + 1000, monsterGroupIdOrMonsterId); else - strncat((char *)_messageToBePrinted, "!", 2); + _messageToBePrinted += "!"; } // handleFight - check damages - End @@ -239,44 +239,36 @@ bool EfhEngine::handleFight(int16 monsterId) { // handleFight - Check armor - start if (var76 != 0 && var62 != 0 && _npcBuf[_teamCharId[var7E]]._hitPoints > 0) { - char buffer[80]; - memset(buffer, 0, 80); if (damagePointsAbsorbed <= 1) - snprintf(buffer, 80, " %s%s's armor absorbs 1 point!", _characterNamePt1, _characterNamePt2.c_str()); + _messageToBePrinted += Common::String::format(" %s%s's armor absorbs 1 point!", _characterNamePt1, _characterNamePt2.c_str()); else - snprintf(buffer, 80, " %s%s's armor absorbs %d points!", _characterNamePt1, _characterNamePt2.c_str(), damagePointsAbsorbed); + _messageToBePrinted += Common::String::format(" %s%s's armor absorbs %d points!", _characterNamePt1, _characterNamePt2.c_str(), damagePointsAbsorbed); - strncat((char *)_messageToBePrinted, buffer, 80); varInt = (originalDamage + damagePointsAbsorbed) / 10; sub1D8C2(_teamCharId[var7E], varInt); } // handleFight - Check armor - end // handleFight - Check effect - start - char buffer[80]; - memset(buffer, 0, 80); switch (_items[unk_monsterField5_itemId].field_16) { case 1: if (getRandom(100) < 20) { _teamCharStatus[var7E]._status = 1; _teamCharStatus[var7E]._duration = getRandom(10); - snprintf(buffer, 80, " %s%s falls asleep!", _characterNamePt1, _characterNamePt2.c_str()); - strncat((char *)_messageToBePrinted, buffer, 80); + _messageToBePrinted += Common::String::format(" %s%s falls asleep!", _characterNamePt1, _characterNamePt2.c_str()); } break; case 2: if (getRandom(100) < 20) { _teamCharStatus[var7E]._status = 2; _teamCharStatus[var7E]._duration = getRandom(10); - snprintf(buffer, 80, " %s%s is frozen!", _characterNamePt1, _characterNamePt2.c_str()); - strncat((char *)_messageToBePrinted, buffer, 80); + _messageToBePrinted += Common::String::format(" %s%s is frozen!", _characterNamePt1, _characterNamePt2.c_str()); } break; case 5: case 6: if (getRandom(100) < 20) { - snprintf(buffer, 80, " %s%s's life energy is gone!", _characterNamePt1, _characterNamePt2.c_str()); - strncat((char *)_messageToBePrinted, buffer, 80); + _messageToBePrinted += Common::String::format(" %s%s's life energy is gone!", _characterNamePt1, _characterNamePt2.c_str()); _npcBuf[_teamCharId[var7E]]._hitPoints = 0; } break; @@ -285,7 +277,7 @@ bool EfhEngine::handleFight(int16 monsterId) { } // handleFight - Check effect - end } else { - snprintf((char *)_messageToBePrinted, 400, "%s%s tries to use %s %s, but it doesn't work!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPossessive[var70], _nameBuffer.c_str()); + _messageToBePrinted = Common::String::format("%s%s tries to use %s %s, but it doesn't work!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPossessive[var70], _nameBuffer.c_str()); } genericGenerateSound(_items[unk_monsterField5_itemId]._attackType, var62); sub1C219(_messageToBePrinted, 1, 2, true); @@ -304,13 +296,13 @@ bool EfhEngine::handleFight(int16 monsterId) { switch (_stru32686[monsterGroupIdOrMonsterId]._field0[var86]) { case 1: - snprintf((char *)_messageToBePrinted, 400, "%s%s wakes up!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str()); + _messageToBePrinted = Common::String::format("%s%s wakes up!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str()); break; case 2: - snprintf((char *)_messageToBePrinted, 400, "%s%s thaws out!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str()); + _messageToBePrinted = Common::String::format("%s%s thaws out!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str()); break; default: - snprintf((char *)_messageToBePrinted, 400, "%s%s recovers!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str()); + _messageToBePrinted = Common::String::format("%s%s recovers!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str()); break; } _stru32686[monsterGroupIdOrMonsterId]._field0[var86] = 0; @@ -353,13 +345,13 @@ void EfhEngine::handleFight_checkEndEffect(int16 charId) { // End of effect message depends on the type of effect switch (_teamCharStatus[charId]._status) { case 1: - snprintf((char *)_messageToBePrinted, 400, "%s%s wakes up!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str()); + _messageToBePrinted = Common::String::format("%s%s wakes up!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str()); break; case 2: - snprintf((char *)_messageToBePrinted, 400, "%s%s thaws out!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str()); + _messageToBePrinted = Common::String::format("%s%s thaws out!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str()); break; default: - snprintf((char *)_messageToBePrinted, 400, "%s%s recovers!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str()); + _messageToBePrinted = Common::String::format("%s%s recovers!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str()); break; } @@ -486,24 +478,24 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { if (checkSpecialItemsOnCurrentPlace(unk_monsterField5_itemId)) { // Action A - Check damages - Start if (var62 == 0) { - snprintf((char *)_messageToBePrinted, 400, "%s%s %s at %s%s with %s %s, but misses!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2.c_str(), kPossessive[var70], _nameBuffer.c_str()); + _messageToBePrinted = Common::String::format("%s%s %s at %s%s with %s %s, but misses!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2.c_str(), kPossessive[var70], _nameBuffer.c_str()); } else if (hitPoints <= 0) { - snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s, but does no damage!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2.c_str(), _attackBuffer, kPossessive[var70], _nameBuffer.c_str()); + _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s, but does no damage!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2.c_str(), _attackBuffer, kPossessive[var70], _nameBuffer.c_str()); } else if (hitPoints == 1) { - snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s for 1 point", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2.c_str(), _attackBuffer, kPossessive[var70], _nameBuffer.c_str()); + _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s for 1 point", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2.c_str(), _attackBuffer, kPossessive[var70], _nameBuffer.c_str()); if (_mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] <= 0) { getDeathTypeDescription(groupId, teamCharId + 1000); getXPAndSearchCorpse(_teamCharId[teamCharId], _enemyNamePt1, _enemyNamePt2, _teamMonsterIdArray[groupId]); } else { - strncat((char *)_messageToBePrinted, "!", 2); + _messageToBePrinted += "!"; } } else { - snprintf((char *)_messageToBePrinted, 400, "%s%s %s %s%s %swith %s %s for %d points", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2.c_str(), _attackBuffer, kPossessive[var70], _nameBuffer.c_str(), hitPoints); + _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s for %d points", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2.c_str(), _attackBuffer, kPossessive[var70], _nameBuffer.c_str(), hitPoints); if (_mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] <= 0) { getDeathTypeDescription(groupId, teamCharId + 1000); getXPAndSearchCorpse(_teamCharId[teamCharId], _enemyNamePt1, _enemyNamePt2, _teamMonsterIdArray[groupId]); } else { - strncat((char *)_messageToBePrinted, "!", 2); + _messageToBePrinted += "!"; } } // Action A - Check damages - End @@ -531,19 +523,15 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { // Action A - Add armor absorb text - Start if (var76 && var62 && _mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] > 0) { - char buffer[80]; - memset(buffer, 0, 80); if (damagePointsAbsorbed <= 1) - snprintf(buffer, 80, " %s%s's armor absorbs 1 point!", _characterNamePt1, _characterNamePt2.c_str()); + _messageToBePrinted += Common::String::format(" %s%s's armor absorbs 1 point!", _characterNamePt1, _characterNamePt2.c_str()); else - snprintf(buffer, 80, " %s%s's armor absorbs %d points!", _characterNamePt1, _characterNamePt2.c_str(), damagePointsAbsorbed); - - strncat((char *)_messageToBePrinted, buffer, 80); + _messageToBePrinted += Common::String::format(" %s%s's armor absorbs %d points!", _characterNamePt1, _characterNamePt2.c_str(), damagePointsAbsorbed); } // Action A - Add armor absorb text - End if (var5C) - strncat((char *)_messageToBePrinted, " Your actions do not go un-noticed...", 400); + _messageToBePrinted += Common::String(" Your actions do not go un-noticed..."); // Action A - Check item durability - Start varInt = _teamCharId[teamCharId]; @@ -552,10 +540,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { var51 = _npcBuf[varInt]._inventory[var64]._stat1 & 0x7F; --var51; if (var51 <= 0) { - char buffer[80]; - memset(buffer, 0, 80); - snprintf(buffer, 80, " * %s%s's %s breaks!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), _nameBuffer.c_str()); - strncat((char *)_messageToBePrinted, buffer, 80); + _messageToBePrinted += Common::String::format(" * %s%s's %s breaks!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), _nameBuffer.c_str()); setCharacterObjectToBroken(varInt, var64); var6E = false; } else { @@ -569,22 +554,16 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { if (getRandom(100) < 35) { _stru32686[var7E]._field0[groupId] = 1; _stru32686[var7E]._field2[groupId] = getRandom(10); - char buffer[80]; - memset(buffer, 0, 80); - snprintf(buffer, 80, " %s%s falls asleep!", _characterNamePt1, _characterNamePt2.c_str()); - strncat((char *)_messageToBePrinted, buffer, 80); + _messageToBePrinted += Common::String::format(" %s%s falls asleep!", _characterNamePt1, _characterNamePt2.c_str()); } } else if (_items[unk_monsterField5_itemId].field_16 == 2 && _mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] > 0) { _stru32686[var7E]._field0[groupId] = 2; _stru32686[var7E]._field2[groupId] = getRandom(10); - char buffer[80]; - memset(buffer, 0, 80); - snprintf(buffer, 80, " %s%s is frozen!", _characterNamePt1, _characterNamePt2.c_str()); - strncat((char *)_messageToBePrinted, buffer, 80); + _messageToBePrinted += Common::String::format(" %s%s is frozen!", _characterNamePt1, _characterNamePt2.c_str()); } // Action A - Check effect - End } else { - snprintf((char *)_messageToBePrinted, 400, "%s%s tries to use %s %s, but it doesn't work!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPossessive[var70], _nameBuffer.c_str()); + _messageToBePrinted = Common::String::format("%s%s tries to use %s %s, but it doesn't work!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPossessive[var70], _nameBuffer.c_str()); } genericGenerateSound(_items[unk_monsterField5_itemId]._attackType, var62); @@ -607,7 +586,7 @@ void EfhEngine::handleFight_lastAction_D(int16 teamCharId) { else _enemyNamePt1 = ""; - snprintf((char *)_messageToBePrinted, 400, "%s%s prepares to defend %sself!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPersonal[var70]); + _messageToBePrinted = Common::String::format("%s%s prepares to defend %sself!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPersonal[var70]); sub1C219(_messageToBePrinted, 1, 2, true); } @@ -626,7 +605,7 @@ void EfhEngine::handleFight_lastAction_H(int16 teamCharId) { else _enemyNamePt1 = ""; - snprintf((char *)_messageToBePrinted, 400, "%s%s attempts to hide %sself!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPersonal[var70]); + _messageToBePrinted = Common::String::format("%s%s attempts to hide %sself!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPersonal[var70]); sub1C219(_messageToBePrinted, 1, 2, true); } @@ -644,7 +623,7 @@ void EfhEngine::handleFight_lastAction_U(int16 teamCharId) { else _enemyNamePt1 = ""; - snprintf((char *)_messageToBePrinted, 400, "%s%s uses %s %s! ", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPossessive[var70], _nameBuffer.c_str()); + _messageToBePrinted = Common::String::format("%s%s uses %s %s! ", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPossessive[var70], _nameBuffer.c_str()); sub1C219(_messageToBePrinted, 1, 2, true); } diff --git a/engines/efh/script.cpp b/engines/efh/script.cpp index 8712f7725d91..fe3cba39c28c 100644 --- a/engines/efh/script.cpp +++ b/engines/efh/script.cpp @@ -52,8 +52,8 @@ uint8 *EfhEngine::script_getNumber(uint8 *srcBuffer, int16 *retval) { } } -int16 EfhEngine::script_parse(uint8 *stringBuffer, int16 posX, int16 posY, int16 maxX, int16 maxY, bool flag) { - debug("script_parse %s %d-%d %d-%d %s", (char *)stringBuffer, posX, posY, maxX, maxY, flag ? "True" : "False"); +int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 posY, int16 maxX, int16 maxY, bool flag) { + debug("script_parse %s %d-%d %d-%d %s", stringBuffer.c_str(), posX, posY, maxX, maxY, flag ? "True" : "False"); bool doneFlag = false; int16 var_F2 = -1; @@ -63,11 +63,10 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int16 posX, int16 posY, int16 int16 numbLines = (1 + maxY - posY) / 9; int16 width = maxX - posX; int16 spaceWidth = getStringWidth(" "); - uint8 *buffer = stringBuffer; + uint8 *buffer = (uint8 *)stringBuffer.c_str(); char nextWord[80]; - char curLine[150]; + Common::String curLine = ""; memset(nextWord, 0, sizeof(nextWord)); - memset(curLine, 0, sizeof(curLine)); int16 curWordPos = 0; setTextPos(posX, curLineNb * 9 + posY); @@ -88,7 +87,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int16 posX, int16 posY, int16 nextWord[curWordPos] = 0; int16 widthNextWord = getStringWidth(nextWord); - int16 widthCurrentLine = spaceWidth + getStringWidth(curLine); + int16 widthCurrentLine = spaceWidth + getStringWidth(curLine.c_str()); if (widthCurrentLine + widthNextWord > width || curChar == 0x7C) { if (curLineNb >= numbLines) { @@ -97,16 +96,13 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int16 posX, int16 posY, int16 if (var_F2 == 0) displayStringAtTextPos(curLine); - *curLine = 0; - strncpy(curLine, nextWord, 80); - strncat(curLine, " ", 2); + curLine = Common::String(nextWord) + " "; ++curLineNb; setTextPos(posX, posY + curLineNb * 9); curWordPos = 0; } } else { - strncat(curLine, nextWord, 80); - strncat(curLine, " ", 2); + curLine += Common::String(nextWord) + " "; curWordPos = 0; } ++buffer; @@ -393,16 +389,16 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int16 posX, int16 posY, int16 drawMapWindow(); displayFctFullScreen(); drawMapWindow(); - var110 = sub1C219((uint8 *)"Nothing...", 1, 2, true); + var110 = sub1C219("Nothing...", 1, 2, true); displayFctFullScreen(); } else { _enemyNamePt2 = _npcBuf[_teamCharId[counter]]._name; _nameBuffer = _items[var110]._name; - snprintf(curLine, 150, "%s finds a %s!", _enemyNamePt2.c_str(), _nameBuffer.c_str()); + curLine = Common::String::format("%s finds a %s!", _enemyNamePt2.c_str(), _nameBuffer.c_str()); drawMapWindow(); displayFctFullScreen(); drawMapWindow(); - var110 = sub1C219((uint8 *)curLine, 1, 2, true); + var110 = sub1C219(curLine, 1, 2, true); displayFctFullScreen(); } @@ -481,7 +477,7 @@ int16 EfhEngine::script_parse(uint8 *stringBuffer, int16 posX, int16 posY, int16 } } - if (*curLine != 0 && curLineNb < numbLines && var_F2 == 0) + if (curLine.size() >= 0 && curLineNb < numbLines && var_F2 == 0) displayStringAtTextPos(curLine); if (var_EE != 0xFF) { From 0df6c4b880ba46bd446ed1e9a0e961be9dfb222b Mon Sep 17 00:00:00 2001 From: Strangerke Date: Mon, 5 Dec 2022 23:17:42 +0100 Subject: [PATCH 183/412] EFH: Remove an original unused debug flag, fix some warnings --- engines/efh/efh.cpp | 59 ++++++++++++++++++++---------------------- engines/efh/efh.h | 2 +- engines/efh/script.cpp | 3 +-- 3 files changed, 30 insertions(+), 34 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index df5a37aa46ac..c310f821b0c9 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -293,7 +293,6 @@ EfhEngine::EfhEngine(OSystem *syst, const ADGameDescription *gd) : Engine(syst), _tempTextPtr = nullptr; _word2C880 = false; _redrawNeededFl = false; - _word2C8D7 = true; _drawHeroOnMapFl = true; _drawMonstersOnMapFl = true; _word2C87A = false; @@ -739,6 +738,7 @@ void EfhEngine::initEngine() { checkProtection(); if (_loadSaveSlot == -1) { loadEfhGame(); + resetGame(); } else { loadGameState(_loadSaveSlot); _loadSaveSlot = -1; @@ -990,11 +990,6 @@ void EfhEngine::drawMap(bool largeMapFl, int16 mapPosX, int16 mapPosY, int16 map } } } - - if (_word2C8D7) - return; - - warning("drawMap() - unexpected code reached, not implemented"); } void EfhEngine::displaySmallMap(int16 posX, int16 posY) { @@ -1481,14 +1476,14 @@ int16 EfhEngine::sub1C219(Common::String str, int16 menuType, int16 arg4, bool d else { drawColoredRect(minX, minY, maxX, maxY, 0); if (str.size()) - int16 varC = script_parse(str, minX, minY, maxX, maxY, false); + script_parse(str, minX, minY, maxX, maxY, false); } if (displayTeamWindowFl) displayLowStatusScreen(false); if (arg4 >= 2) - int16 varC = getLastCharAfterAnimCount(_guessAnimationAmount); + getLastCharAfterAnimCount(_guessAnimationAmount); if (arg4 == 3) drawColoredRect(minX, minY, maxX, maxY, 0); @@ -1665,9 +1660,6 @@ void EfhEngine::handleNewRoundEffects() { static int16 regenCounter = 0; - if (!_word2C8D7) - return; - for (int counter = 0; counter < _teamSize; ++counter) { if (_teamCharStatus[counter]._status == 0) // normal continue; @@ -1687,6 +1679,15 @@ void EfhEngine::handleNewRoundEffects() { regenCounter = 0; } +void EfhEngine::resetGame() { + loadTechMapImp(0); + _largeMapFlag = true; + _oldMapPosX = _mapPosX = 31; + _oldMapPosY = _mapPosY = 31; + _unkRelatedToAnimImageSetId = 0; + _unkArray2C8AA[0] = 0; +} + bool EfhEngine::handleDeathMenu() { debug("handleDeathMenu"); @@ -1720,25 +1721,22 @@ bool EfhEngine::handleDeathMenu() { Common::KeyCode input = waitForKey(); switch (input) { case Common::KEYCODE_l: - loadEfhGame(); + //loadEfhGame(); + //TODO : saveEfhGame opens the GUI save/load screen. It shouldn't bepossible to save at this point + saveEfhGame(); found = true; break; case Common::KEYCODE_q: + _shouldQuit = true; return true; break; case Common::KEYCODE_r: loadEfhGame(); - loadTechMapImp(0); - _largeMapFlag = true; - _oldMapPosX = _mapPosX = 31; - _oldMapPosY = _mapPosY = 31; - _unkRelatedToAnimImageSetId = 0; - _unkArray2C8AA[0] = 0; + resetGame(); found = true; break; case Common::KEYCODE_x: - if (!_word2C8D7) - found = true; + found = true; break; default: break; @@ -2044,8 +2042,6 @@ void EfhEngine::sub174A0() { static int16 sub174A0_monsterPosX = -1; static int16 sub174A0_monsterPosY = -1; - int16 var14 = 0; - int16 var6 = 0; _redrawNeededFl = true; int16 unkMonsterId = -1; int16 mapSize = _largeMapFlag ? 63 : 23; @@ -2071,7 +2067,7 @@ void EfhEngine::sub174A0() { continue; bool var1A = false; - var14 = 0; + int16 var14 = 0; sub174A0_monsterPosX = _mapMonsters[monsterId]._posX; sub174A0_monsterPosY = _mapMonsters[monsterId]._posY; @@ -2566,7 +2562,9 @@ bool EfhEngine::sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemI if (_mapUnknown[var8]._field3 == 0xFF) { sub22AA8(_mapUnknown[var8]._field5); // word! return true; - } else if (_mapUnknown[var8]._field3 == 0xFE) { + } + + if (_mapUnknown[var8]._field3 == 0xFE) { for (int counter = 0; counter < _teamSize; ++counter) { if (_teamCharId[counter] == -1) continue; @@ -2595,7 +2593,9 @@ bool EfhEngine::sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemI continue; for (uint var2 = 0; var2 < 39; ++var2) { - if (_npcBuf[_teamCharId[counter]]._activeScore[var2] >= _mapUnknown[var8]._field4) { + // CHECKME : the whole look doesn't make much sense as it's using var6 instead of var2, plus _activeScore is an array of 15 bytes, not 0x77... + // Also, 39 correspond to the size of activeScore + passiveScore + infoScore + the 2 remaining bytes of the struct + if (_npcBuf[_teamCharId[counter]]._activeScore[var6] >= _mapUnknown[var8]._field4) { sub22AA8(_mapUnknown[var8]._field5); return true; } @@ -2643,8 +2643,8 @@ int8 EfhEngine::sub15581(int16 mapPosX, int16 mapPosY, int16 arg4) { imageSetId *= 72; imageSetId += curTileInfo % 72; - if (arg4 == 1 && _word2C8D7) { - int16 var2 = sub22293(mapPosX, mapPosY, -1, 0x7FFF, 0, imageSetId); + if (arg4 == 1) { + sub22293(mapPosX, mapPosY, -1, 0x7FFF, 0, imageSetId); } if (_word2C880) { @@ -2652,7 +2652,7 @@ int8 EfhEngine::sub15581(int16 mapPosX, int16 mapPosY, int16 arg4) { return -1; } if (_tileFact[imageSetId]._field1 != 0xFF && !_dbgForceMonsterBlock) { - if ((arg4 == 1 && _word2C8D7) || (arg4 == 0 && _word2C8D7 && imageSetId != 128 && imageSetId != 121)) { + if ((arg4 == 1) || (arg4 == 0 && imageSetId != 128 && imageSetId != 121)) { if (_largeMapFlag) { _mapGameMap[mapPosX][mapPosY] = _tileFact[imageSetId]._field1; } else { @@ -5188,9 +5188,6 @@ bool EfhEngine::checkMonsterCollision() { if (_mapMonsters[monsterId]._posX != _mapPosX || _mapMonsters[monsterId]._posY != _mapPosY) continue; - if (!_word2C8D7) - return false; - _mapPosX = _oldMapPosX; _mapPosY = _oldMapPosY; if (_imageSetSubFilesIdx != _oldImageSetSubFilesIdx) diff --git a/engines/efh/efh.h b/engines/efh/efh.h index fa282c29a6ca..d9fdb4338c31 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -330,6 +330,7 @@ class EfhEngine : public Engine { void goNorthWest(); void goSouthWest(); void handleNewRoundEffects(); + void resetGame(); bool handleDeathMenu(); void computeMapAnimation(); void unkFct_anim(); @@ -588,7 +589,6 @@ class EfhEngine : public Engine { // TODO: Remove those useless debug flags bool _dbgForceDisplayUpperRightBorder; // Original debug flag? Always false. bool _dbgForceMonsterBlock; // Original debug flag? Always false. - bool _word2C8D7; // Original debug flag? Always true. bool _ongoingFightFl; bool _statusMenuActive; diff --git a/engines/efh/script.cpp b/engines/efh/script.cpp index fe3cba39c28c..5ebc63cbee9d 100644 --- a/engines/efh/script.cpp +++ b/engines/efh/script.cpp @@ -147,8 +147,7 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos // Change map. { map number, posX, posY } buffer = script_readNumberArray(buffer, 3, scriptNumberArray); if (flag) { - if (_word2C8D7) - writeTechAndMapFiles(); + writeTechAndMapFiles(); _oldMapPosX = _mapPosX = scriptNumberArray[1]; _oldMapPosY = _mapPosY = scriptNumberArray[2]; loadTechMapImp(scriptNumberArray[0]); From 68b66cad8360e000d6cc584526635e86de9d9264 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Tue, 6 Dec 2022 07:06:56 +0100 Subject: [PATCH 184/412] EFH: turn some more char[] into Common::String, fix 4 warnings --- engines/efh/efh.cpp | 72 ++++++++++++++++++---------------------- engines/efh/efh.h | 2 +- engines/efh/graphics.cpp | 8 ++--- 3 files changed, 37 insertions(+), 45 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index c310f821b0c9..1857ed4545db 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -1030,12 +1030,12 @@ void EfhEngine::drawScreen() { void EfhEngine::displayLowStatusScreen(bool flag) { debugC(6, kDebugEngine, "displayLowStatusScreen %s", flag ? "True" : "False"); - const char strName[5] = "Name"; - const char strDef[4] = "DEF"; - const char strHp[3] = "HP"; - const char strMaxHp[7] = "Max HP"; - const char strWeapon[7] = "Weapon"; - const char strDead[9] = "* DEAD *"; + Common::String strName = "Name"; + Common::String strDef = "DEF"; + Common::String strHp = "HP"; + Common::String strMaxHp = "Max HP"; + Common::String strWeapon = "Weapon"; + Common::String strDead = "* DEAD *"; for (int counter = 0; counter < 2; ++counter) { if (counter == 0 || flag) { @@ -1057,11 +1057,11 @@ void EfhEngine::displayLowStatusScreen(bool flag) { setTextPos(16, textPosY); displayStringAtTextPos(buffer); buffer = Common::String::format("%d", getEquipmentDefense(charId, false)); - displayCenteredString(buffer.c_str(), 104, 128, textPosY); + displayCenteredString(buffer, 104, 128, textPosY); buffer = Common::String::format("%d", _npcBuf[charId]._hitPoints); - displayCenteredString(buffer.c_str(), 144, 176, textPosY); + displayCenteredString(buffer, 144, 176, textPosY); buffer = Common::String::format("%d", _npcBuf[charId]._maxHP); - displayCenteredString(buffer.c_str(), 192, 224, textPosY); + displayCenteredString(buffer, 192, 224, textPosY); if (_npcBuf[charId]._hitPoints <= 0) { displayCenteredString(strDead, 225, 302, textPosY); @@ -1088,7 +1088,7 @@ void EfhEngine::displayLowStatusScreen(bool flag) { break; } - displayCenteredString(_nameBuffer.c_str(), 225, 302, textPosY); + displayCenteredString(_nameBuffer, 225, 302, textPosY); } } @@ -2265,9 +2265,6 @@ bool EfhEngine::checkMonsterGroupDistance1OrLess(int16 monsterId) { bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { debug("sub21820 %d %d %d", monsterId, arg2, itemId); - char buffer[80]; - memset(buffer, 0, 80); - uint8 var51 = _mapMonsters[monsterId]._possessivePronounSHL6 & 0x3F; if (_mapMonsters[monsterId]._guess_fullPlaceId == 0xFF) return false; @@ -2378,7 +2375,7 @@ bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { displayMonsterAnim(monsterId); _enemyNamePt2 = _npcBuf[var58]._name; _characterNamePt2 = _npcBuf[_teamCharId[counter]]._name; - snprintf(buffer, 80, "%s asks that %s leave your party.", _enemyNamePt2.c_str(), _characterNamePt2.c_str()); + Common::String buffer = Common::String::format("%s asks that %s leave your party.", _enemyNamePt2.c_str(), _characterNamePt2.c_str()); for (uint i = 0; i < 2; ++i) { clearBottomTextZone(0); _textColor = 0xE; @@ -3794,16 +3791,13 @@ void EfhEngine::sub1D8C2(int16 charId, int16 damage) { void EfhEngine::displayMenuItemString(int16 menuBoxId, int16 thisBoxId, int16 minX, int16 maxX, int16 minY, const char *str) { debug("displayMenuItemString %d %d %d->%d %d %s", menuBoxId, thisBoxId, minX, maxX, minY, str); - char buffer[20]; - memset(buffer, 0, 20); - if (menuBoxId == thisBoxId) { if (_menuDepth == 0) setTextColorWhite(); else setTextColorGrey(); - snprintf(buffer, 20, "> %s <", str); + Common::String buffer = Common::String::format("> %s <", str); displayCenteredString(buffer, minX, maxX, minY); setTextColorRed(); } else { @@ -4407,7 +4401,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me if (varAA != 0x1B) { buffer1 = " The magic makes the user as quick and agile as a bird!"; if (argA == 2) { - displayString_3(buffer1.c_str(), false, charId, windowId, menuId, curMenuLine); + displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; } @@ -4431,7 +4425,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me if (teamCharId != 0x1B) { buffer1 = " The magic makes the user invisible!"; if (argA == 2) { - displayString_3(buffer1.c_str(), false, charId, windowId, menuId, curMenuLine); + displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; } @@ -4445,8 +4439,6 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me } break; case 16: { // Fairy Dust - int16 varAC = _mapPosX; - int16 varAA = _mapPosY; _mapPosX = getRandom(_largeMapFlag ? 63 : 23); _mapPosY = getRandom(_largeMapFlag ? 63 : 23); int16 varAE = sub15538(_mapPosX, _mapPosY); @@ -4455,7 +4447,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me totalPartyKill(); buffer1 = "The entire party vanishes in a flash... only to appear in stone !"; if (argA == 2) { - displayString_3(buffer1.c_str(), false, charId, windowId, menuId, curMenuLine); + displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; retVal = true; @@ -4465,7 +4457,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me if (varAE == 0 || varAE == 0x48) { buffer1 = "The entire party vanishes in a flash...but re-appears, as if nothing happened!"; if (argA == 2) { - displayString_3(buffer1.c_str(), false, charId, windowId, menuId, curMenuLine); + displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; retVal = true; @@ -4473,7 +4465,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me } else { buffer1 = "The entire party vanishes in a flash...only to appear elsewhere!"; if (argA == 2) { - displayString_3(buffer1.c_str(), false, charId, windowId, menuId, curMenuLine); + displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; retVal = true; @@ -4492,7 +4484,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me totalPartyKill(); buffer1 = "The entire party vanishes in a flash... only to appear in stone !"; if (argA == 2) { - displayString_3(buffer1.c_str(), false, charId, windowId, menuId, curMenuLine); + displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; retVal = true; @@ -4502,7 +4494,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me if (varAE == 0 || varAE == 0x48) { buffer1 = "The entire party vanishes in a flash...but re-appears, as if nothing happened!"; if (argA == 2) { - displayString_3(buffer1.c_str(), false, charId, windowId, menuId, curMenuLine); + displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; retVal = true; @@ -4510,7 +4502,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me } else { buffer1 = "The entire party vanishes in a flash...only to appear elsewhere!"; if (argA == 2) { - displayString_3(buffer1.c_str(), false, charId, windowId, menuId, curMenuLine); + displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; retVal = true; @@ -4542,7 +4534,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me case 19: // "Junk" buffer1 = " * The item breaks!"; if (argA == 2) { - displayString_3(buffer1.c_str(), false, charId, windowId, menuId, curMenuLine); + displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; } @@ -4578,7 +4570,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me } buffer1 += "'"; if (argA == 2) { - displayString_3(buffer1.c_str(), false, charId, windowId, menuId, curMenuLine); + displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; retVal = true; @@ -4607,7 +4599,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me buffer1 = Common::String::format("%s increased 1 point!", kSkillArray[varAE]); if (argA == 2) { - displayString_3(buffer1.c_str(), false, charId, windowId, menuId, curMenuLine); + displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; retVal = true; @@ -4638,7 +4630,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me buffer1 = Common::String::format("%s lowered 1 point!", kSkillArray[varAE]); if (argA == 2) { - displayString_3(buffer1.c_str(), false, charId, windowId, menuId, curMenuLine); + displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; retVal = true; @@ -4651,7 +4643,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me case 26: // "Black Sphere" buffer1 = "The entire party collapses, dead!!!"; if (argA == 2) { - displayString_3(buffer1.c_str(), false, charId, windowId, menuId, curMenuLine); + displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; retVal = true; @@ -4673,7 +4665,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me _npcBuf[_teamCharId[teamCharId]]._hitPoints = 0; buffer1 = Common::String::format("%s collapses, dead!!!", _npcBuf[_teamCharId[teamCharId]]._name); if (argA == 2) { - displayString_3(buffer1.c_str(), false, charId, windowId, menuId, curMenuLine); + displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; retVal = true; @@ -4724,7 +4716,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me } if (argA == 2) { - displayString_3(buffer1.c_str(), false, charId, windowId, menuId, curMenuLine); + displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; retVal = true; @@ -4755,7 +4747,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me } if (argA == 2) { - displayString_3(buffer1.c_str(), false, charId, windowId, menuId, curMenuLine); + displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; retVal = true; @@ -4786,8 +4778,8 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me if (varA1 <= 0) { buffer1 = " * The item breaks!"; if (argA == 2) { - Common::KeyCode varAE = getLastCharAfterAnimCount(_guessAnimationAmount); - displayString_3(buffer1.c_str(), false, charId, windowId, menuId, curMenuLine); + getLastCharAfterAnimCount(_guessAnimationAmount); + displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; } @@ -4799,7 +4791,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me } if (argA == 2) { - Common::KeyCode varAE = getLastCharAfterAnimCount(_guessAnimationAmount); + getLastCharAfterAnimCount(_guessAnimationAmount); sub18E80(charId, windowId, menuId, curMenuLine); } } @@ -5223,7 +5215,7 @@ bool EfhEngine::checkMonsterCollision() { clearBottomTextZone(0); _textColor = 0xE; displayCenteredString("Interaction", 24, 296, 152); - displayCenteredString(buffer.c_str(), 24, 296, 161); + displayCenteredString(buffer, 24, 296, 161); setTextPos(24, 169); setTextColorWhite(); displayStringAtTextPos("T"); diff --git a/engines/efh/efh.h b/engines/efh/efh.h index d9fdb4338c31..4fef53097377 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -444,7 +444,7 @@ class EfhEngine : public Engine { void clearScreen(int16 color); void displayRawDataAtPos(uint8 *imagePtr, int16 posX, int16 posY); void drawString(const char *str, int16 startX, int16 startY, uint16 textColor); - void displayCenteredString(const char *str, int16 minX, int16 maxX, int16 posY); + void displayCenteredString(Common::String str, int16 minX, int16 maxX, int16 posY); void displayMenuAnswerString(const char *str, int16 minX, int16 maxX, int16 posY); void drawMapWindow(); void displayGameScreen(); diff --git a/engines/efh/graphics.cpp b/engines/efh/graphics.cpp index 8e9a97213c94..5062448b68ef 100644 --- a/engines/efh/graphics.cpp +++ b/engines/efh/graphics.cpp @@ -235,11 +235,11 @@ void EfhEngine::drawString(const char *str, int16 startX, int16 startY, uint16 t } } -void EfhEngine::displayCenteredString(const char *str, int16 minX, int16 maxX, int16 posY) { - debugC(1, kDebugGraphics, "displayCenteredString %s %d-%d %d", str, minX, maxX, posY); - uint16 length = getStringWidth(str); +void EfhEngine::displayCenteredString(Common::String str, int16 minX, int16 maxX, int16 posY) { + debugC(1, kDebugGraphics, "displayCenteredString %s %d-%d %d", str.c_str(), minX, maxX, posY); + uint16 length = getStringWidth(str.c_str()); int16 startCenteredDisplayX = minX + (maxX - minX - length) / 2; - drawString(str, startCenteredDisplayX, posY, _textColor); + drawString(str.c_str(), startCenteredDisplayX, posY, _textColor); } void EfhEngine::displayMenuAnswerString(const char *str, int16 minX, int16 maxX, int16 posY) { From db6ba84b0fb9fa0944d60a3ccec00a290107dd79 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Tue, 6 Dec 2022 07:11:15 +0100 Subject: [PATCH 185/412] EFH: Fix another warning --- engines/efh/fight.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index 8f606c7fab24..7999205f453f 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -26,7 +26,6 @@ namespace Efh { bool EfhEngine::handleFight(int16 monsterId) { debug("handleFight %d", monsterId); - int16 var8C = 0; _ongoingFightFl = true; sub1BE89(monsterId); From 6c11b653a360eee3a6901c5b8c9a324495fe1fdc Mon Sep 17 00:00:00 2001 From: Strangerke Date: Wed, 14 Dec 2022 23:03:15 +0100 Subject: [PATCH 186/412] EFH: turn some more char[] into Common::String --- engines/efh/efh.cpp | 46 +++++++++++++++++++-------------------- engines/efh/efh.h | 4 ++-- engines/efh/fight.cpp | 50 +++++++++++++++++++++---------------------- 3 files changed, 50 insertions(+), 50 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 1857ed4545db..107fabd5ca15 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -232,12 +232,12 @@ EfhEngine::EfhEngine(OSystem *syst, const ADGameDescription *gd) : Engine(syst), _portraitSubFilesArray[i] = nullptr; } - memset(_characterNamePt1, 0, 5); + _characterNamePt1 = ""; _characterNamePt2 = ""; _enemyNamePt1 = ""; _enemyNamePt2 = ""; _nameBuffer = ""; - memset(_attackBuffer, 0, 20); + _attackBuffer = ""; for (int i = 0; i < 100; ++i) { _imp1PtrArray[i] = nullptr; @@ -3634,13 +3634,13 @@ void EfhEngine::addReactionText(int16 id) { case 0: switch (rand3) { case 1: - _messageToBePrinted += Common::String::format(" %s%s reels from the blow!", _characterNamePt1, _characterNamePt2.c_str()); + _messageToBePrinted += Common::String::format(" %s%s reels from the blow!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); break; case 2: - _messageToBePrinted += Common::String::format(" %s%s sways from the attack!", _characterNamePt1, _characterNamePt2.c_str()); + _messageToBePrinted += Common::String::format(" %s%s sways from the attack!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); break; case 3: - _messageToBePrinted += Common::String::format(" %s%s looks dazed!", _characterNamePt1, _characterNamePt2.c_str()); + _messageToBePrinted += Common::String::format(" %s%s looks dazed!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); break; default: break; @@ -3649,13 +3649,13 @@ void EfhEngine::addReactionText(int16 id) { case 1: switch (rand3) { case 1: - _messageToBePrinted += Common::String::format(" %s%s cries out in agony!", _characterNamePt1, _characterNamePt2.c_str()); + _messageToBePrinted += Common::String::format(" %s%s cries out in agony!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); break; case 2: - _messageToBePrinted += Common::String::format(" %s%s screams from the abuse!", _characterNamePt1, _characterNamePt2.c_str()); + _messageToBePrinted += Common::String::format(" %s%s screams from the abuse!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); break; case 3: - _messageToBePrinted += Common::String::format(" %s%s wails terribly!", _characterNamePt1, _characterNamePt2.c_str()); + _messageToBePrinted += Common::String::format(" %s%s wails terribly!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); break; default: break; @@ -3664,13 +3664,13 @@ void EfhEngine::addReactionText(int16 id) { case 2: switch (rand3) { case 1: - _messageToBePrinted += Common::String::format(" %s%s is staggering!", _characterNamePt1, _characterNamePt2.c_str()); + _messageToBePrinted += Common::String::format(" %s%s is staggering!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); break; case 2: - _messageToBePrinted += Common::String::format(" %s%s falters for a moment!", _characterNamePt1, _characterNamePt2.c_str()); + _messageToBePrinted += Common::String::format(" %s%s falters for a moment!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); break; case 3: - _messageToBePrinted += Common::String::format(" %s%s is stumbling about!", _characterNamePt1, _characterNamePt2.c_str()); + _messageToBePrinted += Common::String::format(" %s%s is stumbling about!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); break; default: break; @@ -3679,13 +3679,13 @@ void EfhEngine::addReactionText(int16 id) { case 3: switch (rand3) { case 1: - _messageToBePrinted += Common::String::format(" %s%s winces from the pain!", _characterNamePt1, _characterNamePt2.c_str()); + _messageToBePrinted += Common::String::format(" %s%s winces from the pain!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); break; case 2: - _messageToBePrinted += Common::String::format(" %s%s cringes from the damage!", _characterNamePt1, _characterNamePt2.c_str()); + _messageToBePrinted += Common::String::format(" %s%s cringes from the damage!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); break; case 3: - _messageToBePrinted += Common::String::format(" %s%s shrinks from the wound!", _characterNamePt1, _characterNamePt2.c_str()); + _messageToBePrinted += Common::String::format(" %s%s shrinks from the wound!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); break; default: break; @@ -3694,13 +3694,13 @@ void EfhEngine::addReactionText(int16 id) { case 4: switch (rand3) { case 1: - _messageToBePrinted += Common::String::format(" %s%s screams!", _characterNamePt1, _characterNamePt2.c_str()); + _messageToBePrinted += Common::String::format(" %s%s screams!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); break; case 2: - _messageToBePrinted += Common::String::format(" %s%s bellows!", _characterNamePt1, _characterNamePt2.c_str()); + _messageToBePrinted += Common::String::format(" %s%s bellows!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); break; case 3: - _messageToBePrinted += Common::String::format(" %s%s shrills!", _characterNamePt1, _characterNamePt2.c_str()); + _messageToBePrinted += Common::String::format(" %s%s shrills!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); break; default: break; @@ -3709,13 +3709,13 @@ void EfhEngine::addReactionText(int16 id) { case 5: switch (rand3) { case 1: - _messageToBePrinted += Common::String::format(" %s%s chortles!", _characterNamePt1, _characterNamePt2.c_str()); + _messageToBePrinted += Common::String::format(" %s%s chortles!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); break; case 2: - _messageToBePrinted += Common::String::format(" %s%s seems amused!", _characterNamePt1, _characterNamePt2.c_str()); + _messageToBePrinted += Common::String::format(" %s%s seems amused!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); break; case 3: - _messageToBePrinted += Common::String::format(" %s%s looks concerned!", _characterNamePt1, _characterNamePt2.c_str()); + _messageToBePrinted += Common::String::format(" %s%s looks concerned!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); break; default: break; @@ -3724,13 +3724,13 @@ void EfhEngine::addReactionText(int16 id) { case 6: switch (rand3) { case 1: - _messageToBePrinted += Common::String::format(" %s%s laughs at the feeble attack!", _characterNamePt1, _characterNamePt2.c_str()); + _messageToBePrinted += Common::String::format(" %s%s laughs at the feeble attack!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); break; case 2: - _messageToBePrinted += Common::String::format(" %s%s smiles at the pathetic attack!", _characterNamePt1, _characterNamePt2.c_str()); + _messageToBePrinted += Common::String::format(" %s%s smiles at the pathetic attack!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); break; case 3: - _messageToBePrinted += Common::String::format(" %s%s laughs at the ineffective assault!", _characterNamePt1, _characterNamePt2.c_str()); + _messageToBePrinted += Common::String::format(" %s%s laughs at the ineffective assault!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); break; default: break; diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 4fef53097377..490f68dea4e7 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -522,10 +522,10 @@ class EfhEngine : public Engine { uint8 _techDataArr[19][4100]; Common::String _enemyNamePt1; Common::String _enemyNamePt2; - char _characterNamePt1[5]; + Common::String _characterNamePt1; Common::String _characterNamePt2; Common::String _nameBuffer; - char _attackBuffer[20]; + Common::String _attackBuffer; Common::String _messageToBePrinted; uint8 *_mapBitmapRefArr[19]; diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index 7999205f453f..3006e2073615 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -174,17 +174,17 @@ bool EfhEngine::handleFight(int16 monsterId) { if (var62 > 0) { _npcBuf[_teamCharId[var7E]]._hitPoints -= originalDamage; if (var62 > 1) - snprintf(_attackBuffer, 20, "%d times ", var62); + _attackBuffer = Common::String::format("%d times ", var62); else - *_attackBuffer = 0; + _attackBuffer = ""; } int16 var68 = _items[unk_monsterField5_itemId]._attackType + 1; int16 var6A = getRandom(3); if (var5E == 2) - snprintf(_characterNamePt1, 5, "The "); + _characterNamePt1 = "The "; else - *_characterNamePt1 = 0; + _characterNamePt1 = ""; if (var7E == 2) _enemyNamePt1 = "The "; @@ -197,17 +197,17 @@ bool EfhEngine::handleFight(int16 monsterId) { if (checkSpecialItemsOnCurrentPlace(unk_monsterField5_itemId)) { // handleFight - check damages - Start if (var62 == 0) { - _messageToBePrinted = Common::String::format("%s%s %s at %s%s with %s %s, but misses!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2.c_str(), kPossessive[var70], _nameBuffer.c_str()); + _messageToBePrinted = Common::String::format("%s%s %s at %s%s with %s %s, but misses!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1.c_str(), _characterNamePt2.c_str(), kPossessive[var70], _nameBuffer.c_str()); } else if (hitPoints <= 0) { - _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s, but does no damage!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2.c_str(), _attackBuffer, kPossessive[var70], _nameBuffer.c_str()); + _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s, but does no damage!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[var70], _nameBuffer.c_str()); } else if (hitPoints == 1) { - _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s for 1 point", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2.c_str(), _attackBuffer, kPossessive[var70], _nameBuffer.c_str()); + _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s for 1 point", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[var70], _nameBuffer.c_str()); if (_npcBuf[_teamCharId[var7E]]._hitPoints <= 0) getDeathTypeDescription(var7E + 1000, monsterGroupIdOrMonsterId); else _messageToBePrinted += "!"; } else { - _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s for %d points", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1, _characterNamePt2.c_str(), _attackBuffer, kPossessive[var70], _nameBuffer.c_str(), hitPoints); + _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s for %d points", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[var70], _nameBuffer.c_str(), hitPoints); if (_npcBuf[_teamCharId[var7E]]._hitPoints <= 0) getDeathTypeDescription(var7E + 1000, monsterGroupIdOrMonsterId); else @@ -239,9 +239,9 @@ bool EfhEngine::handleFight(int16 monsterId) { // handleFight - Check armor - start if (var76 != 0 && var62 != 0 && _npcBuf[_teamCharId[var7E]]._hitPoints > 0) { if (damagePointsAbsorbed <= 1) - _messageToBePrinted += Common::String::format(" %s%s's armor absorbs 1 point!", _characterNamePt1, _characterNamePt2.c_str()); + _messageToBePrinted += Common::String::format(" %s%s's armor absorbs 1 point!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); else - _messageToBePrinted += Common::String::format(" %s%s's armor absorbs %d points!", _characterNamePt1, _characterNamePt2.c_str(), damagePointsAbsorbed); + _messageToBePrinted += Common::String::format(" %s%s's armor absorbs %d points!", _characterNamePt1.c_str(), _characterNamePt2.c_str(), damagePointsAbsorbed); varInt = (originalDamage + damagePointsAbsorbed) / 10; sub1D8C2(_teamCharId[var7E], varInt); @@ -254,20 +254,20 @@ bool EfhEngine::handleFight(int16 monsterId) { if (getRandom(100) < 20) { _teamCharStatus[var7E]._status = 1; _teamCharStatus[var7E]._duration = getRandom(10); - _messageToBePrinted += Common::String::format(" %s%s falls asleep!", _characterNamePt1, _characterNamePt2.c_str()); + _messageToBePrinted += Common::String::format(" %s%s falls asleep!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); } break; case 2: if (getRandom(100) < 20) { _teamCharStatus[var7E]._status = 2; _teamCharStatus[var7E]._duration = getRandom(10); - _messageToBePrinted += Common::String::format(" %s%s is frozen!", _characterNamePt1, _characterNamePt2.c_str()); + _messageToBePrinted += Common::String::format(" %s%s is frozen!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); } break; case 5: case 6: if (getRandom(100) < 20) { - _messageToBePrinted += Common::String::format(" %s%s's life energy is gone!", _characterNamePt1, _characterNamePt2.c_str()); + _messageToBePrinted += Common::String::format(" %s%s's life energy is gone!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); _npcBuf[_teamCharId[var7E]]._hitPoints = 0; } break; @@ -452,17 +452,17 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { if (var62 > 0) { _mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] -= originalDamage; if (var62 > 1) { - snprintf(_attackBuffer, 20, "%d times ", var62); + _attackBuffer = Common::String::format("%d times ", var62); } else { - *_attackBuffer = 0; + _attackBuffer = ""; } } int16 var68 = _items[unk_monsterField5_itemId]._attackType + 1; int16 var6A = getRandom(3) - 1; if (var5E == 2) { - snprintf(_characterNamePt1, 5, "The "); + _characterNamePt1 = "The "; } else { - *_characterNamePt1 = 0; + _characterNamePt1 = ""; } if (var70 == 2) { @@ -477,11 +477,11 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { if (checkSpecialItemsOnCurrentPlace(unk_monsterField5_itemId)) { // Action A - Check damages - Start if (var62 == 0) { - _messageToBePrinted = Common::String::format("%s%s %s at %s%s with %s %s, but misses!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2.c_str(), kPossessive[var70], _nameBuffer.c_str()); + _messageToBePrinted = Common::String::format("%s%s %s at %s%s with %s %s, but misses!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1.c_str(), _characterNamePt2.c_str(), kPossessive[var70], _nameBuffer.c_str()); } else if (hitPoints <= 0) { - _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s, but does no damage!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2.c_str(), _attackBuffer, kPossessive[var70], _nameBuffer.c_str()); + _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s, but does no damage!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[var70], _nameBuffer.c_str()); } else if (hitPoints == 1) { - _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s for 1 point", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2.c_str(), _attackBuffer, kPossessive[var70], _nameBuffer.c_str()); + _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s for 1 point", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[var70], _nameBuffer.c_str()); if (_mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] <= 0) { getDeathTypeDescription(groupId, teamCharId + 1000); getXPAndSearchCorpse(_teamCharId[teamCharId], _enemyNamePt1, _enemyNamePt2, _teamMonsterIdArray[groupId]); @@ -489,7 +489,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { _messageToBePrinted += "!"; } } else { - _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s for %d points", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1, _characterNamePt2.c_str(), _attackBuffer, kPossessive[var70], _nameBuffer.c_str(), hitPoints); + _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s for %d points", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[var70], _nameBuffer.c_str(), hitPoints); if (_mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] <= 0) { getDeathTypeDescription(groupId, teamCharId + 1000); getXPAndSearchCorpse(_teamCharId[teamCharId], _enemyNamePt1, _enemyNamePt2, _teamMonsterIdArray[groupId]); @@ -523,9 +523,9 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { // Action A - Add armor absorb text - Start if (var76 && var62 && _mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] > 0) { if (damagePointsAbsorbed <= 1) - _messageToBePrinted += Common::String::format(" %s%s's armor absorbs 1 point!", _characterNamePt1, _characterNamePt2.c_str()); + _messageToBePrinted += Common::String::format(" %s%s's armor absorbs 1 point!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); else - _messageToBePrinted += Common::String::format(" %s%s's armor absorbs %d points!", _characterNamePt1, _characterNamePt2.c_str(), damagePointsAbsorbed); + _messageToBePrinted += Common::String::format(" %s%s's armor absorbs %d points!", _characterNamePt1.c_str(), _characterNamePt2.c_str(), damagePointsAbsorbed); } // Action A - Add armor absorb text - End @@ -553,12 +553,12 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { if (getRandom(100) < 35) { _stru32686[var7E]._field0[groupId] = 1; _stru32686[var7E]._field2[groupId] = getRandom(10); - _messageToBePrinted += Common::String::format(" %s%s falls asleep!", _characterNamePt1, _characterNamePt2.c_str()); + _messageToBePrinted += Common::String::format(" %s%s falls asleep!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); } } else if (_items[unk_monsterField5_itemId].field_16 == 2 && _mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] > 0) { _stru32686[var7E]._field0[groupId] = 2; _stru32686[var7E]._field2[groupId] = getRandom(10); - _messageToBePrinted += Common::String::format(" %s%s is frozen!", _characterNamePt1, _characterNamePt2.c_str()); + _messageToBePrinted += Common::String::format(" %s%s is frozen!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); } // Action A - Check effect - End } else { From d598eefac42eeee47ca6703154c3f3130bdf29bd Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sat, 17 Dec 2022 11:48:24 +0100 Subject: [PATCH 187/412] EFH: Fix bug in displayImp1Text, renaming --- engines/efh/efh.cpp | 153 +++++++++++++++++++------------------- engines/efh/efh.h | 14 ++-- engines/efh/files.cpp | 4 +- engines/efh/savegames.cpp | 4 +- 4 files changed, 89 insertions(+), 86 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 107fabd5ca15..b45042d66539 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -66,7 +66,7 @@ void InvObject::init() { void UnkMapStruct::init() { _placeId = _posX = _posY = _field3 = _field4 = 0; - _field5 = _field7 = 0; + _field5_textId = _field7_textId = 0; } void UnkAnimStruct::init() { @@ -111,8 +111,8 @@ void NPCStruct::init() { field_F = 0; field_10 = 0; field_11 = 0; - field_12 = 0; - field_14 = 0; + field12_textId = 0; + field14_textId = 0; _xp = 0; for (int i = 0; i < 15; ++i) @@ -788,8 +788,8 @@ void EfhEngine::loadMapArrays(int idx) { _mapUnknown[i]._posY = _mapUnknownPtr[9 * i + 2]; _mapUnknown[i]._field3 = _mapUnknownPtr[9 * i + 3]; _mapUnknown[i]._field4 = _mapUnknownPtr[9 * i + 4]; - _mapUnknown[i]._field5 = READ_LE_UINT16(&_mapUnknownPtr[9 * i + 5]); - _mapUnknown[i]._field7 = READ_LE_UINT16(&_mapUnknownPtr[9 * i + 7]); + _mapUnknown[i]._field5_textId = READ_LE_UINT16(&_mapUnknownPtr[9 * i + 5]); + _mapUnknown[i]._field7_textId = READ_LE_UINT16(&_mapUnknownPtr[9 * i + 7]); } uint8 *mapMonstersPtr = &_mapArr[idx][902]; @@ -804,7 +804,7 @@ void EfhEngine::loadMapArrays(int idx) { _mapMonsters[i]._field_6 = mapMonstersPtr[29 * i + 6]; _mapMonsters[i]._monsterRef = mapMonstersPtr[29 * i + 7]; _mapMonsters[i]._field_8 = mapMonstersPtr[29 * i + 8]; - _mapMonsters[i]._field_9 = mapMonstersPtr[29 * i + 9]; + _mapMonsters[i]._field9_textId = mapMonstersPtr[29 * i + 9]; _mapMonsters[i]._groupSize = mapMonstersPtr[29 * i + 10]; for (int j = 0; j < 9; ++j) _mapMonsters[i]._pictureRef[j] = READ_LE_INT16(&mapMonstersPtr[29 * i + 11 + j * 2]); @@ -1118,8 +1118,8 @@ void EfhEngine::removeCharacterFromTeam(int16 teamMemberId) { debug("removeCharacterFromTeam %d", teamMemberId); int16 charId = _teamCharId[teamMemberId]; - _npcBuf[charId].field_12 = _npcBuf[charId].field_B; - _npcBuf[charId].field_14 = _npcBuf[charId].field_E; + _npcBuf[charId].field12_textId = _npcBuf[charId].field_B; + _npcBuf[charId].field14_textId = _npcBuf[charId].field_E; _npcBuf[charId].field_10 = _npcBuf[charId].field_C; _npcBuf[charId].field_11 = _npcBuf[charId].field_D; @@ -1424,8 +1424,8 @@ void EfhEngine::sub2455E(int16 arg0, int16 arg2, int16 arg4) { } } -int16 EfhEngine::sub1C219(Common::String str, int16 menuType, int16 arg4, bool displayTeamWindowFl) { - debug("sub1C219 %s %d %d %s", str.c_str(), menuType, arg4, displayTeamWindowFl ? "True" : "False"); +int16 EfhEngine::sub1C219(Common::String str, int16 menuType, int16 displayOption, bool displayTeamWindowFl) { + debug("sub1C219 %s %d %d %s", str.c_str(), menuType, displayOption, displayTeamWindowFl ? "True" : "False"); int16 varA = 0xFF; int16 minX, maxX, minY, maxY; @@ -1469,7 +1469,7 @@ int16 EfhEngine::sub1C219(Common::String str, int16 menuType, int16 arg4, bool d if (displayTeamWindowFl) displayLowStatusScreen(false); - if (arg4 != 0) { + if (displayOption != 0) { displayFctFullScreen(); if (_word2C87A) _word2C87A = false; @@ -1482,10 +1482,10 @@ int16 EfhEngine::sub1C219(Common::String str, int16 menuType, int16 arg4, bool d if (displayTeamWindowFl) displayLowStatusScreen(false); - if (arg4 >= 2) + if (displayOption >= 2) getLastCharAfterAnimCount(_guessAnimationAmount); - if (arg4 == 3) + if (displayOption == 3) drawColoredRect(minX, minY, maxX, maxY, 0); } @@ -2279,11 +2279,11 @@ bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { return false; if (var51 != 0x3F) { - if (_mapMonsters[monsterId]._field_9 == 0xFF || arg2 != 5) { + if (_mapMonsters[monsterId]._field9_textId == 0xFF || arg2 != 5) { return false; } displayMonsterAnim(monsterId); - sub22AA8(_mapMonsters[monsterId]._field_9); + displayImp1Text(_mapMonsters[monsterId]._field9_textId); displayAnimFrames(0xFE, true); return true; } @@ -2296,7 +2296,7 @@ bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { case 0: if (arg2 == 4 && _npcBuf[var58].field_11 == itemId) { displayMonsterAnim(monsterId); - sub22AA8(_npcBuf[var58].field_14); + displayImp1Text(_npcBuf[var58].field14_textId); displayAnimFrames(0xFE, true); return true; } @@ -2304,7 +2304,7 @@ bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { case 1: if (arg2 == 2 && _npcBuf[var58].field_11 == itemId) { displayMonsterAnim(monsterId); - sub22AA8(_npcBuf[var58].field_14); + displayImp1Text(_npcBuf[var58].field14_textId); displayAnimFrames(0xFE, true); return true; } @@ -2312,7 +2312,7 @@ bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { case 2: if (arg2 == 1 && _npcBuf[var58].field_11 == itemId) { displayMonsterAnim(monsterId); - sub22AA8(_npcBuf[var58].field_14); + displayImp1Text(_npcBuf[var58].field14_textId); displayAnimFrames(0xFE, true); return true; } @@ -2320,7 +2320,7 @@ bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { case 3: if (_history[_npcBuf[var58].field_11] != 0) { displayMonsterAnim(monsterId); - sub22AA8(_npcBuf[var58].field_14); + displayImp1Text(_npcBuf[var58].field14_textId); displayAnimFrames(0xFE, true); return true; } @@ -2331,7 +2331,7 @@ bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { if (_npcBuf[_teamCharId[counter]]._inventory[charId]._ref == _npcBuf[var58].field_11) { removeObject(_teamCharId[counter], charId); displayMonsterAnim(monsterId); - sub22AA8(_npcBuf[var58].field_14); + displayImp1Text(_npcBuf[var58].field14_textId); displayAnimFrames(0xFE, true); return true; } @@ -2341,7 +2341,7 @@ bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { case 5: if (arg2 == 2 && _npcBuf[var58].field_11 == itemId) { displayMonsterAnim(monsterId); - sub22AA8(_npcBuf[var58].field_14); + displayImp1Text(_npcBuf[var58].field14_textId); displayAnimFrames(0xFE, true); return true; } @@ -2351,7 +2351,7 @@ bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { for (uint charId = 0; charId < 10; ++charId) { if (_npcBuf[_teamCharId[counter]]._inventory[charId]._ref == _npcBuf[var58].field_11) { displayMonsterAnim(monsterId); - sub22AA8(_npcBuf[var58].field_14); + displayImp1Text(_npcBuf[var58].field14_textId); displayAnimFrames(0xFE, true); return true; } @@ -2363,7 +2363,7 @@ bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { if (_npcBuf[var58].field_11 == _teamCharId[counter]) { removeCharacterFromTeam(counter); displayMonsterAnim(monsterId); - sub22AA8(_npcBuf[var58].field_14); + displayImp1Text(_npcBuf[var58].field14_textId); displayAnimFrames(0xFE, true); return true; } @@ -2389,7 +2389,7 @@ bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { Common::KeyCode input = mapInputCode(waitForKey()); if (input == Common::KEYCODE_y) { removeCharacterFromTeam(counter); - sub22AA8(_npcBuf[var58].field_14); + displayImp1Text(_npcBuf[var58].field14_textId); } displayAnimFrames(0xFE, true); return true; @@ -2400,7 +2400,7 @@ bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { for (int counter = 0; counter < _teamSize; ++counter) { if (_npcBuf[var58].field_11 == _teamCharId[counter]) { displayMonsterAnim(monsterId); - sub22AA8(_npcBuf[var58].field_14); + displayImp1Text(_npcBuf[var58].field14_textId); displayAnimFrames(0xFE, true); return true; } @@ -2408,7 +2408,7 @@ bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { break; case 16: displayMonsterAnim(monsterId); - sub22AA8(_npcBuf[var58].field_14); + displayImp1Text(_npcBuf[var58].field14_textId); displayAnimFrames(0xFE, true); return true; default: @@ -2416,11 +2416,11 @@ bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { break; } - if (_npcBuf[var58].field_12 == 0x7FFF || arg2 != 5) + if (_npcBuf[var58].field12_textId == 0x7FFF || arg2 != 5) return false; displayMonsterAnim(monsterId); - sub22AA8(_npcBuf[var58].field_12); + displayImp1Text(_npcBuf[var58].field12_textId); displayAnimFrames(0xFE, true); return true; } @@ -2434,13 +2434,15 @@ void EfhEngine::sub221D2(int16 monsterId) { } } -void EfhEngine::sub22AA8(int16 arg0) { - debug("sub22AA8 %d", arg0); +void EfhEngine::displayImp1Text(int16 textId) { + debug("displayImp1Text %d", textId); - int16 var8, varA, varC, stringIdx; - var8 = varA = varC = stringIdx = 0; + int16 charCounter = 0; + int16 stringIdx = 0; + bool textComplete = false; + bool maxReached = false; - if (arg0 <= 0xFE) { + if (textId <= 0xFE) { if (_tempTextPtr) { _tempTextPtr = nullptr; displayMiddleLeftTempText(_tempTextPtr, true); @@ -2448,22 +2450,23 @@ void EfhEngine::sub22AA8(int16 arg0) { if (_statusMenuActive) drawGameScreenAndTempText(true); - int16 var4 = arg0; + int16 curTextId = textId; for (;;) { - uint8 *var12 = nullptr; - if (var4 >= 0 && var4 <= 0xFE) { - var12 = _imp1PtrArray[var4]; + uint8 *curString = nullptr; + if (curTextId >= 0 && curTextId <= 0xFE) { + curString = _imp1PtrArray[curTextId]; } - var4 = 0xFF; - if (var12 == nullptr) + curTextId = 0xFF; + if (curString == nullptr) break; - if (stringIdx == 0) - _messageToBePrinted = ""; do { - switch (*var12) { + if (stringIdx == 0) + _messageToBePrinted = ""; + + switch (*curString) { case 0x00: case 0x0A: break; @@ -2471,41 +2474,41 @@ void EfhEngine::sub22AA8(int16 arg0) { case 0x20: _messageToBePrinted += " "; stringIdx++; - if (++varC >= 350) { - var8 = -1; + if (++charCounter >= 350) { + maxReached = true; } break; case 0x40: case 0x60: - varA = -1; + textComplete = true; break; case 0x7C: _messageToBePrinted += Common::String(0x7C); stringIdx++; - varC += 20; - if (varC >= 350) { - var8 = -1; + charCounter += 20; + if (charCounter >= 350) { + maxReached = true; } break; case 0x7E: - var8 = -1; + maxReached = true; break; default: - _messageToBePrinted += Common::String(*var12); + _messageToBePrinted += Common::String(*curString); stringIdx++; - varC++; + charCounter++; break; } - var12 += 1; - int16 var2 = 0xFF ; - if (var8 != 0 || varA != 0) { - var8 = 0; + curString += 1; + if (maxReached || textComplete) { + int16 nextTextId = 0xFF; + maxReached = false; stringIdx = 0; - varC = 0; + charCounter = 0; uint8 firstChar = _messageToBePrinted.firstChar(); if (firstChar == 0x5E || firstChar == 0) { if (firstChar == 0x5E) { - var2 = script_parse(_messageToBePrinted, 0, 0, 319, 199, true); + nextTextId = script_parse(_messageToBePrinted, 0, 0, 319, 199, true); _word2C87A = false; } } else { @@ -2515,13 +2518,13 @@ void EfhEngine::sub22AA8(int16 arg0) { displayFctFullScreen(); } - var2 = sub1C219(_messageToBePrinted, 1, 1, true); - if (var2 != 0xFF) - var4 = var2; + nextTextId = sub1C219(_messageToBePrinted, 1, 1, true); + if (nextTextId != 0xFF) + curTextId = nextTextId; - if (var4 != -1) { + if (curTextId != -1) { for (uint counter = 0; counter < 2; ++counter) { - if (varA) { + if (textComplete) { displayCenteredString("[DONE]", 128, 303, 117); } else { displayCenteredString("[MORE]", 128, 303, 117); @@ -2532,14 +2535,14 @@ void EfhEngine::sub22AA8(int16 arg0) { getInputBlocking(); } } - if (var2 != 0xFF) - var4 = var2; + if (nextTextId != 0xFF) + curTextId = nextTextId; } - } while (varA == 0 && var4 != -1); + } while (!textComplete && curTextId != -1); - varA = 0; - if (var4 == 0xFF || var4 == -1) + textComplete = false; + if (curTextId == 0xFF || curTextId == -1) break; } } @@ -2557,7 +2560,7 @@ bool EfhEngine::sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemI displayMiddleLeftTempText(_imp2PtrArray[imageSetId], true); } else if (arg8 == 0) { if (_mapUnknown[var8]._field3 == 0xFF) { - sub22AA8(_mapUnknown[var8]._field5); // word! + displayImp1Text(_mapUnknown[var8]._field5_textId); // word! return true; } @@ -2566,7 +2569,7 @@ bool EfhEngine::sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemI if (_teamCharId[counter] == -1) continue; if (_teamCharId[counter] == _mapUnknown[var8]._field4) { - sub22AA8(_mapUnknown[var8]._field5); + displayImp1Text(_mapUnknown[var8]._field5_textId); return true; } } @@ -2577,7 +2580,7 @@ bool EfhEngine::sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemI for (uint var2 = 0; var2 < 10; ++var2) { if (_npcBuf[_teamCharId[counter]]._inventory[var2]._ref == _mapUnknown[var8]._field4) { - sub22AA8(_mapUnknown[var8]._field5); + displayImp1Text(_mapUnknown[var8]._field5_textId); return true; } } @@ -2593,7 +2596,7 @@ bool EfhEngine::sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemI // CHECKME : the whole look doesn't make much sense as it's using var6 instead of var2, plus _activeScore is an array of 15 bytes, not 0x77... // Also, 39 correspond to the size of activeScore + passiveScore + infoScore + the 2 remaining bytes of the struct if (_npcBuf[_teamCharId[counter]]._activeScore[var6] >= _mapUnknown[var8]._field4) { - sub22AA8(_mapUnknown[var8]._field5); + displayImp1Text(_mapUnknown[var8]._field5_textId); return true; } } @@ -2602,7 +2605,7 @@ bool EfhEngine::sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemI } else { if ((_mapUnknown[var8]._field3 == 0xFA && arg8 == 1) || (_mapUnknown[var8]._field3 == 0xFC && arg8 == 2) || (_mapUnknown[var8]._field3 == 0xFB && arg8 == 3)) { if (_mapUnknown[var8]._field4 == itemId) { - sub22AA8(_mapUnknown[var8]._field5); + displayImp1Text(_mapUnknown[var8]._field5_textId); return true; } } else if (arg8 == 4) { @@ -2610,7 +2613,7 @@ bool EfhEngine::sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemI if (var6 >= 0x7B && var6 <= 0xEF) { var6 -= 0x78; if (var6 >= 0 && var6 <= 0x8B && var6 == itemId && _mapUnknown[var8]._field4 <= _npcBuf[charId]._activeScore[itemId]) { - sub22AA8(_mapUnknown[var8]._field5); + displayImp1Text(_mapUnknown[var8]._field5_textId); return true; } } @@ -2623,9 +2626,9 @@ bool EfhEngine::sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemI } if ((arg8 == 4 && _mapUnknown[var8]._field3 < 0xFA) || arg8 != 4) { - if (_mapUnknown[var8]._field7 > 0xFE) + if (_mapUnknown[var8]._field7_textId > 0xFE) return false; - sub22AA8(_mapUnknown[var8]._field7); + displayImp1Text(_mapUnknown[var8]._field7_textId); return true; } diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 490f68dea4e7..d23e908d9d67 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -91,8 +91,8 @@ struct UnkMapStruct { uint8 _posY; uint8 _field3; uint8 _field4; - uint16 _field5; - uint16 _field7; + uint16 _field5_textId; + uint16 _field7_textId; void init(); }; @@ -137,8 +137,8 @@ struct NPCStruct { uint8 field_F; uint8 field_10; uint8 field_11; - uint16 field_12; - uint16 field_14; + uint16 field12_textId; + uint16 field14_textId; uint32 _xp; uint8 _activeScore[15]; uint8 _passiveScore[11]; @@ -210,7 +210,7 @@ struct MapMonster { uint8 _field_6; uint8 _monsterRef; uint8 _field_8; - uint8 _field_9; + uint8 _field9_textId; uint8 _groupSize; int16 _pictureRef[9]; }; @@ -318,7 +318,7 @@ class EfhEngine : public Engine { void displayMiddleLeftTempText(uint8 *impArray, bool flag); void sub15A28(int16 arg0, int16 arg2); void sub2455E(int16 arg0, int16 arg1, int16 arg2); - int16 sub1C219(Common::String str, int16 menuType, int16 arg4, bool displayTeamWindowFl); + int16 sub1C219(Common::String str, int16 menuType, int16 displayOption, bool displayTeamWindowFl); int16 sub151FD(int16 posX, int16 posY); bool isPosOutOfMap(int16 mapPosX, int16 mapPosY); void goSouth(); @@ -352,7 +352,7 @@ class EfhEngine : public Engine { bool checkMonsterGroupDistance1OrLess(int16 monsterId); bool sub21820(int16 monsterId, int16 arg2, int16 itemId); void sub221D2(int16 monsterId); - void sub22AA8(int16 arg0); + void displayImp1Text(int16 textId); bool sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemId, int16 arg8, int16 imageSetId); int8 sub15581(int16 mapPosX, int16 mapPosY, int16 arg4); bool isTeamMemberStatusNormal(int16 id); diff --git a/engines/efh/files.cpp b/engines/efh/files.cpp index 38b6984f2662..79f71c03abe5 100644 --- a/engines/efh/files.cpp +++ b/engines/efh/files.cpp @@ -271,8 +271,8 @@ void EfhEngine::loadNPCS() { _npcBuf[i].field_F = f.readByte(); _npcBuf[i].field_10 = f.readByte(); _npcBuf[i].field_11 = f.readByte(); - _npcBuf[i].field_12 = f.readUint16LE(); - _npcBuf[i].field_14 = f.readUint16LE(); + _npcBuf[i].field12_textId = f.readUint16LE(); + _npcBuf[i].field14_textId = f.readUint16LE(); _npcBuf[i]._xp = f.readUint32LE(); for (int idx = 0; idx < 15; ++idx) { _npcBuf[i]._activeScore[idx] = f.readByte(); diff --git a/engines/efh/savegames.cpp b/engines/efh/savegames.cpp index 6401564e1034..e43bda6a8760 100644 --- a/engines/efh/savegames.cpp +++ b/engines/efh/savegames.cpp @@ -174,8 +174,8 @@ void EfhEngine::synchronize(Common::Serializer &s) { s.syncAsByte(_npcBuf[i].field_F); s.syncAsByte(_npcBuf[i].field_10); s.syncAsByte(_npcBuf[i].field_11); - s.syncAsSint16LE(_npcBuf[i].field_12); - s.syncAsSint16LE(_npcBuf[i].field_14); + s.syncAsSint16LE(_npcBuf[i].field12_textId); + s.syncAsSint16LE(_npcBuf[i].field14_textId); s.syncAsSint32LE(_npcBuf[i]._xp); for (int idx = 0; idx < 15; ++idx) s.syncAsByte(_npcBuf[i]._activeScore[idx]); From 41dd4d0b4bd89d6656b166a9d57761d663ab400b Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sun, 18 Dec 2022 22:36:20 +0100 Subject: [PATCH 188/412] EFH: Some renaming, verify some more functions (and use debugC for those) --- engines/efh/efh.cpp | 35 ++++++++--------------------------- engines/efh/efh.h | 11 ++++++----- engines/efh/fight.cpp | 17 +++++++++++++++-- engines/efh/files.cpp | 2 +- engines/efh/graphics.cpp | 9 +++++++++ engines/efh/script.cpp | 16 +++++++++------- engines/efh/utils.cpp | 10 +++++----- 7 files changed, 53 insertions(+), 47 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index b45042d66539..a3995f8a7e0e 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -392,7 +392,7 @@ Common::Error EfhEngine::run() { if (newMs - lastMs >= 220) { lastMs = newMs; - unkFct_anim(); + handleAnimations(); } Common::Event event; @@ -1156,18 +1156,6 @@ bool EfhEngine::isCharacterATeamMember(int16 id) { return false; } -bool EfhEngine::isTPK() { - debug("isTPK"); - - int16 zeroedChar = 0; - for (int counter = 0; counter < _teamSize; ++counter) { - if (_npcBuf[_teamCharId[counter]]._hitPoints <= 0) - ++zeroedChar; - } - - return zeroedChar == _teamSize; -} - void EfhEngine::handleWinSequence() { debugC(1, kDebugEngine, "handleWinSequence"); @@ -1748,7 +1736,7 @@ bool EfhEngine::handleDeathMenu() { } void EfhEngine::computeMapAnimation() { - debug("computeMapAnimation"); + debugC(6, kDebugEngine, "computeMapAnimation"); const int16 maxMapBlocks = _largeMapFlag ? 63 : 23; @@ -1797,13 +1785,13 @@ void EfhEngine::computeMapAnimation() { } } -void EfhEngine::unkFct_anim() { +void EfhEngine::handleAnimations() { setNumLock(); if (_engineInitPending) return; - debug("unkFct_anim"); + debugC(6, kDebugEngine, "handleAnimations"); if (_animImageSetId != 0xFF) { displayNextAnimFrame(); @@ -2435,7 +2423,7 @@ void EfhEngine::sub221D2(int16 monsterId) { } void EfhEngine::displayImp1Text(int16 textId) { - debug("displayImp1Text %d", textId); + debugC(6, kDebugEngine,"displayImp1Text %d", textId); int16 charCounter = 0; int16 stringIdx = 0; @@ -5381,17 +5369,10 @@ uint8 EfhEngine::getMapTileInfo(int16 mapPosX, int16 mapPosY) { return _curPlace[mapPosX][mapPosY]; } -void EfhEngine::displayNextAnimFrame() { - debug("displayNextAnimFrame"); - - if (++_unkAnimRelatedIndex >= 15) - _unkAnimRelatedIndex = 0; - - displayAnimFrame(); -} - void EfhEngine::writeTechAndMapFiles() { - warning("STUB - writeTechAndMapFiles"); + // The original game overwrite game data files when switching map, keeping track of modified data. + // In our implementation, we have everything in memory and save it in savegames only. + // This function is therefore not useful and is not implemented. } uint16 EfhEngine::getStringWidth(const char *buffer) { diff --git a/engines/efh/efh.h b/engines/efh/efh.h index d23e908d9d67..1cc11ce69820 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -60,7 +60,8 @@ static const uint8 kSavegameVersion = 1; enum AccessDebugChannels { kDebugEngine = 1 << 0, kDebugUtils = 1 << 1, - kDebugGraphics = 1 << 2 + kDebugGraphics = 1 << 2, + kDebugScript = 1 << 3 }; class EfhGraphicsStruct { @@ -295,7 +296,6 @@ class EfhEngine : public Engine { void saveEfhGame(); void copyCurrentPlaceToBuffer(int16 id); uint8 getMapTileInfo(int16 mapPosX, int16 mapPosY); - void displayNextAnimFrame(); void writeTechAndMapFiles(); uint16 getStringWidth(const char *buffer); void setTextPos(int16 textPosX, int16 textPosY); @@ -309,7 +309,6 @@ class EfhEngine : public Engine { void removeCharacterFromTeam(int16 teamMemberId); void refreshTeamSize(); bool isCharacterATeamMember(int16 id); - bool isTPK(); void handleWinSequence(); bool giveItemTo(int16 charId, int16 objectId, int16 altCharId); int16 chooseCharacterToReplace(); @@ -333,7 +332,7 @@ class EfhEngine : public Engine { void resetGame(); bool handleDeathMenu(); void computeMapAnimation(); - void unkFct_anim(); + void handleAnimations(); int8 sub16B08(int16 monsterId); bool moveMonsterAwayFromTeam(int16 monsterId); bool moveMonsterTowardsTeam(int16 monsterId); @@ -408,6 +407,7 @@ class EfhEngine : public Engine { void handleFight_lastAction_D(int16 teamCharId); void handleFight_lastAction_H(int16 teamCharId); void handleFight_lastAction_U(int16 teamCharId); + bool isTPK(); bool sub1BC74(int16 monsterId, int16 teamMonsterId); void sub1BCA7(int16 monsterTeamId); void reset_stru32686(); @@ -433,6 +433,7 @@ class EfhEngine : public Engine { // Graphics void initPalette(); void drawLeftCenterBox(); + void displayNextAnimFrame(); void displayAnimFrame(); void displayAnimFrames(int16 animId, bool displayMenuBoxFl); void displayFctFullScreen(); @@ -468,7 +469,7 @@ class EfhEngine : public Engine { // Script uint8 *script_readNumberArray(uint8 *buffer, int16 destArraySize, int16 *destArray); - uint8 *script_getNumber(uint8 *srcBuffer, int16 *retval); + uint8 *script_getNumber(uint8 *srcBuffer, int16 *retBuf); int16 script_parse(Common::String str, int16 posX, int16 posY, int16 maxX, int16 maxY, bool flag); // Sound diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index 3006e2073615..08aa415b02ca 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -611,11 +611,12 @@ void EfhEngine::handleFight_lastAction_H(int16 teamCharId) { void EfhEngine::handleFight_lastAction_U(int16 teamCharId) { debug("handleFight_lastAction_U %d", teamCharId); + // Fight - Action 'U' - Use Item // In the original, this function is part of handleFight. // It has been split for readability purposes. - int16 unk_monsterField5_itemId = _npcBuf[_teamCharId[teamCharId]]._inventory[_word31780[teamCharId]]._ref; + int16 itemId = _npcBuf[_teamCharId[teamCharId]]._inventory[_word31780[teamCharId]]._ref; _enemyNamePt2 = _npcBuf[_teamCharId[teamCharId]]._name; - _nameBuffer = _items[unk_monsterField5_itemId]._name; + _nameBuffer = _items[itemId]._name; int16 var70 = _npcBuf[_teamCharId[teamCharId]]._possessivePronounSHL6 >> 6; if (var70 == 2) _enemyNamePt1 = "The "; @@ -626,6 +627,18 @@ void EfhEngine::handleFight_lastAction_U(int16 teamCharId) { sub1C219(_messageToBePrinted, 1, 2, true); } +bool EfhEngine::isTPK() { + debugC(6, kDebugEngine,"isTPK"); + + int16 zeroedChar = 0; + for (int counter = 0; counter < _teamSize; ++counter) { + if (_npcBuf[_teamCharId[counter]]._hitPoints <= 0) + ++zeroedChar; + } + + return zeroedChar == _teamSize; +} + bool EfhEngine::sub1BC74(int16 monsterId, int16 teamMonsterId) { debug("sub1BC74 %d %d", monsterId, teamMonsterId); diff --git a/engines/efh/files.cpp b/engines/efh/files.cpp index 79f71c03abe5..8e1153dbd4c3 100644 --- a/engines/efh/files.cpp +++ b/engines/efh/files.cpp @@ -117,7 +117,7 @@ void EfhEngine::rImageFile(Common::String filename, uint8 *targetBuffer, uint8 * } void EfhEngine::readImpFile(int16 id, bool techMapFl) { - debug("readImpFile %d %s", id, techMapFl ? "True" : "False"); + debugC(6, kDebugEngine, "readImpFile %d %s", id, techMapFl ? "True" : "False"); Common::String fileName = Common::String::format("imp.%d", id); diff --git a/engines/efh/graphics.cpp b/engines/efh/graphics.cpp index 5062448b68ef..7d73ea35cf9a 100644 --- a/engines/efh/graphics.cpp +++ b/engines/efh/graphics.cpp @@ -56,6 +56,15 @@ void EfhEngine::drawLeftCenterBox() { drawColoredRect(16, 8, 111, 135, 0); } +void EfhEngine::displayNextAnimFrame() { + debugC(6, kDebugGraphics, "displayNextAnimFrame"); + + if (++_unkAnimRelatedIndex >= 15) + _unkAnimRelatedIndex = 0; + + displayAnimFrame(); +} + void EfhEngine::displayAnimFrame() { debugC(1, kDebugGraphics, "displayAnimFrame"); // The original had a parameter. As it was always equal to zero, it was removed in ScummVM diff --git a/engines/efh/script.cpp b/engines/efh/script.cpp index 5ebc63cbee9d..be42723e2f58 100644 --- a/engines/efh/script.cpp +++ b/engines/efh/script.cpp @@ -25,7 +25,7 @@ namespace Efh { uint8 *EfhEngine::script_readNumberArray(uint8 *srcBuffer, int16 destArraySize, int16 *destArray) { - debug("script_readNumberArray"); + debugC(6, kDebugScript, "script_readNumberArray"); uint8 *buffer = srcBuffer; for (int i = 0; i < destArraySize; ++i) { @@ -36,20 +36,22 @@ uint8 *EfhEngine::script_readNumberArray(uint8 *srcBuffer, int16 destArraySize, return buffer; } -uint8 *EfhEngine::script_getNumber(uint8 *srcBuffer, int16 *retval) { - debug("script_getNumber"); +uint8 *EfhEngine::script_getNumber(uint8 *srcBuffer, int16 *retBuf) { + debugC(6, kDebugScript, "script_getNumber"); uint8 *buffer = srcBuffer; - int16 var2 = 0; + int16 retVal = 0; for (;;) { uint8 curChar = *buffer; if (curChar < 0x30 || curChar > 0x39) { - *retval = var2; - return buffer; + break; } - var2 = var2 * 10 + curChar - 0x30; + retVal = retVal * 10 + curChar - 0x30; buffer++; } + + *retBuf = retVal; + return buffer; } int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 posY, int16 maxX, int16 maxY, bool flag) { diff --git a/engines/efh/utils.cpp b/engines/efh/utils.cpp index fb2b82a4b405..78a01fe96d1d 100644 --- a/engines/efh/utils.cpp +++ b/engines/efh/utils.cpp @@ -157,7 +157,7 @@ Common::KeyCode EfhEngine::getLastCharAfterAnimCount(int16 delay) { if (newMs - lastMs >= 200) { lastMs = newMs; --delay; - unkFct_anim(); + handleAnimations(); } lastChar = handleAndMapInput(false); @@ -182,7 +182,7 @@ Common::KeyCode EfhEngine::getInput(int16 delay) { if (newMs - lastMs >= 200) { lastMs = newMs; --delay; - unkFct_anim(); + handleAnimations(); } lastChar = handleAndMapInput(false); @@ -205,7 +205,7 @@ Common::KeyCode EfhEngine::waitForKey() { if (newMs - lastMs >= 200) { lastMs = newMs; - unkFct_anim(); + handleAnimations(); } _system->getEventManager()->pollEvent(event); @@ -248,7 +248,7 @@ Common::KeyCode EfhEngine::handleAndMapInput(bool animFl) { if (newMs - lastMs >= 200) { lastMs = newMs; - unkFct_anim(); + handleAnimations(); } } else break; @@ -276,7 +276,7 @@ Common::KeyCode EfhEngine::getInputBlocking() { if (newMs - lastMs >= 220) { lastMs = newMs; - unkFct_anim(); + handleAnimations(); } } return retVal; From 86b0c137c90ece062dd0f38451b029c4a513e665 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Mon, 19 Dec 2022 22:37:16 +0100 Subject: [PATCH 189/412] EFH: move some functions from efh to fight, tag some more functions as reviewed (via the use of debugC) --- engines/efh/efh.cpp | 434 +---------------------------------- engines/efh/efh.h | 11 +- engines/efh/fight.cpp | 518 ++++++++++++++++++++++++++++++++++++++---- 3 files changed, 480 insertions(+), 483 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index a3995f8a7e0e..8de22d8a284c 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -1099,14 +1099,14 @@ void EfhEngine::displayLowStatusScreen(bool flag) { void EfhEngine::removeObject(int16 charId, int16 objectId) { - debug("removeObject %d %d", charId, objectId); + debugC(6, kDebugEngine, "removeObject %d %d", charId, objectId); _npcBuf[charId]._inventory[objectId]._ref = 0x7FFF; _npcBuf[charId]._inventory[objectId]._stat1 = 0; _npcBuf[charId]._inventory[objectId]._stat2 = 0; } void EfhEngine::totalPartyKill() { - debug("totalPartyKill"); + debugC(6, kDebugEngine, "totalPartyKill"); for (uint counter = 0; counter < 3; ++counter) { if (_teamCharId[counter] != -1) @@ -1115,7 +1115,7 @@ void EfhEngine::totalPartyKill() { } void EfhEngine::removeCharacterFromTeam(int16 teamMemberId) { - debug("removeCharacterFromTeam %d", teamMemberId); + debugC(6, kDebugEngine, "removeCharacterFromTeam %d", teamMemberId); int16 charId = _teamCharId[teamMemberId]; _npcBuf[charId].field12_textId = _npcBuf[charId].field_B; @@ -1136,7 +1136,7 @@ void EfhEngine::removeCharacterFromTeam(int16 teamMemberId) { } void EfhEngine::refreshTeamSize() { - debug("refreshTeamSize"); + debugC(6, kDebugEngine, "refreshTeamSize"); _teamSize = 0; for (uint counter = 0; counter < 3; ++counter) { @@ -1146,7 +1146,7 @@ void EfhEngine::refreshTeamSize() { } bool EfhEngine::isCharacterATeamMember(int16 id) { - debug("isCharacterATeamMember %d", id); + debugC(6, kDebugEngine,"isCharacterATeamMember %d", id); for (int counter = 0; counter < _teamSize; ++counter) { if (_teamCharId[counter] == id) @@ -1803,9 +1803,8 @@ void EfhEngine::handleAnimations() { } int8 EfhEngine::sub16B08(int16 monsterId) { - debug("sub16B08 %d", monsterId); + debugC(3, kDebugEngine,"sub16B08 %d", monsterId); - // Simplified version compared to the original int16 maxSize = _largeMapFlag ? 63 : 23; if (_mapMonsters[monsterId]._posX < 0 || _mapMonsters[monsterId]._posY < 0 || _mapMonsters[monsterId]._posX > maxSize || _mapMonsters[monsterId]._posY > maxSize) return 0; @@ -2657,15 +2656,6 @@ int8 EfhEngine::sub15581(int16 mapPosX, int16 mapPosY, int16 arg4) { return _tileFact[imageSetId]._field0; } -bool EfhEngine::isTeamMemberStatusNormal(int16 teamMemberId) { - debug("isTeamMemberStatusNormal %d", teamMemberId); - - if (_npcBuf[_teamCharId[teamMemberId]]._hitPoints > 0 && _teamCharStatus[teamMemberId]._status == 0) - return true; - - return false; -} - void EfhEngine::sub1CDFA() { debug("sub1CDFA"); // Initiatives @@ -2738,63 +2728,6 @@ int16 EfhEngine::selectMonsterGroup() { return retVal; } -int16 EfhEngine::sub1C956(int16 charId, int16 unkFied18Val, bool arg4) { - debug("sub1C956 %d %d %d", charId, unkFied18Val, arg4); - - int16 varE = -1; - - int16 var6 = sub1C80A(charId, unkFied18Val, true); - int16 range = 0; - if (var6 != 0x7FFF) - range = _items[var6]._range; - - switch (range) { - case 3: - case 2: - ++range; - case 1: - ++range; - case 0: - ++range; - break; - case 4: - return 100; - default: - return varE; - } - - do { - for (uint counter = 0; counter < 2; ++counter) { - drawCombatScreen(charId, true, false); - if (_teamMonsterIdArray[1] != -1) - sub1C219("Select Monster Group:", 3, 0, false); - - if (counter == 0) - displayFctFullScreen(); - } - - if (_teamMonsterIdArray[1] == -1) - varE = 0; - else - varE = selectMonsterGroup(); - - if (!arg4) { - if (varE == 27) // Esc - varE = 0; - } else if (varE != 27) { - int16 monsterGroupDistance = computeMonsterGroupDistance(_teamMonsterIdArray[varE]); - if (monsterGroupDistance > range) { - varE = 27; - } - } - } while (varE == -1); - - if (varE == 27) - varE = -1; - - return varE; -} - void EfhEngine::sub1CAB6(int16 charId) { debug("sub1CAB6 %d", charId); @@ -2807,112 +2740,6 @@ void EfhEngine::sub1CAB6(int16 charId) { } } -bool EfhEngine::sub1CB27() { - debug("sub1CB27"); - - bool var4 = false; - for (int counter1 = 0; counter1 < _teamSize; ++counter1) { - _teamLastAction[counter1] = 0; - if (!isTeamMemberStatusNormal(counter1)) - continue; - - var4 = true; - do { - drawCombatScreen(_teamCharId[counter1], false, true); - Common::KeyCode var1 = handleAndMapInput(true); - switch (var1) { - case Common::KEYCODE_a: // Attack - _teamLastAction[counter1] = 'A'; - _teamNextAttack[counter1] = sub1C956(_teamCharId[counter1], 9, true); - if (_teamNextAttack[counter1] == -1) - _teamLastAction[counter1] = 0; - break; - case Common::KEYCODE_d: // Defend - _teamLastAction[counter1] = 'D'; - break; - case Common::KEYCODE_h: // Hide - _teamLastAction[counter1] = 'H'; - break; - case Common::KEYCODE_r: // Run - for (int counter2 = 0; counter2 < _teamSize; ++counter2) { - _teamLastAction[counter2] = 'R'; - } - return true; - case Common::KEYCODE_s: { // Status - int16 var8 = handleStatusMenu(2, _teamCharId[counter1]); - sub1CAB6(_teamCharId[counter1]); - if (var8 > 999) { - if (var8 == 0x7D00) - _teamLastAction[counter1] = 'S'; - } else { - _teamLastAction[counter1] = 'U'; - _word31780[counter1] = var8; - int16 var6 = _npcBuf[_teamCharId[counter1]]._inventory[var8]._ref; - switch (var6 - 1) { - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - case 8: - case 10: - case 12: - case 13: - _teamNextAttack[counter1] = sub1C956(_teamCharId[counter1], 9, false); - break; - - case 9: - case 11: - case 14: - case 15: - case 18: - case 24: - case 25: - case 27: - case 28: - case 29: - case 30: - sub1C219("Select Character:", 3, 1, false); - _teamNextAttack[counter1] = selectOtherCharFromTeam(); - break; - - case 16: - case 17: - case 26: - _teamNextAttack[counter1] = 0xC8; - break; - - case 19: - case 20: - case 21: - case 22: - case 23: - default: - break; - } - - } - - } - break; - case Common::KEYCODE_t: // Terrain - redrawScreenForced(); - getInputBlocking(); - drawCombatScreen(_teamCharId[counter1], false, true); - break; - default: - break; - } - } while (_teamLastAction[counter1] == 0); - - } - - return var4; -} - // The parameter isn't used in the original void EfhEngine::sub1BE9A(int16 monsterId) { debug("sub1BE9A %d", monsterId); @@ -3324,255 +3151,6 @@ bool EfhEngine::hasAdequateDefense_2(int16 charId, uint8 attackType) { return false; } -void EfhEngine::getDeathTypeDescription(int16 attackerId, int16 victimId) { - debug("getDeathTypeDescription %d %d", attackerId, victimId); - - int16 possessivePronoun; - - if (attackerId > 999) { - int16 charId = _teamCharId[attackerId - 1000]; - possessivePronoun = _npcBuf[charId]._possessivePronounSHL6 >> 6; - } else { - int16 charId = _teamMonsterIdArray[attackerId]; - possessivePronoun = _mapMonsters[charId]._possessivePronounSHL6 >> 6; - } - - if (possessivePronoun > 2) - possessivePronoun = 2; - - int16 deathType; - if (getRandom(100) < 20) { - deathType = 0; - } else { - if (victimId >= 1000) { - int16 charId = _teamCharId[victimId - 1000]; - if (charId == -1) - deathType = 0; - else { - int16 var6 = sub1C80A(charId, 9, true); - if (var6 == 0x7FFF) - deathType = 0; - else - deathType = _items[var6]._attackType + 1; - } - } else if (_teamMonsterIdArray[victimId] == -1) - deathType = 0; - else { - int16 itemId = _mapMonsters[_teamMonsterIdArray[victimId]]._itemId_Weapon; - deathType = _items[itemId]._attackType; - } - } - - int16 rndDescrForDeathType = getRandom((3)) - 1; - Common::String tmpStr = "DUDE IS TOAST!"; - switch (deathType) { - case 0: - switch (rndDescrForDeathType) { - case 0: - tmpStr = Common::String::format(", killing %s!", kPersonal[possessivePronoun]); - break; - case 1: - tmpStr = Common::String::format(", slaughtering %s!", kPersonal[possessivePronoun]); - break; - case 2: - tmpStr = Common::String::format(", annihilating %s!", kPersonal[possessivePronoun]); - break; - default: - break; - } - break; - case 1: - switch (rndDescrForDeathType) { - case 0: - tmpStr = Common::String::format(", cutting %s in two!", kPersonal[possessivePronoun]); - break; - case 1: - tmpStr = Common::String::format(", dicing %s into small cubes!", kPersonal[possessivePronoun]); - break; - case 2: - tmpStr = Common::String::format(", butchering %s into lamb chops!", kPersonal[possessivePronoun]); - break; - default: - break; - } - break; - case 2: - switch (rndDescrForDeathType) { - case 0: - tmpStr = Common::String::format(", piercing %s heart!", kPersonal[possessivePronoun]); - break; - case 1: - tmpStr = Common::String::format(", leaving %s a spouting mass of blood!", kPersonal[possessivePronoun]); - break; - case 2: - tmpStr = Common::String::format(", popping %s like a zit!", kPersonal[possessivePronoun]); - break; - default: - break; - } - break; - case 3: - switch (rndDescrForDeathType) { - case 0: - tmpStr = Common::String::format(", pulping %s head over a wide area!", kPersonal[possessivePronoun]); - break; - case 1: - tmpStr = Common::String::format(", smashing %s into a meat patty!", kPersonal[possessivePronoun]); - break; - case 2: - tmpStr = Common::String::format(", squashing %s like a ripe tomato!", kPersonal[possessivePronoun]); - break; - default: - break; - } - break; - case 4: - switch (rndDescrForDeathType) { - case 0: - tmpStr = Common::String::format(", totally incinerating %s!", kPersonal[possessivePronoun]); - break; - case 1: - tmpStr = Common::String::format(", reducing %s to a pile of ash!", kPersonal[possessivePronoun]); - break; - case 2: - tmpStr = Common::String::format(", leaving a blistered mass of flesh behind!"); - break; - default: - break; - } - break; - case 5: - switch (rndDescrForDeathType) { - case 0: - // The original has a typo: popscicle - tmpStr = Common::String::format(", turning %s into a popsicle!", kPersonal[possessivePronoun]); - break; - case 1: - tmpStr = Common::String::format(", encasing %s in a block of ice!", kPersonal[possessivePronoun]); - break; - case 2: - tmpStr = Common::String::format(", shattering %s into shards!", kPersonal[possessivePronoun]); - break; - default: - break; - } - break; - case 6: - switch (rndDescrForDeathType) { - case 0: - tmpStr = Common::String::format(", leaving pudding for brains"); - break; - case 1: - tmpStr = Common::String::format(", bursting %s head like a bubble!", kPersonal[possessivePronoun]); - break; - case 2: - tmpStr = Common::String::format(", turning %s into a mindless vegetable", kPersonal[possessivePronoun]); - break; - default: - break; - } - break; - case 7: - switch (rndDescrForDeathType) { - case 0: - tmpStr = Common::String::format(", reducing %s to an oozing pile of flesh!", kPersonal[possessivePronoun]); - break; - case 1: - tmpStr = Common::String::format(", melting %s like an ice cube in hot coffee!", kPersonal[possessivePronoun]); - break; - case 2: - tmpStr = Common::String::format(", vaporizing %s into a steaming cloud!", kPersonal[possessivePronoun]); - break; - default: - break; - } - break; - case 8: - switch (rndDescrForDeathType) { - case 0: - tmpStr = Common::String::format(", engulfing %s in black smoke puffs!", kPersonal[possessivePronoun]); - break; - case 1: - tmpStr = Common::String::format(", sucking %s into eternity!", kPersonal[possessivePronoun]); - break; - case 2: - tmpStr = Common::String::format(", turning %s into a mindless zombie!", kPersonal[possessivePronoun]); - break; - default: - break; - } - break; - case 9: - case 10: - case 11: - switch (rndDescrForDeathType) { - case 0: - tmpStr = Common::String::format(", completely disintegrating %s!", kPersonal[possessivePronoun]); - break; - case 1: - tmpStr = Common::String::format(", spreading %s into a fine mist!", kPersonal[possessivePronoun]); - break; - case 2: - tmpStr = Common::String::format(", leaving a smoking crater in %s place!", kPersonal[possessivePronoun]); - break; - default: - break; - } - break; - case 12: - case 13: - case 14: - switch (rndDescrForDeathType) { - case 0: - tmpStr = Common::String::format(", tearing a chunk out of %s back!", kPersonal[possessivePronoun]); - break; - case 1: - tmpStr = Common::String::format(", blowing %s brains out!", kPersonal[possessivePronoun]); - break; - case 2: - tmpStr = Common::String::format(", exploding %s entire chest!", kPersonal[possessivePronoun]); - break; - default: - break; - } - break; - case 15: - switch (rndDescrForDeathType) { - case 0: - tmpStr = Common::String::format(", choking %s to death!", kPersonal[possessivePronoun]); - break; - case 1: - tmpStr = Common::String::format(", melting %s lungs!", kPersonal[possessivePronoun]); - break; - case 2: - tmpStr = Common::String::format(", leaving %s gasping for air as %s collapses!", kPersonal[possessivePronoun], kPersonal[possessivePronoun]); - break; - default: - break; - } - break; - case 16: - switch (rndDescrForDeathType) { - case 0: - tmpStr = Common::String::format(", tearing a chunk out of %s back!", kPersonal[possessivePronoun]); - break; - case 1: - tmpStr = Common::String::format(", piercing %s heart!", kPersonal[possessivePronoun]); - break; - case 2: - tmpStr = Common::String::format(", impaling %s brain!", kPersonal[possessivePronoun]); - break; - default: - break; - } - break; - default: - break; - } - - _messageToBePrinted += tmpStr; -} - bool EfhEngine::characterSearchesMonsterCorpse(int16 charId, int16 monsterId) { debug("characterSearchesMonsterCorpse %d %d", charId, monsterId); diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 1cc11ce69820..46b6a2f28b37 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -61,7 +61,8 @@ enum AccessDebugChannels { kDebugEngine = 1 << 0, kDebugUtils = 1 << 1, kDebugGraphics = 1 << 2, - kDebugScript = 1 << 3 + kDebugScript = 1 << 3, + kDebugFight = 1 << 4 }; class EfhGraphicsStruct { @@ -354,13 +355,10 @@ class EfhEngine : public Engine { void displayImp1Text(int16 textId); bool sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemId, int16 arg8, int16 imageSetId); int8 sub15581(int16 mapPosX, int16 mapPosY, int16 arg4); - bool isTeamMemberStatusNormal(int16 id); void sub1CDFA(); void redrawScreenForced(); int16 selectMonsterGroup(); - int16 sub1C956(int16 charId, int16 unkFied18Val, bool arg4); void sub1CAB6(int16 charId); - bool sub1CB27(); void sub1BE9A(int16 monsterId); int16 getTeamMonsterAnimId(); int16 countMonsterGroupMembers(int16 monsterGroup); @@ -372,7 +370,6 @@ class EfhEngine : public Engine { bool checkSpecialItemsOnCurrentPlace(int16 itemId); bool hasAdequateDefense(int16 monsterId, uint8 attackType); bool hasAdequateDefense_2(int16 charId, uint8 attackType); - void getDeathTypeDescription(int16 attackerId, int16 victimId); bool characterSearchesMonsterCorpse(int16 charId, int16 monsterId); void getXPAndSearchCorpse(int16 charId, Common::String namePt1, Common::String namePt2, int16 monsterId); void addReactionText(int16 id); @@ -413,6 +410,10 @@ class EfhEngine : public Engine { void reset_stru32686(); void sub1BE89(int16 monsterId); void resetTeamMonsterIdArray(); + bool isTeamMemberStatusNormal(int16 id); + void getDeathTypeDescription(int16 attackerId, int16 victimId); + int16 sub1C956(int16 charId, int16 unkFied18Val, bool arg4); + bool sub1CB27(); // Files int32 readFileToBuffer(Common::String &filename, uint8 *destBuffer); diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index 08aa415b02ca..3ca3c8e41f89 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -23,6 +23,60 @@ namespace Efh { +void EfhEngine::sub1BCA7(int16 monsterTeamId) { + debug("sub1BCA7 %d", monsterTeamId); + + int16 counter = 0; + if (monsterTeamId != -1 && countPictureRef(monsterTeamId, false) > 0) { + counter = 1; + _teamMonsterIdArray[0] = monsterTeamId; + } + + for (int counter2 = 1; counter2 <= 3; ++counter2) { + if (counter >= 5) + break; + + for (uint monsterId = 0; monsterId < 64; ++monsterId) { + if (_mapMonsters[monsterId]._guess_fullPlaceId == 0xFF) + continue; + + if (((_mapMonsters[monsterId]._possessivePronounSHL6 & 0x3F) != 0x3F || isCharacterATeamMember(_mapMonsters[monsterId]._field_1)) && (_mapMonsters[monsterId]._possessivePronounSHL6 & 0x3F) > 0x3D) + continue; + + if (!checkIfMonsterOnSameLargeMapPlace(monsterId)) + continue; + + bool found = false; + for (uint counter3 = 0; counter3 < 9; ++counter3) { + if (_mapMonsters[monsterId]._pictureRef[counter3] > 0) { + found = true; + break; + } + } + + if (found) { + if (computeMonsterGroupDistance(monsterId) <= counter2 && !sub1BC74(monsterId, counter)) { + _teamMonsterIdArray[counter] = monsterId; + if (++counter >= 5) + break; + } + } + } + } + + if (counter > 4) + return; + + for (uint id = counter; id < 5; ++id) + _teamMonsterIdArray[id] = -1; +} + +void EfhEngine::sub1BE89(int16 monsterId) { + debug("sub1BE89 %d", monsterId); + sub1BCA7(monsterId); + reset_stru32686(); +} + bool EfhEngine::handleFight(int16 monsterId) { debug("handleFight %d", monsterId); @@ -628,7 +682,7 @@ void EfhEngine::handleFight_lastAction_U(int16 teamCharId) { } bool EfhEngine::isTPK() { - debugC(6, kDebugEngine,"isTPK"); + debugC(6, kDebugFight, "isTPK"); int16 zeroedChar = 0; for (int counter = 0; counter < _teamSize; ++counter) { @@ -649,76 +703,440 @@ bool EfhEngine::sub1BC74(int16 monsterId, int16 teamMonsterId) { return false; } -void EfhEngine::sub1BCA7(int16 monsterTeamId) { - debug("sub1BCA7 %d", monsterTeamId); +void EfhEngine::reset_stru32686() { + debug("reset_stru32686"); + for (uint counter1 = 0; counter1 < 5; ++counter1) { + for (uint counter2 = 0; counter2 < 9; ++counter2) { + _stru32686[counter1]._field0[counter2] = 0; + _stru32686[counter1]._field2[counter2] = 0; + } + } +} - int16 counter = 0; - if (monsterTeamId != -1 && countPictureRef(monsterTeamId, false) > 0) { - counter = 1; - _teamMonsterIdArray[0] = monsterTeamId; +void EfhEngine::resetTeamMonsterIdArray() { + debug("resetTeamMonsterIdArray"); + + for (int i = 0; i < 5; ++i) { + _teamMonsterIdArray[i] = -1; } +} - for (int counter2 = 1; counter2 <= 3; ++counter2) { - if (counter >= 5) - break; +bool EfhEngine::isTeamMemberStatusNormal(int16 teamMemberId) { + debugC(6, kDebugFight, "isTeamMemberStatusNormal %d", teamMemberId); - for (uint monsterId = 0; monsterId < 64; ++monsterId) { - if (_mapMonsters[monsterId]._guess_fullPlaceId == 0xFF) - continue; + if (_npcBuf[_teamCharId[teamMemberId]]._hitPoints > 0 && _teamCharStatus[teamMemberId]._status == 0) + return true; - if (((_mapMonsters[monsterId]._possessivePronounSHL6 & 0x3F) != 0x3F || isCharacterATeamMember(_mapMonsters[monsterId]._field_1)) && (_mapMonsters[monsterId]._possessivePronounSHL6 & 0x3F) > 0x3D) - continue; + return false; +} - if (!checkIfMonsterOnSameLargeMapPlace(monsterId)) - continue; +void EfhEngine::getDeathTypeDescription(int16 attackerId, int16 victimId) { + debug("getDeathTypeDescription %d %d", attackerId, victimId); - bool var6 = false; - for (uint counter3 = 0; counter3 < 9; ++counter3) { - if (_mapMonsters[monsterId]._pictureRef[counter3] > 0) { - var6 = true; - break; - } - } + int16 possessivePronoun; - if (var6) { - if (computeMonsterGroupDistance(monsterId) <= counter2 && !sub1BC74(monsterId, counter)) { - _teamMonsterIdArray[counter] = monsterId; - if (++counter >= 5) - break; - } + if (attackerId > 999) { + int16 charId = _teamCharId[attackerId - 1000]; + possessivePronoun = _npcBuf[charId]._possessivePronounSHL6 >> 6; + } else { + int16 charId = _teamMonsterIdArray[attackerId]; + possessivePronoun = _mapMonsters[charId]._possessivePronounSHL6 >> 6; + } + + if (possessivePronoun > 2) + possessivePronoun = 2; + + int16 deathType; + if (getRandom(100) < 20) { + deathType = 0; + } else { + if (victimId >= 1000) { + int16 charId = _teamCharId[victimId - 1000]; + if (charId == -1) + deathType = 0; + else { + int16 var6 = sub1C80A(charId, 9, true); + if (var6 == 0x7FFF) + deathType = 0; + else + deathType = _items[var6]._attackType + 1; } + } else if (_teamMonsterIdArray[victimId] == -1) + deathType = 0; + else { + int16 itemId = _mapMonsters[_teamMonsterIdArray[victimId]]._itemId_Weapon; + deathType = _items[itemId]._attackType; } } - if (counter > 4) - return; + int16 rndDescrForDeathType = getRandom((3)) - 1; + Common::String tmpStr = "DUDE IS TOAST!"; + switch (deathType) { + case 0: + switch (rndDescrForDeathType) { + case 0: + tmpStr = Common::String::format(", killing %s!", kPersonal[possessivePronoun]); + break; + case 1: + tmpStr = Common::String::format(", slaughtering %s!", kPersonal[possessivePronoun]); + break; + case 2: + tmpStr = Common::String::format(", annihilating %s!", kPersonal[possessivePronoun]); + break; + default: + break; + } + break; + case 1: + switch (rndDescrForDeathType) { + case 0: + tmpStr = Common::String::format(", cutting %s in two!", kPersonal[possessivePronoun]); + break; + case 1: + tmpStr = Common::String::format(", dicing %s into small cubes!", kPersonal[possessivePronoun]); + break; + case 2: + tmpStr = Common::String::format(", butchering %s into lamb chops!", kPersonal[possessivePronoun]); + break; + default: + break; + } + break; + case 2: + switch (rndDescrForDeathType) { + case 0: + tmpStr = Common::String::format(", piercing %s heart!", kPersonal[possessivePronoun]); + break; + case 1: + tmpStr = Common::String::format(", leaving %s a spouting mass of blood!", kPersonal[possessivePronoun]); + break; + case 2: + tmpStr = Common::String::format(", popping %s like a zit!", kPersonal[possessivePronoun]); + break; + default: + break; + } + break; + case 3: + switch (rndDescrForDeathType) { + case 0: + tmpStr = Common::String::format(", pulping %s head over a wide area!", kPersonal[possessivePronoun]); + break; + case 1: + tmpStr = Common::String::format(", smashing %s into a meat patty!", kPersonal[possessivePronoun]); + break; + case 2: + tmpStr = Common::String::format(", squashing %s like a ripe tomato!", kPersonal[possessivePronoun]); + break; + default: + break; + } + break; + case 4: + switch (rndDescrForDeathType) { + case 0: + tmpStr = Common::String::format(", totally incinerating %s!", kPersonal[possessivePronoun]); + break; + case 1: + tmpStr = Common::String::format(", reducing %s to a pile of ash!", kPersonal[possessivePronoun]); + break; + case 2: + tmpStr = Common::String::format(", leaving a blistered mass of flesh behind!"); + break; + default: + break; + } + break; + case 5: + switch (rndDescrForDeathType) { + case 0: + // The original has a typo: popscicle + tmpStr = Common::String::format(", turning %s into a popsicle!", kPersonal[possessivePronoun]); + break; + case 1: + tmpStr = Common::String::format(", encasing %s in a block of ice!", kPersonal[possessivePronoun]); + break; + case 2: + tmpStr = Common::String::format(", shattering %s into shards!", kPersonal[possessivePronoun]); + break; + default: + break; + } + break; + case 6: + switch (rndDescrForDeathType) { + case 0: + tmpStr = Common::String::format(", leaving pudding for brains"); + break; + case 1: + tmpStr = Common::String::format(", bursting %s head like a bubble!", kPersonal[possessivePronoun]); + break; + case 2: + tmpStr = Common::String::format(", turning %s into a mindless vegetable", kPersonal[possessivePronoun]); + break; + default: + break; + } + break; + case 7: + switch (rndDescrForDeathType) { + case 0: + tmpStr = Common::String::format(", reducing %s to an oozing pile of flesh!", kPersonal[possessivePronoun]); + break; + case 1: + tmpStr = Common::String::format(", melting %s like an ice cube in hot coffee!", kPersonal[possessivePronoun]); + break; + case 2: + tmpStr = Common::String::format(", vaporizing %s into a steaming cloud!", kPersonal[possessivePronoun]); + break; + default: + break; + } + break; + case 8: + switch (rndDescrForDeathType) { + case 0: + tmpStr = Common::String::format(", engulfing %s in black smoke puffs!", kPersonal[possessivePronoun]); + break; + case 1: + tmpStr = Common::String::format(", sucking %s into eternity!", kPersonal[possessivePronoun]); + break; + case 2: + tmpStr = Common::String::format(", turning %s into a mindless zombie!", kPersonal[possessivePronoun]); + break; + default: + break; + } + break; + case 9: + case 10: + case 11: + switch (rndDescrForDeathType) { + case 0: + tmpStr = Common::String::format(", completely disintegrating %s!", kPersonal[possessivePronoun]); + break; + case 1: + tmpStr = Common::String::format(", spreading %s into a fine mist!", kPersonal[possessivePronoun]); + break; + case 2: + tmpStr = Common::String::format(", leaving a smoking crater in %s place!", kPersonal[possessivePronoun]); + break; + default: + break; + } + break; + case 12: + case 13: + case 14: + switch (rndDescrForDeathType) { + case 0: + tmpStr = Common::String::format(", tearing a chunk out of %s back!", kPersonal[possessivePronoun]); + break; + case 1: + tmpStr = Common::String::format(", blowing %s brains out!", kPersonal[possessivePronoun]); + break; + case 2: + tmpStr = Common::String::format(", exploding %s entire chest!", kPersonal[possessivePronoun]); + break; + default: + break; + } + break; + case 15: + switch (rndDescrForDeathType) { + case 0: + tmpStr = Common::String::format(", choking %s to death!", kPersonal[possessivePronoun]); + break; + case 1: + tmpStr = Common::String::format(", melting %s lungs!", kPersonal[possessivePronoun]); + break; + case 2: + tmpStr = Common::String::format(", leaving %s gasping for air as %s collapses!", kPersonal[possessivePronoun], kPersonal[possessivePronoun]); + break; + default: + break; + } + break; + case 16: + switch (rndDescrForDeathType) { + case 0: + tmpStr = Common::String::format(", tearing a chunk out of %s back!", kPersonal[possessivePronoun]); + break; + case 1: + tmpStr = Common::String::format(", piercing %s heart!", kPersonal[possessivePronoun]); + break; + case 2: + tmpStr = Common::String::format(", impaling %s brain!", kPersonal[possessivePronoun]); + break; + default: + break; + } + break; + default: + break; + } - for (uint id = counter; id < 5; ++id) - _teamMonsterIdArray[id] = -1; + _messageToBePrinted += tmpStr; } -void EfhEngine::reset_stru32686() { - debug("reset_stru32686"); - for (uint counter1 = 0; counter1 < 5; ++counter1) { - for (uint counter2 = 0; counter2 < 9; ++counter2) { - _stru32686[counter1]._field0[counter2] = 0; - _stru32686[counter1]._field2[counter2] = 0; - } +int16 EfhEngine::sub1C956(int16 charId, int16 unkFied18Val, bool arg4) { + debug("sub1C956 %d %d %d", charId, unkFied18Val, arg4); + + int16 varE = -1; + + int16 var6 = sub1C80A(charId, unkFied18Val, true); + int16 range = 0; + if (var6 != 0x7FFF) + range = _items[var6]._range; + + switch (range) { + case 3: + case 2: + ++range; + case 1: + ++range; + case 0: + ++range; + break; + case 4: + return 100; + default: + return varE; } -} -void EfhEngine::sub1BE89(int16 monsterId) { - debug("sub1BE89 %d", monsterId); - sub1BCA7(monsterId); - reset_stru32686(); + do { + for (uint counter = 0; counter < 2; ++counter) { + drawCombatScreen(charId, true, false); + if (_teamMonsterIdArray[1] != -1) + sub1C219("Select Monster Group:", 3, 0, false); + + if (counter == 0) + displayFctFullScreen(); + } + + if (_teamMonsterIdArray[1] == -1) + varE = 0; + else + varE = selectMonsterGroup(); + + if (!arg4) { + if (varE == 27) // Esc + varE = 0; + } else if (varE != 27) { + int16 monsterGroupDistance = computeMonsterGroupDistance(_teamMonsterIdArray[varE]); + if (monsterGroupDistance > range) { + varE = 27; + } + } + } while (varE == -1); + + if (varE == 27) + varE = -1; + + return varE; } -void EfhEngine::resetTeamMonsterIdArray() { - debug("resetTeamMonsterIdArray"); +bool EfhEngine::sub1CB27() { + debug("sub1CB27"); + + bool var4 = false; + for (int counter1 = 0; counter1 < _teamSize; ++counter1) { + _teamLastAction[counter1] = 0; + if (!isTeamMemberStatusNormal(counter1)) + continue; + + var4 = true; + do { + drawCombatScreen(_teamCharId[counter1], false, true); + Common::KeyCode var1 = handleAndMapInput(true); + switch (var1) { + case Common::KEYCODE_a: // Attack + _teamLastAction[counter1] = 'A'; + _teamNextAttack[counter1] = sub1C956(_teamCharId[counter1], 9, true); + if (_teamNextAttack[counter1] == -1) + _teamLastAction[counter1] = 0; + break; + case Common::KEYCODE_d: // Defend + _teamLastAction[counter1] = 'D'; + break; + case Common::KEYCODE_h: // Hide + _teamLastAction[counter1] = 'H'; + break; + case Common::KEYCODE_r: // Run + for (int counter2 = 0; counter2 < _teamSize; ++counter2) { + _teamLastAction[counter2] = 'R'; + } + return true; + case Common::KEYCODE_s: { // Status + int16 var8 = handleStatusMenu(2, _teamCharId[counter1]); + sub1CAB6(_teamCharId[counter1]); + if (var8 > 999) { + if (var8 == 0x7D00) + _teamLastAction[counter1] = 'S'; + } else { + _teamLastAction[counter1] = 'U'; + _word31780[counter1] = var8; + int16 var6 = _npcBuf[_teamCharId[counter1]]._inventory[var8]._ref; + switch (var6 - 1) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 10: + case 12: + case 13: + _teamNextAttack[counter1] = sub1C956(_teamCharId[counter1], 9, false); + break; - for (int i = 0; i < 5; ++i) { - _teamMonsterIdArray[i] = -1; + case 9: + case 11: + case 14: + case 15: + case 18: + case 24: + case 25: + case 27: + case 28: + case 29: + case 30: + sub1C219("Select Character:", 3, 1, false); + _teamNextAttack[counter1] = selectOtherCharFromTeam(); + break; + + case 16: + case 17: + case 26: + _teamNextAttack[counter1] = 0xC8; + break; + + case 19: + case 20: + case 21: + case 22: + case 23: + default: + break; + } + } + + } break; + case Common::KEYCODE_t: // Terrain + redrawScreenForced(); + getInputBlocking(); + drawCombatScreen(_teamCharId[counter1], false, true); + break; + default: + break; + } + } while (_teamLastAction[counter1] == 0); } + + return var4; } } // End of namespace Efh From 19fae17e60893e3d905f90339b9b5006e0995a6b Mon Sep 17 00:00:00 2001 From: Strangerke Date: Tue, 20 Dec 2022 23:18:02 +0100 Subject: [PATCH 190/412] EFH: Fix a bug in checkMonsterCollision(), some renaming --- engines/efh/efh.cpp | 15 +++++++-------- engines/efh/efh.h | 4 ++-- engines/efh/files.cpp | 4 ++-- engines/efh/savegames.cpp | 4 ++-- 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 8de22d8a284c..944fd4359ea1 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -104,10 +104,10 @@ void ItemStruct::init() { void NPCStruct::init() { for (int i = 0; i < 11; ++i) _name[i] = 0; - field_B = 0; + fieldB_textId = 0; field_C = 0; field_D = 0; - field_E = 0; + fieldE_textId = 0; field_F = 0; field_10 = 0; field_11 = 0; @@ -1118,8 +1118,8 @@ void EfhEngine::removeCharacterFromTeam(int16 teamMemberId) { debugC(6, kDebugEngine, "removeCharacterFromTeam %d", teamMemberId); int16 charId = _teamCharId[teamMemberId]; - _npcBuf[charId].field12_textId = _npcBuf[charId].field_B; - _npcBuf[charId].field14_textId = _npcBuf[charId].field_E; + _npcBuf[charId].field12_textId = _npcBuf[charId].fieldB_textId; + _npcBuf[charId].field14_textId = _npcBuf[charId].fieldE_textId; _npcBuf[charId].field_10 = _npcBuf[charId].field_C; _npcBuf[charId].field_11 = _npcBuf[charId].field_D; @@ -1280,7 +1280,6 @@ int16 EfhEngine::chooseCharacterToReplace() { int16 EfhEngine::handleCharacterJoining() { debug("handleCharacterJoining"); - const char strReplaceWho[13] = "Replace Who?"; for (uint counter = 0; counter < 3; ++counter) { if (_teamCharId[counter] == -1) { return counter; @@ -1289,7 +1288,7 @@ int16 EfhEngine::handleCharacterJoining() { for (uint counter = 0; counter < 2; ++counter) { drawColoredRect(200, 112, 278, 132, 0); - displayCenteredString(strReplaceWho, 200, 278, 117); + displayCenteredString("Replace Who?", 200, 278, 117); if (counter == 0) displayFctFullScreen(); } @@ -4742,8 +4741,8 @@ bool EfhEngine::checkMonsterCollision() { if (!(_largeMapFlag && _mapMonsters[monsterId]._guess_fullPlaceId == 0xFE) && !(!_largeMapFlag && _mapMonsters[monsterId]._guess_fullPlaceId == _fullPlaceId)) continue; - if ((_mapMonsters[monsterId]._field_1 & 0x3F) > 0x3D - && (((_mapMonsters[monsterId]._possessivePronounSHL6 & 0x3F) == 0x3F) || isCharacterATeamMember(_mapMonsters[monsterId]._field_1))) + if ((_mapMonsters[monsterId]._possessivePronounSHL6 & 0x3F) > 0x3D + && !(((_mapMonsters[monsterId]._possessivePronounSHL6 & 0x3F) == 0x3F) && !isCharacterATeamMember(_mapMonsters[monsterId]._field_1))) continue; if (_mapMonsters[monsterId]._posX != _mapPosX || _mapMonsters[monsterId]._posY != _mapPosY) diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 46b6a2f28b37..18638bbcb488 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -132,10 +132,10 @@ struct ItemStruct { struct NPCStruct { char _name[11]; - uint8 field_B; + uint8 fieldB_textId; uint8 field_C; uint8 field_D; - uint8 field_E; + uint8 fieldE_textId; uint8 field_F; uint8 field_10; uint8 field_11; diff --git a/engines/efh/files.cpp b/engines/efh/files.cpp index 8e1153dbd4c3..e43026a2b1ce 100644 --- a/engines/efh/files.cpp +++ b/engines/efh/files.cpp @@ -264,10 +264,10 @@ void EfhEngine::loadNPCS() { for (int i = 0; i < 99; ++i) { for (int idx = 0; idx < 11; ++idx) _npcBuf[i]._name[idx] = f.readByte(); - _npcBuf[i].field_B = f.readByte(); + _npcBuf[i].fieldB_textId = f.readByte(); _npcBuf[i].field_C = f.readByte(); _npcBuf[i].field_D = f.readByte(); - _npcBuf[i].field_E = f.readByte(); + _npcBuf[i].fieldE_textId = f.readByte(); _npcBuf[i].field_F = f.readByte(); _npcBuf[i].field_10 = f.readByte(); _npcBuf[i].field_11 = f.readByte(); diff --git a/engines/efh/savegames.cpp b/engines/efh/savegames.cpp index e43bda6a8760..bdf6962ae1b4 100644 --- a/engines/efh/savegames.cpp +++ b/engines/efh/savegames.cpp @@ -167,10 +167,10 @@ void EfhEngine::synchronize(Common::Serializer &s) { for (int idx = 0; idx < 11; ++idx) s.syncAsByte(_npcBuf[i]._name[idx]); - s.syncAsByte(_npcBuf[i].field_B); + s.syncAsByte(_npcBuf[i].fieldB_textId); s.syncAsByte(_npcBuf[i].field_C); s.syncAsByte(_npcBuf[i].field_D); - s.syncAsByte(_npcBuf[i].field_E); + s.syncAsByte(_npcBuf[i].fieldE_textId); s.syncAsByte(_npcBuf[i].field_F); s.syncAsByte(_npcBuf[i].field_10); s.syncAsByte(_npcBuf[i].field_11); From 7e326f5cd3ce05601af10a6126d35a55af74f8dc Mon Sep 17 00:00:00 2001 From: Strangerke Date: Wed, 21 Dec 2022 09:09:43 +0100 Subject: [PATCH 191/412] EFH: validate some more functions, some renaming and code simplification --- engines/efh/efh.cpp | 92 +++++++++++++++++++++------------------------ engines/efh/efh.h | 2 +- 2 files changed, 43 insertions(+), 51 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 944fd4359ea1..1b2494cf72b8 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -304,7 +304,7 @@ EfhEngine::EfhEngine(OSystem *syst, const ADGameDescription *gd) : Engine(syst), _menuItemCounter = 0; for (int i = 0; i < 15; ++i) { - _word3273A[i] = 0; + _menuStatItemArr[i] = 0; } _messageToBePrinted = ""; @@ -3357,7 +3357,7 @@ void EfhEngine::sub1D8C2(int16 charId, int16 damage) { } void EfhEngine::displayMenuItemString(int16 menuBoxId, int16 thisBoxId, int16 minX, int16 maxX, int16 minY, const char *str) { - debug("displayMenuItemString %d %d %d->%d %d %s", menuBoxId, thisBoxId, minX, maxX, minY, str); + debugC(6, kDebugEngine, "displayMenuItemString %d %d %d->%d %d %s", menuBoxId, thisBoxId, minX, maxX, minY, str); if (menuBoxId == thisBoxId) { if (_menuDepth == 0) @@ -3379,7 +3379,7 @@ void EfhEngine::displayMenuItemString(int16 menuBoxId, int16 thisBoxId, int16 mi } void EfhEngine::displayStatusMenu(int16 windowId) { - debug("displayStatusMenu %d", windowId); + debugC(3, kDebugEngine, "displayStatusMenu %d", windowId); for (uint counter = 0; counter < 9; ++counter) { drawColoredRect(80, 39 + 14 * counter, 134, 47 + 14 * counter, 0); @@ -3402,49 +3402,40 @@ void EfhEngine::displayStatusMenu(int16 windowId) { } void EfhEngine::countRightWindowItems(int16 menuId, int16 charId) { - debug("countRightWindowItems %d %d", menuId, charId); + debugC(6, kDebugEngine, "countRightWindowItems %d %d", menuId, charId); - int16 var2 = 0; - int16 var4 = 0; + int16 maxId = 0; + int16 minId; _menuItemCounter = 0; switch (menuId) { - case 0: - case 1: - case 2: - case 3: - case 4: - case 9: - var4 = -1; - break; case 5: - var4 = 26; - var2 = 36; + minId = 26; + maxId = 36; break; case 6: - var4 = 15; - var2 = 25; + minId = 15; + maxId = 25; break; case 7: - var4 = 0; - var2 = 14; + minId = 0; + maxId = 14; break; - default: // Case 8 + Default - var4 = -1; - _menuItemCounter = 0; + default: + minId = -1; break; } - if (var4 == -1) { + if (minId == -1) { for (uint counter = 0; counter < 10; ++counter) { if (_npcBuf[charId]._inventory[counter]._ref != 0x7FFF) { - _word3273A[_menuItemCounter++] = counter; + _menuStatItemArr[_menuItemCounter++] = counter; } } } else { - for (int16 counter = var4; counter < var2; ++counter) { + for (int16 counter = minId; counter < maxId; ++counter) { if (_npcBuf[charId]._activeScore[counter] != 0) { - _word3273A[_menuItemCounter++] = counter; + _menuStatItemArr[_menuItemCounter++] = counter; } } } @@ -3472,7 +3463,7 @@ int16 EfhEngine::getXPLevel(int32 xp) { } void EfhEngine::displayCharacterSummary(int16 curMenuLine, int16 npcId) { - debug("displayCharacterSummary %d %d", curMenuLine, npcId); + debugC(3, kDebugEngine, "displayCharacterSummary %d %d", curMenuLine, npcId); setTextColorRed(); Common::String buffer1 = _npcBuf[npcId]._name; @@ -3516,9 +3507,9 @@ void EfhEngine::displayCharacterSummary(int16 curMenuLine, int16 npcId) { setTextColorWhite(); } int16 textPosY = 81 + counter * 9; - int16 itemId = _npcBuf[npcId]._inventory[_word3273A[counter]]._ref; + int16 itemId = _npcBuf[npcId]._inventory[_menuStatItemArr[counter]]._ref; if (itemId != 0x7FFF) { - if (_npcBuf[npcId]._inventory[_word3273A[counter]]._stat1 & 0x80) { + if (_npcBuf[npcId]._inventory[_menuStatItemArr[counter]]._stat1 & 0x80) { setTextPos(146, textPosY); displayCharAtTextPos('E'); } @@ -3539,23 +3530,24 @@ void EfhEngine::displayCharacterSummary(int16 curMenuLine, int16 npcId) { setTextPos(262, textPosY); if (_items[itemId]._defense > 0) { - int16 var54 = _npcBuf[npcId]._inventory[_word3273A[counter]]._stat2; - if (var54 == 0xFF) { - // useless? - var54 = _items[_npcBuf[npcId]._inventory[_word3273A[counter]]._ref]._defense; - } else { - buffer1 = Common::String::format("%d", 1 + var54 / 8); + int16 stat2 = _npcBuf[npcId]._inventory[_menuStatItemArr[counter]]._stat2; + if (stat2 != 0xFF) { + buffer1 = Common::String::format("%d", 1 + stat2 / 8); displayStringAtTextPos(buffer1); setTextPos(286, textPosY); displayStringAtTextPos("Def"); } + // useless code removed. + // else { + // var54 = _items[_npcBuf[npcId]._inventory[_menuStatItemArr[counter]]._ref]._defense; + // { } else if (_items[itemId]._uses != 0x7F) { - int16 var52 = _npcBuf[npcId]._inventory[_word3273A[counter]]._stat1; - if (var52 != 0x7F) { - buffer1 = Common::String::format("%d", var52); + int16 stat1 = _npcBuf[npcId]._inventory[_menuStatItemArr[counter]]._stat1; + if (stat1 != 0x7F) { + buffer1 = Common::String::format("%d", stat1); displayStringAtTextPos(buffer1); setTextPos(286, textPosY); - if (var52 == 1) + if (stat1 == 1) displayStringAtTextPos("Use"); else displayStringAtTextPos("Uses"); @@ -3595,8 +3587,8 @@ void EfhEngine::displayCharacterInformationOrSkills(int16 curMenuLine, int16 cha displayStringAtTextPos(buffer); setTextPos(163, textPosY); - displayStringAtTextPos(kSkillArray[_word3273A[counter]]); - buffer = Common::String::format("%d", _npcBuf[charId]._activeScore[_word3273A[counter]]); + displayStringAtTextPos(kSkillArray[_menuStatItemArr[counter]]); + buffer = Common::String::format("%d", _npcBuf[charId]._activeScore[_menuStatItemArr[counter]]); setTextPos(278, textPosY); displayStringAtTextPos(buffer); setTextColorRed(); @@ -4535,7 +4527,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { int16 itemId; switch (menuId) { case 0: - objectId = _word3273A[selectedLine]; + objectId = _menuStatItemArr[selectedLine]; itemId = _npcBuf[charId]._inventory[objectId]._ref; sub191FF(charId, objectId, windowId, menuId, curMenuLine); if (gameMode == 2) { @@ -4545,7 +4537,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { } break; case 1: - objectId = _word3273A[selectedLine]; + objectId = _menuStatItemArr[selectedLine]; itemId = _npcBuf[charId]._inventory[objectId]._ref; if (gameMode == 2) { restoreAnimImageSetId(); @@ -4561,7 +4553,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { sub19E2E(charId, objectId, windowId, menuId, curMenuLine, 2); break; case 2: - objectId = _word3273A[selectedLine]; + objectId = _menuStatItemArr[selectedLine]; itemId = _npcBuf[charId]._inventory[objectId]._ref; if (hasObjectEquipped(charId, objectId) && isItemCursed(itemId)) { displayString_3("The item is cursed! IT IS EVIL!!!!!!!!", true, charId, windowId, menuId, curMenuLine); @@ -4587,7 +4579,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { break; case 3: - objectId = _word3273A[selectedLine]; + objectId = _menuStatItemArr[selectedLine]; itemId = _npcBuf[charId]._inventory[objectId]._ref; if (hasObjectEquipped(charId, objectId) && isItemCursed(itemId)) { displayString_3("The item is cursed! IT IS EVIL!!!!!!!!", true, charId, windowId, menuId, curMenuLine); @@ -4645,7 +4637,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { } break; case 4: - objectId = _word3273A[selectedLine]; + objectId = _menuStatItemArr[selectedLine]; itemId = _npcBuf[charId]._inventory[objectId]._ref; if (hasObjectEquipped(charId, objectId) && isItemCursed(itemId)) { displayString_3("The item is cursed! IT IS EVIL!!!!!!!!", true, charId, windowId, menuId, curMenuLine); @@ -4672,7 +4664,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { } break; case 5: - objectId = _word3273A[selectedLine]; + objectId = _menuStatItemArr[selectedLine]; if (gameMode == 2) { displayString_3("Not a Combat Option!", true, charId, windowId, menuId, curMenuLine); } else { @@ -4684,7 +4676,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { } break; case 6: // Identical to case 5? - objectId = _word3273A[selectedLine]; + objectId = _menuStatItemArr[selectedLine]; if (gameMode == 2) { displayString_3("Not a Combat Option!", true, charId, windowId, menuId, curMenuLine); } else { @@ -4696,7 +4688,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { } break; case 7: // Identical to case 5? - objectId = _word3273A[selectedLine]; + objectId = _menuStatItemArr[selectedLine]; if (gameMode == 2) { displayString_3("Not a Combat Option!", true, charId, windowId, menuId, curMenuLine); } else { diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 18638bbcb488..4b02a2841ec3 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -601,7 +601,7 @@ class EfhEngine : public Engine { int16 _teamNextAttack[3]; int16 _word31780[3]; - int16 _word3273A[15]; + int16 _menuStatItemArr[15]; Stru32686 _stru32686[5]; Stru3244C _stru3244C[8]; }; From 4395cfc17e2f2c3312d92279c5387c25489ec11b Mon Sep 17 00:00:00 2001 From: Strangerke Date: Thu, 22 Dec 2022 00:31:14 +0100 Subject: [PATCH 192/412] EFH: Double check more functions, some renaming --- engines/efh/efh.cpp | 153 ++++++++++++++++++++++++-------------------- 1 file changed, 84 insertions(+), 69 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 1b2494cf72b8..110b07184b3f 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -1511,7 +1511,7 @@ bool EfhEngine::isPosOutOfMap(int16 mapPosX, int16 mapPosY) { } void EfhEngine::goSouth() { - debug("goSouth"); + debugC(6,kDebugEngine, "goSouth"); if (_largeMapFlag) { if (++_mapPosY > 63) @@ -1528,7 +1528,7 @@ void EfhEngine::goSouth() { } void EfhEngine::goNorth() { - debug("goNorth"); + debugC(6,kDebugEngine, "goNorth"); if (--_mapPosY < 0) _mapPosY = 0; @@ -1540,7 +1540,7 @@ void EfhEngine::goNorth() { } void EfhEngine::goEast() { - debug("goEast"); + debugC(6, kDebugEngine, "goEast"); if (_largeMapFlag) { if (++_mapPosX > 63) @@ -1557,7 +1557,7 @@ void EfhEngine::goEast() { } void EfhEngine::goWest() { - debug("goWest"); + debugC(6, kDebugEngine, "goWest"); if (--_mapPosX < 0) _mapPosX = 0; @@ -1569,7 +1569,7 @@ void EfhEngine::goWest() { } void EfhEngine::goNorthEast() { - debug("goNorthEast"); + debugC(6, kDebugEngine, "goNorthEast"); if (--_mapPosY < 0) _mapPosY = 0; @@ -1589,7 +1589,7 @@ void EfhEngine::goNorthEast() { } void EfhEngine::goSouthEast() { - debug("goSouthEast"); + debugC(6, kDebugEngine, "goSouthEast"); if (_largeMapFlag) { if (++_mapPosX > 63) @@ -1610,7 +1610,7 @@ void EfhEngine::goSouthEast() { } void EfhEngine::goNorthWest() { - debug("goNorthWest"); + debugC(6, kDebugEngine,"goNorthWest"); if (--_mapPosY < 0) _mapPosY = 0; @@ -1625,7 +1625,7 @@ void EfhEngine::goNorthWest() { } void EfhEngine::goSouthWest() { - debug("goSouthWest"); + debugC(6, kDebugEngine, "goSouthWest"); if (--_mapPosX < 0) _mapPosX = 0; @@ -1828,7 +1828,7 @@ int8 EfhEngine::sub16B08(int16 monsterId) { } bool EfhEngine::moveMonsterAwayFromTeam(int16 monsterId) { - debug("moveMonsterAwayFromTeam %d", monsterId); + debugC(6, kDebugEngine, "moveMonsterAwayFromTeam %d", monsterId); if (_mapMonsters[monsterId]._posX < _mapPosX) { --_mapMonsters[monsterId]._posX; @@ -1847,7 +1847,7 @@ bool EfhEngine::moveMonsterAwayFromTeam(int16 monsterId) { else if (_mapMonsters[monsterId]._posY > _mapPosY) ++_mapMonsters[monsterId]._posY; - return true; + return true; } // Original checks for posX equality, which is the only possible option at this point => skipped @@ -1862,7 +1862,7 @@ bool EfhEngine::moveMonsterAwayFromTeam(int16 monsterId) { } bool EfhEngine::moveMonsterTowardsTeam(int16 monsterId) { - debug("moveMonsterTowardsTeam %d", monsterId); + debugC(6, kDebugEngine, "moveMonsterTowardsTeam %d", monsterId); if (_mapMonsters[monsterId]._posX < _mapPosX) { ++_mapMonsters[monsterId]._posX; @@ -1896,40 +1896,53 @@ bool EfhEngine::moveMonsterTowardsTeam(int16 monsterId) { } bool EfhEngine::moveMonsterGroupOther(int16 monsterId, int16 direction) { - debug("moveMonsterGroupOther %d %d", monsterId, direction); + debugC(6, kDebugEngine, "moveMonsterGroupOther %d %d", monsterId, direction); + + bool retVal; switch (direction - 1) { case 0: --_mapMonsters[monsterId]._posY; - return true; + retVal = true; + break; case 1: --_mapMonsters[monsterId]._posY; ++_mapMonsters[monsterId]._posX; - return true; + retVal = true; + break; case 2: ++_mapMonsters[monsterId]._posX; - return true; + retVal = true; + break; case 3: ++_mapMonsters[monsterId]._posX; ++_mapMonsters[monsterId]._posY; - return true; + retVal = true; + break; case 4: ++_mapMonsters[monsterId]._posY; - return true; + retVal = true; + break; case 5: ++_mapMonsters[monsterId]._posY; --_mapMonsters[monsterId]._posX; - return true; + retVal = true; + break; case 6: --_mapMonsters[monsterId]._posX; - return true; + retVal = true; + break; case 7: --_mapMonsters[monsterId]._posX; --_mapMonsters[monsterId]._posY; - return true; + retVal = true; + break; default: - return false; + retVal = false; + break; } + + return retVal; } bool EfhEngine::moveMonsterGroup(int16 monsterId) { @@ -2052,8 +2065,8 @@ void EfhEngine::sub174A0() { if (var4 < minDisplayedMapX || var4 > maxDisplayedMapX || var2 < minDisplayedMapY || var2 > maxDisplayedMapY) continue; - bool var1A = false; - int16 var14 = 0; + bool monsterMovedFl = false; + int16 lastRangeCheck = 0; sub174A0_monsterPosX = _mapMonsters[monsterId]._posX; sub174A0_monsterPosY = _mapMonsters[monsterId]._posY; @@ -2070,106 +2083,106 @@ void EfhEngine::sub174A0() { switch (var1C - 1) { case 0: if (getRandom(100) >= 0xE - var1E) - var1A = moveMonsterTowardsTeam(monsterId); + monsterMovedFl = moveMonsterTowardsTeam(monsterId); else - var1A = moveMonsterGroup(monsterId); + monsterMovedFl = moveMonsterGroup(monsterId); break; case 1: if (getRandom(100) >= 0xE - var1E) - var1A = moveMonsterAwayFromTeam(monsterId); + monsterMovedFl = moveMonsterAwayFromTeam(monsterId); else - var1A = moveMonsterGroup(monsterId); + monsterMovedFl = moveMonsterGroup(monsterId); break; case 2: - var1A = moveMonsterGroupOther(monsterId, getRandom(8)); + monsterMovedFl = moveMonsterGroupOther(monsterId, getRandom(8)); break; case 3: - var1A = moveMonsterGroup(monsterId); + monsterMovedFl = moveMonsterGroup(monsterId); break; case 4: if (getRandom(100) > 0x32 - var1E) - var1A = moveMonsterTowardsTeam(monsterId); + monsterMovedFl = moveMonsterTowardsTeam(monsterId); else - var1A = moveMonsterGroup(monsterId); + monsterMovedFl = moveMonsterGroup(monsterId); break; case 5: if (getRandom(100) > 0x32 - var1E) - var1A = moveMonsterAwayFromTeam(monsterId); + monsterMovedFl = moveMonsterAwayFromTeam(monsterId); else - var1A = moveMonsterGroup(monsterId); + monsterMovedFl = moveMonsterGroup(monsterId); break; case 6: if (getRandom(100) >= 0x32 - var1E) - var1A = moveMonsterGroup(monsterId); + monsterMovedFl = moveMonsterGroup(monsterId); break; case 7: // var14 is not a typo. - var14 = checkMonsterWeaponRange(monsterId); + lastRangeCheck = checkMonsterWeaponRange(monsterId); break; case 8: - var14 = checkMonsterWeaponRange(monsterId); - if (var14 == 0) { + lastRangeCheck = checkMonsterWeaponRange(monsterId); + if (lastRangeCheck == 0) { if (getRandom(100) >= 0xE - var1E) - var1A = moveMonsterTowardsTeam(monsterId); + monsterMovedFl = moveMonsterTowardsTeam(monsterId); else - var1A = moveMonsterGroup(monsterId); + monsterMovedFl = moveMonsterGroup(monsterId); } break; case 9: - var14 = checkMonsterWeaponRange(monsterId); - if (var14 == 0) { + lastRangeCheck = checkMonsterWeaponRange(monsterId); + if (lastRangeCheck == 0) { if (getRandom(100) >= 0xE - var1E) - var1A = moveMonsterAwayFromTeam(monsterId); + monsterMovedFl = moveMonsterAwayFromTeam(monsterId); else - var1A = moveMonsterGroup(monsterId); + monsterMovedFl = moveMonsterGroup(monsterId); } break; case 10: - var14 = checkMonsterWeaponRange(monsterId); - if (var14 == 0) { - var1A = moveMonsterGroupOther(monsterId, getRandom(8)); + lastRangeCheck = checkMonsterWeaponRange(monsterId); + if (lastRangeCheck == 0) { + monsterMovedFl = moveMonsterGroupOther(monsterId, getRandom(8)); } break; case 11: - var14 = checkMonsterWeaponRange(monsterId); - if (var14 == 0) { - var1A = moveMonsterGroup(monsterId); + lastRangeCheck = checkMonsterWeaponRange(monsterId); + if (lastRangeCheck == 0) { + monsterMovedFl = moveMonsterGroup(monsterId); } break; case 12: - var14 = checkMonsterWeaponRange(monsterId); - if (var14 == 0) { + lastRangeCheck = checkMonsterWeaponRange(monsterId); + if (lastRangeCheck == 0) { if (getRandom(100) >= 0x32 - var1E) - var1A = moveMonsterTowardsTeam(monsterId); + monsterMovedFl = moveMonsterTowardsTeam(monsterId); else - var1A = moveMonsterGroup(monsterId); + monsterMovedFl = moveMonsterGroup(monsterId); } break; case 13: - var14 = checkMonsterWeaponRange(monsterId); - if (var14 == 0) { + lastRangeCheck = checkMonsterWeaponRange(monsterId); + if (lastRangeCheck == 0) { if (getRandom(100) >= 0x32 - var1E) - var1A = moveMonsterAwayFromTeam(monsterId); + monsterMovedFl = moveMonsterAwayFromTeam(monsterId); else - var1A = moveMonsterGroup(monsterId); + monsterMovedFl = moveMonsterGroup(monsterId); } break; case 14: - var14 = checkMonsterWeaponRange(monsterId); - if (var14 == 0 && getRandom(100) >= 0x32 - var1E) - var1A = moveMonsterGroup(monsterId); + lastRangeCheck = checkMonsterWeaponRange(monsterId); + if (lastRangeCheck == 0 && getRandom(100) >= 0x32 - var1E) + monsterMovedFl = moveMonsterGroup(monsterId); break; default: break; } for (;;) { - if (!var1A) { - if (var14 == 0) { - var1A = true; + if (!monsterMovedFl) { + if (lastRangeCheck == 0) { + monsterMovedFl = true; } else { unkMonsterId = monsterId; - var1A = true; + monsterMovedFl = true; } } else { int8 var18 = sub16B08(monsterId); @@ -2177,7 +2190,7 @@ void EfhEngine::sub174A0() { if (var18 == 0) { _mapMonsters[monsterId]._posX = sub174A0_monsterPosX; _mapMonsters[monsterId]._posY = sub174A0_monsterPosY; - var1A = false; + monsterMovedFl = false; --var16; } else if (var18 == 2) { _mapMonsters[monsterId]._posX = sub174A0_monsterPosX; @@ -2185,14 +2198,14 @@ void EfhEngine::sub174A0() { } } - if (!var1A && var16 == 1 && var1E > 1) { - var1A = moveMonsterGroupOther(monsterId, getRandom(8)); + if (!monsterMovedFl && var16 == 1 && var1E > 1) { + monsterMovedFl = moveMonsterGroupOther(monsterId, getRandom(8)); continue; } break; } - } while (!var1A && var16 > 0); + } while (!monsterMovedFl && var16 > 0); } if (unkMonsterId != -1) @@ -3559,7 +3572,7 @@ void EfhEngine::displayCharacterSummary(int16 curMenuLine, int16 npcId) { } void EfhEngine::displayCharacterInformationOrSkills(int16 curMenuLine, int16 charId) { - debug("displayCharacterInformationOrSkills %d %d", curMenuLine, charId); + debugC(3, kDebugEngine, "displayCharacterInformationOrSkills %d %d", curMenuLine, charId); setTextColorRed(); Common::String buffer = _npcBuf[charId]._name; @@ -3639,6 +3652,8 @@ void EfhEngine::displayStatusMenuActions(int16 menuId, int16 curMenuLine, int16 displayCenteredString("Character Summary", 144, 310, 15); displayCharacterSummary(curMenuLine, npcId); break; + default: + break; } } From a354207813b346b75ee16c64748dc0b4be0cd86a Mon Sep 17 00:00:00 2001 From: Strangerke Date: Fri, 23 Dec 2022 08:53:00 +0100 Subject: [PATCH 193/412] EFH: Disable saving during intro, winning sequence and after death, some renaming and functions review --- engines/efh/efh.cpp | 65 ++++++++++++++++++++------------------- engines/efh/efh.h | 6 ++-- engines/efh/savegames.cpp | 2 +- 3 files changed, 38 insertions(+), 35 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 110b07184b3f..fd601d708e17 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -296,7 +296,6 @@ EfhEngine::EfhEngine(OSystem *syst, const ADGameDescription *gd) : Engine(syst), _drawHeroOnMapFl = true; _drawMonstersOnMapFl = true; _word2C87A = false; - _dbgForceDisplayUpperRightBorder = false; _dbgForceMonsterBlock = false; _ongoingFightFl = false; _statusMenuActive = false; @@ -341,6 +340,8 @@ EfhEngine::EfhEngine(OSystem *syst, const ADGameDescription *gd) : Engine(syst), // If requested, load a savegame instead of showing the intro _loadSaveSlot = -1; + _saveAuthorized = false; + if (ConfMan.hasKey("save_slot")) { int saveSlot = ConfMan.getInt("save_slot"); if (saveSlot >= 0 && saveSlot <= 999) @@ -743,6 +744,8 @@ void EfhEngine::initEngine() { loadGameState(_loadSaveSlot); _loadSaveSlot = -1; } + + _saveAuthorized = true; _engineInitPending = false; } @@ -1010,17 +1013,9 @@ void EfhEngine::drawScreen() { if (!_largeMapFlag) { if (_fullPlaceId != 0xFF) displaySmallMap(_mapPosX, _mapPosY); - - // TODO: When refactoring : Always false, to be removed - if (_dbgForceDisplayUpperRightBorder) - drawUpperRightBorders(); } else { if (_techId != 0xFF) displayLargeMap(_mapPosX, _mapPosY); - - // TODO: When refactoring : Always false, to be removed - if (_dbgForceDisplayUpperRightBorder) - drawUpperRightBorders(); } if (counter == 0) displayFctFullScreen(); @@ -1158,6 +1153,7 @@ bool EfhEngine::isCharacterATeamMember(int16 id) { void EfhEngine::handleWinSequence() { debugC(1, kDebugEngine, "handleWinSequence"); + _saveAuthorized = false; saveAnimImageSetId(); findMapFile(18); @@ -1497,7 +1493,7 @@ int16 EfhEngine::sub151FD(int16 posX, int16 posY) { } bool EfhEngine::isPosOutOfMap(int16 mapPosX, int16 mapPosY) { - debug("isPosOutOfMap %d %d", mapPosX, mapPosY); + debugC(6, kDebugEngine, "isPosOutOfMap %d %d", mapPosX, mapPosY); int16 maxMapBlocks = _largeMapFlag ? 63 : 23; @@ -1678,6 +1674,8 @@ void EfhEngine::resetGame() { bool EfhEngine::handleDeathMenu() { debug("handleDeathMenu"); + _saveAuthorized = false; + displayAnimFrames(20, true); _imageSetSubFilesIdx = 213; drawScreen(); @@ -1709,9 +1707,13 @@ bool EfhEngine::handleDeathMenu() { switch (input) { case Common::KEYCODE_l: //loadEfhGame(); - //TODO : saveEfhGame opens the GUI save/load screen. It shouldn't bepossible to save at this point + //TODO: + //SaveEfhGame opens the GUI save/load screen. It's not possible to save at this point, which is fine, but it's possible to close the screen without loading. + //Maybe adding the _saveAuthorized flag in the savegame would do the trick and could then be used tp keep found at false and loop on the input selection? + //like: found = _saveAuthorized saveEfhGame(); found = true; + _saveAuthorized = true; break; case Common::KEYCODE_q: _shouldQuit = true; @@ -1721,8 +1723,9 @@ bool EfhEngine::handleDeathMenu() { loadEfhGame(); resetGame(); found = true; + _saveAuthorized = true; break; - case Common::KEYCODE_x: + case Common::KEYCODE_x: // mysterious and unexpected keycode ? found = true; break; default: @@ -3414,8 +3417,8 @@ void EfhEngine::displayStatusMenu(int16 windowId) { setTextColorRed(); } -void EfhEngine::countRightWindowItems(int16 menuId, int16 charId) { - debugC(6, kDebugEngine, "countRightWindowItems %d %d", menuId, charId); +void EfhEngine::prepareStatusRightWindowIndexes(int16 menuId, int16 charId) { + debugC(6, kDebugEngine, "prepareStatusRightWindowIndexes %d %d", menuId, charId); int16 maxId = 0; int16 minId; @@ -3455,21 +3458,21 @@ void EfhEngine::countRightWindowItems(int16 menuId, int16 charId) { } int16 EfhEngine::getXPLevel(int32 xp) { - debug("getXPLevel %ld", xp); + debugC(6, kDebugEngine, "getXPLevel %ld", xp); int16 level = 0; - int16 var6 = 1500; + int16 nextLevelXP = 1500; int32 wrkXp = xp; while (wrkXp > 0) { - wrkXp -= var6; + wrkXp -= nextLevelXP; if (wrkXp >= 0) ++level; - var6 += 1500; - if (var6 > 15000) - var6 = 15000; + nextLevelXP += 1500; + if (nextLevelXP > 15000) + nextLevelXP = 15000; } return level; @@ -3609,7 +3612,7 @@ void EfhEngine::displayCharacterInformationOrSkills(int16 curMenuLine, int16 cha } void EfhEngine::displayStatusMenuActions(int16 menuId, int16 curMenuLine, int16 npcId) { - debug("displayStatusMenuActions %d %d %d", menuId, curMenuLine, npcId); + debugC(6, kDebugEngine, "displayStatusMenuActions %d %d %d", menuId, curMenuLine, npcId); drawColoredRect(144, 15, 310, 184, 0); displayCenteredString("(ESCape Aborts)", 144, 310, 175); @@ -3657,12 +3660,12 @@ void EfhEngine::displayStatusMenuActions(int16 menuId, int16 curMenuLine, int16 } } -void EfhEngine::unk_StatusMenu(int16 windowId, int16 menuId, int16 curMenuLine, int16 charId, bool unusedFl, bool refreshFl) { - debug("unk_StatusMenu %d %d %d %d %s", windowId, menuId, curMenuLine, charId, refreshFl ? "True" : "False"); +void EfhEngine::prepareStatusMenu(int16 windowId, int16 menuId, int16 curMenuLine, int16 charId, bool unusedFl, bool refreshFl) { + debugC(6, kDebugEngine, "prepareStatusMenu %d %d %d %d %s", windowId, menuId, curMenuLine, charId, refreshFl ? "True" : "False"); displayStatusMenu(windowId); - countRightWindowItems(menuId, charId); + prepareStatusRightWindowIndexes(menuId, charId); displayStatusMenuActions(menuId, curMenuLine, charId); if (refreshFl) @@ -3674,7 +3677,7 @@ void EfhEngine::sub18E80(int16 charId, int16 windowId, int16 menuId, int16 curMe for (int counter = 0; counter < 2; ++counter) { displayWindow(_menuBuf, 0, 0, _hiResImageBuf); - unk_StatusMenu(windowId, menuId, curMenuLine, charId, true, false); + prepareStatusMenu(windowId, menuId, curMenuLine, charId, true, false); if (counter == 0) displayFctFullScreen(); @@ -3687,7 +3690,7 @@ int16 EfhEngine::displayString_3(Common::String str, bool animFl, int16 charId, int16 retVal = 0; for (uint counter = 0; counter < 2; ++counter) { - unk_StatusMenu(windowId, menuId, curMenuLine, charId, true, false); + prepareStatusMenu(windowId, menuId, curMenuLine, charId, true, false); displayWindow(_windowWithBorderBuf, 19, 113, _hiResImageBuf); if (counter == 0) { @@ -4393,7 +4396,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { for (;;) { if (windowId != -1) - unk_StatusMenu(windowId, menuId, curMenuLine, charId, true, true); + prepareStatusMenu(windowId, menuId, curMenuLine, charId, true, true); else windowId = 0; @@ -4474,7 +4477,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { _menuDepth = 0; curMenuLine = -1; menuId = 9; - unk_StatusMenu(windowId, menuId, curMenuLine, charId, true, true); + prepareStatusMenu(windowId, menuId, curMenuLine, charId, true, true); } else { selectedLine = curMenuLine; var10 = true; @@ -4485,7 +4488,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { _menuDepth = 0; curMenuLine = -1; menuId = 9; - unk_StatusMenu(windowId, menuId, curMenuLine, charId, true, true); + prepareStatusMenu(windowId, menuId, curMenuLine, charId, true, true); break; case Common::KEYCODE_2: case Common::KEYCODE_6: @@ -4530,9 +4533,9 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { } if (curMenuLine == -1) - unk_StatusMenu(windowId, menuId, curMenuLine, charId, false, true); + prepareStatusMenu(windowId, menuId, curMenuLine, charId, false, true); else - unk_StatusMenu(windowId, menuId, curMenuLine, charId, true, true); + prepareStatusMenu(windowId, menuId, curMenuLine, charId, true, true); } while (!var10); diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 4b02a2841ec3..65a04aa60bcb 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -279,6 +279,7 @@ class EfhEngine : public Engine { Common::Platform _platform; int _loadSaveSlot; + bool _saveAuthorized; void initialize(); Common::KeyCode playSong(uint8 *buffer); @@ -376,12 +377,12 @@ class EfhEngine : public Engine { void sub1D8C2(int16 charId, int16 damage); void displayMenuItemString(int16 menuBoxId, int16 thisBoxId, int16 minX, int16 maxX, int16 minY, const char *str); void displayStatusMenu(int16 windowId); - void countRightWindowItems(int16 menuId, int16 charId); + void prepareStatusRightWindowIndexes(int16 menuId, int16 charId); int16 getXPLevel(int32 xp); void displayCharacterSummary(int16 curMenuLine, int16 npcId); void displayCharacterInformationOrSkills(int16 curMenuLine, int16 npcId); void displayStatusMenuActions(int16 menuId, int16 curMenuLine, int16 npcId); - void unk_StatusMenu(int16 windowId, int16 menuId, int16 curMenuLine, int16 charId, bool unusedFl, bool refreshFl); + void prepareStatusMenu(int16 windowId, int16 menuId, int16 curMenuLine, int16 charId, bool unusedFl, bool refreshFl); void sub18E80(int16 charId, int16 windowId, int16 menuId, int16 curMenuLine); int16 displayString_3(Common::String str, bool animFl, int16 charId, int16 windowId, int16 menuId, int16 curMenuLine); bool isItemCursed(int16 itemId); @@ -589,7 +590,6 @@ class EfhEngine : public Engine { uint16 _tempTextDelay; uint8 *_tempTextPtr; // TODO: Remove those useless debug flags - bool _dbgForceDisplayUpperRightBorder; // Original debug flag? Always false. bool _dbgForceMonsterBlock; // Original debug flag? Always false. bool _ongoingFightFl; diff --git a/engines/efh/savegames.cpp b/engines/efh/savegames.cpp index bdf6962ae1b4..55eaf2198aa3 100644 --- a/engines/efh/savegames.cpp +++ b/engines/efh/savegames.cpp @@ -38,7 +38,7 @@ bool EfhEngine::canLoadGameStateCurrently() { } bool EfhEngine::canSaveGameStateCurrently() { - return true; + return _saveAuthorized; } Common::Error EfhEngine::loadGameState(int slot) { From 6e5899047a061f3a11c8892d2a14ca2d1f80cfdd Mon Sep 17 00:00:00 2001 From: Strangerke Date: Fri, 23 Dec 2022 09:14:04 +0100 Subject: [PATCH 194/412] EFH: Move several functions from EFH to Menu and Fight --- engines/efh/efh.cpp | 862 ------------------------------------------ engines/efh/efh.h | 44 ++- engines/efh/fight.cpp | 402 ++++++++++++++++++++ engines/efh/menu.cpp | 486 ++++++++++++++++++++++++ engines/efh/module.mk | 1 + 5 files changed, 912 insertions(+), 883 deletions(-) create mode 100644 engines/efh/menu.cpp diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index fd601d708e17..278859bcd3ab 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -1407,74 +1407,6 @@ void EfhEngine::sub2455E(int16 arg0, int16 arg2, int16 arg4) { } } -int16 EfhEngine::sub1C219(Common::String str, int16 menuType, int16 displayOption, bool displayTeamWindowFl) { - debug("sub1C219 %s %d %d %s", str.c_str(), menuType, displayOption, displayTeamWindowFl ? "True" : "False"); - - int16 varA = 0xFF; - int16 minX, maxX, minY, maxY; - - switch (menuType) { - case 0: - minX = 129; - minY = 9; - maxX = 302; - maxY = 18; - break; - case 1: - minX = 129; - minY = 9; - maxX = 302; - maxY = 110; - break; - case 2: - minX = 129; - minY = 112; - maxX = 302; - maxY = 132; - break; - case 3: - minX = 129; - minY = 79; - maxX = 303; - maxY = 107; - break; - default: - minX = minY = 0; - maxX = 320; - maxY = 200; - break; - } - - drawColoredRect(minX, minY, maxX, maxY, 0); - if (str.size()) - varA = script_parse(str, minX, minY, maxX, maxY, true); - - if (displayTeamWindowFl) - displayLowStatusScreen(false); - - if (displayOption != 0) { - displayFctFullScreen(); - if (_word2C87A) - _word2C87A = false; - else { - drawColoredRect(minX, minY, maxX, maxY, 0); - if (str.size()) - script_parse(str, minX, minY, maxX, maxY, false); - } - - if (displayTeamWindowFl) - displayLowStatusScreen(false); - - if (displayOption >= 2) - getLastCharAfterAnimCount(_guessAnimationAmount); - - if (displayOption == 3) - drawColoredRect(minX, minY, maxX, maxY, 0); - } - - return varA; -} - int16 EfhEngine::sub151FD(int16 posX, int16 posY) { debug("sub151FD %d %d", posX, posY); @@ -1671,72 +1603,6 @@ void EfhEngine::resetGame() { _unkArray2C8AA[0] = 0; } -bool EfhEngine::handleDeathMenu() { - debug("handleDeathMenu"); - - _saveAuthorized = false; - - displayAnimFrames(20, true); - _imageSetSubFilesIdx = 213; - drawScreen(); - - for (uint counter = 0; counter < 2; ++counter) { - clearBottomTextZone(0); - displayCenteredString("Darkness Prevails...Death Has Taken You!", 24, 296, 153); - setTextPos(100, 162); - setTextColorWhite(); - displayCharAtTextPos('L'); - setTextColorRed(); - displayStringAtTextPos("oad last saved game"); - setTextPos(100, 171); - setTextColorWhite(); - displayCharAtTextPos('R'); - setTextColorRed(); - displayStringAtTextPos("estart from beginning"); - setTextPos(100, 180); - setTextColorWhite(); - displayCharAtTextPos('Q'); - setTextColorRed(); - displayStringAtTextPos("uit for now"); - if (counter == 0) - displayFctFullScreen(); - } - - for (bool found = false; !found;) { - Common::KeyCode input = waitForKey(); - switch (input) { - case Common::KEYCODE_l: - //loadEfhGame(); - //TODO: - //SaveEfhGame opens the GUI save/load screen. It's not possible to save at this point, which is fine, but it's possible to close the screen without loading. - //Maybe adding the _saveAuthorized flag in the savegame would do the trick and could then be used tp keep found at false and loop on the input selection? - //like: found = _saveAuthorized - saveEfhGame(); - found = true; - _saveAuthorized = true; - break; - case Common::KEYCODE_q: - _shouldQuit = true; - return true; - break; - case Common::KEYCODE_r: - loadEfhGame(); - resetGame(); - found = true; - _saveAuthorized = true; - break; - case Common::KEYCODE_x: // mysterious and unexpected keycode ? - found = true; - break; - default: - break; - } - } - - displayAnimFrames(0xFE, true); - return false; -} - void EfhEngine::computeMapAnimation() { debugC(6, kDebugEngine, "computeMapAnimation"); @@ -2888,444 +2754,6 @@ int16 EfhEngine::countMonsterGroupMembers(int16 monsterGroup) { return result; } -void EfhEngine::sub1C4CA(bool whiteFl) { - debug("sub1C4CA %s", whiteFl ? "True" : "False"); - - int16 textPosY = 20; - for (uint counter = 0; counter < 5; ++counter) { - if (_teamMonsterIdArray[counter] == -1) - continue; - - int16 var6C = computeMonsterGroupDistance(_teamMonsterIdArray[counter]); - int16 var6E = countMonsterGroupMembers(counter); - if (whiteFl) - setTextColorWhite(); - else - setTextColorGrey(); - - setTextPos(129, textPosY); - char buffer[80]; - snprintf(buffer, 80, "%c)", 'A' + counter); - displayStringAtTextPos(buffer); - setTextColorRed(); - int16 var1 = _mapMonsters[_teamMonsterIdArray[counter]]._possessivePronounSHL6 & 0x3F; - if (var1 <= 0x3D) { - snprintf(buffer, 80, "%d %s", var6E, kEncounters[_mapMonsters[_teamMonsterIdArray[counter]]._monsterRef]._name); - displayStringAtTextPos(buffer); - if (var6E > 1) - displayStringAtTextPos("s"); - } else if (var1 == 0x3E) { - displayStringAtTextPos("(NOT DEFINED)"); - } else if (var1 == 0x3F) { - Common::String stringToDisplay = _npcBuf[_mapMonsters[_teamMonsterIdArray[counter]]._field_1]._name; - displayStringAtTextPos(stringToDisplay); - } - - setTextPos(228, textPosY); - if (unkFct_checkMonsterField8(counter, true)) { - _textColor = 0xE; - displayStringAtTextPos("Hostile"); - } else { - _textColor = 0x2; - displayStringAtTextPos("Friendly"); - } - - setTextColorRed(); - switch (var6C) { - case 1: - displayCenteredString("S", 290, 302, textPosY); - break; - case 2: - displayCenteredString("M", 290, 302, textPosY); - break; - case 3: - displayCenteredString("L", 290, 302, textPosY); - break; - default: - displayCenteredString("?", 290, 302, textPosY); - break; - } - - textPosY += 9; - } -} - -void EfhEngine::displayCombatMenu(int16 charId) { - debug("displayCombatMenu %d", charId); - - Common::String buffer = _npcBuf[charId]._name; - buffer += ":"; - setTextColorWhite(); - setTextPos(144, 7); - displayStringAtTextPos(buffer); - setTextPos(152, 79); - displayStringAtTextPos("A"); - setTextColorRed(); - displayStringAtTextPos("ttack"); - setTextPos(195, 79); - setTextColorWhite(); - displayStringAtTextPos("H"); - setTextColorRed(); - displayStringAtTextPos("ide"); - setTextPos(152, 88); - setTextColorWhite(); - displayStringAtTextPos("D"); - setTextColorRed(); - displayStringAtTextPos("efend"); - setTextPos(195, 88); - setTextColorWhite(); - displayStringAtTextPos("R"); - setTextColorRed(); - displayStringAtTextPos("un"); - setTextPos(152, 97); - setTextColorWhite(); - displayStringAtTextPos("S"); - setTextColorRed(); - displayStringAtTextPos("tatus"); -} - -void EfhEngine::drawCombatScreen(int16 charId, bool whiteFl, bool forceDrawFl) { - debug("drawCombatScreen %d %s %s", charId, whiteFl ? "True" : "False", forceDrawFl ? "True" : "False"); - - for (uint counter = 0; counter < 2; ++counter) { - if (counter == 0 || forceDrawFl) { - drawMapWindow(); - displayCenteredString("Combat", 128, 303, 9); - drawColoredRect(200, 112, 278, 132, 0); - displayCenteredString("'T' for Terrain", 128, 303, 117); - sub1C219("", 1, 0, false); - sub1C4CA(whiteFl); - displayCombatMenu(charId); - displayLowStatusScreen(false); - } - - if (counter == 0 && forceDrawFl) - displayFctFullScreen(); - } -} - -int16 EfhEngine::sub1DEC8(int16 groupNumber) { - debug("sub1DEC8 %d", groupNumber); - - int16 var4 = -1; - int16 monsterId = _teamMonsterIdArray[groupNumber]; - - if (monsterId == -1) - return -1; - - for (uint counter = 0; counter < 9; ++counter) { - if (isMonsterActive(groupNumber, counter)) { - var4 = counter; - break; - } - } - - for (int16 counter = var4 + 1; counter < 9; ++counter) { - if (!isMonsterActive(groupNumber, counter)) - continue; - - if (_mapMonsters[monsterId]._pictureRef[var4] > _mapMonsters[monsterId]._pictureRef[counter]) - var4 = counter; - } - - if (_mapMonsters[monsterId]._pictureRef[var4] <= 0) - return -1; - - return var4; -} - -int16 EfhEngine::getCharacterScore(int16 charId, int16 itemId) { - debug("getCharacterScore %d %d", charId, itemId); - - int16 totalScore = 0; - switch (_items[itemId]._range) { - case 0: - totalScore = _npcBuf[charId]._passiveScore[5] + _npcBuf[charId]._passiveScore[3] + _npcBuf[charId]._passiveScore[4]; - totalScore += _npcBuf[charId]._infoScore[0] / 5; - totalScore += _npcBuf[charId]._infoScore[2] * 2, - totalScore += _npcBuf[charId]._infoScore[6] / 5; - totalScore += 2 * _npcBuf[charId]._infoScore[5] / 5; - break; - case 1: - totalScore = _npcBuf[charId]._passiveScore[3] + _npcBuf[charId]._passiveScore[4]; - totalScore += _npcBuf[charId]._infoScore[2] * 2; - totalScore += _npcBuf[charId]._infoScore[1] / 5; - totalScore += _npcBuf[charId]._infoScore[3] / 5; - break; - case 2: - case 3: - case 4: - totalScore = _npcBuf[charId]._passiveScore[1]; - totalScore += _npcBuf[charId]._infoScore[2] * 2; - totalScore += _npcBuf[charId]._infoScore[1] / 5; - totalScore += _npcBuf[charId]._infoScore[3] / 5; - totalScore += _npcBuf[charId]._infoScore[8] / 5; - default: - break; - } - - int16 extraScore = 0; - switch (_items[itemId]._attackType) { - case 0: - case 1: - case 2: - if (itemId == 0x3F) - extraScore = _npcBuf[charId]._passiveScore[2]; - else if (itemId == 0x41 || itemId == 0x42 || itemId == 0x6A || itemId == 0x6C || itemId == 0x6D) - extraScore = _npcBuf[charId]._passiveScore[0]; - break; - case 3: - case 4: - case 6: - extraScore = _npcBuf[charId]._infoScore[7]; - break; - case 5: - case 7: - extraScore = _npcBuf[charId]._infoScore[9]; - break; - case 8: - case 9: - extraScore = _npcBuf[charId]._activeScore[12]; - break; - case 10: - extraScore = _npcBuf[charId]._passiveScore[10]; - break; - case 11: - extraScore = _npcBuf[charId]._passiveScore[6]; - break; - case 12: - extraScore = _npcBuf[charId]._passiveScore[7]; - break; - case 13: - extraScore = _npcBuf[charId]._passiveScore[8]; - break; - case 14: - extraScore = _npcBuf[charId]._activeScore[13]; - break; - case 15: - extraScore = _npcBuf[charId]._passiveScore[9]; - break; - default: - break; - } - - extraScore += _items[itemId].field_13; - - int16 grandTotalScore = totalScore + extraScore; - if (grandTotalScore > 60) - grandTotalScore = 60; - - int16 retVal = CLIP(grandTotalScore + 30, 5, 90); - return retVal; -} - -bool EfhEngine::checkSpecialItemsOnCurrentPlace(int16 itemId) { - debug("checkSpecialItemsOnCurrentPlace %d", itemId); - - switch(_techDataArr[_techId][_techDataId_MapPosX * 64 + _techDataId_MapPosY]) { - case 1: - if ((itemId < 0x58 || itemId > 0x68) && (itemId < 0x86 || itemId > 0x89) && (itemId < 0x74 || itemId > 0x76) && (itemId != 0x8C)) - return true; - return false; - case 2: - if ((itemId < 0x61 || itemId > 0x63) && (itemId < 0x74 || itemId > 0x76) && (itemId < 0x86 || itemId > 0x89) && (itemId < 0x5B || itemId > 0x5E) && (itemId < 0x66 || itemId > 0x68) && (itemId != 0x8C)) - return true; - return false; - default: - return true; - } -} - -bool EfhEngine::hasAdequateDefense(int16 monsterId, uint8 attackType) { - debug("hasAdequateDefense %d %d", monsterId, attackType); - - int16 itemId = _mapMonsters[monsterId]._itemId_Weapon; - - if (_items[itemId].field_16 != 0) - return false; - - return _items[itemId].field17_attackTypeDefense == attackType; -} - -bool EfhEngine::hasAdequateDefense_2(int16 charId, uint8 attackType) { - debug("hasAdequateDefense_2 %d %d", charId, attackType); - - int16 itemId = _npcBuf[charId]._unkItemId; - - if (_items[itemId].field_16 == 0 && _items[itemId].field17_attackTypeDefense == attackType) - return true; - - for (uint counter = 0; counter < 10; ++counter) { - if (_npcBuf[charId]._inventory[counter]._ref == 0x7FFF || _npcBuf[charId]._inventory[counter]._stat1 == 0x80) - continue; - - itemId = _npcBuf[charId]._inventory[counter]._ref; - if (_items[itemId].field_16 == 0 && _items[itemId].field17_attackTypeDefense == attackType) - return true; - } - return false; -} - -bool EfhEngine::characterSearchesMonsterCorpse(int16 charId, int16 monsterId) { - debug("characterSearchesMonsterCorpse %d %d", charId, monsterId); - - int16 rndVal = getRandom(100); - if (kEncounters[_mapMonsters[monsterId]._monsterRef]._dropOccurrencePct < rndVal) - return false; - - rndVal = getRandom(5) - 1; - int16 itemId = kEncounters[_mapMonsters[monsterId]._monsterRef]._dropItemId[rndVal]; - if (itemId == -1) - return false; - - if (!giveItemTo(charId, itemId, 0xFF)) - return false; - - _messageToBePrinted += Common::String::format(" and finds a %s!", _items[itemId]._name); - return true; -} - -void EfhEngine::getXPAndSearchCorpse(int16 charId, Common::String namePt1, Common::String namePt2, int16 monsterId) { - debug("getXPAndSearchCorpse %d %s%s %d", charId, namePt1.c_str(), namePt2.c_str(), monsterId); - - int16 xpLevel = getXPLevel(_npcBuf[charId]._xp); - _npcBuf[charId]._xp += kEncounters[_mapMonsters[monsterId]._monsterRef]._xpGiven; - - if (getXPLevel(_npcBuf[charId]._xp) > xpLevel) { - generateSound(15); - int16 var2 = getRandom(20) + getRandom(_npcBuf[charId]._infoScore[4]); - _npcBuf[charId]._hitPoints += var2; - _npcBuf[charId]._maxHP += var2; - _npcBuf[charId]._infoScore[0] += getRandom(3) - 1; - _npcBuf[charId]._infoScore[1] += getRandom(3) - 1; - _npcBuf[charId]._infoScore[2] += getRandom(3) - 1; - _npcBuf[charId]._infoScore[3] += getRandom(3) - 1; - _npcBuf[charId]._infoScore[4] += getRandom(3) - 1; - } - - _messageToBePrinted += Common::String::format(" %s%s gains %d experience", namePt1.c_str(), namePt2.c_str(), kEncounters[_mapMonsters[monsterId]._monsterRef]._xpGiven); - if (!characterSearchesMonsterCorpse(charId, monsterId)) - _messageToBePrinted += "!"; - -} - -void EfhEngine::addReactionText(int16 id) { - debug("addReactionText %d", id); - - int16 rand3 = getRandom(3); - - switch (id) { - case 0: - switch (rand3) { - case 1: - _messageToBePrinted += Common::String::format(" %s%s reels from the blow!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); - break; - case 2: - _messageToBePrinted += Common::String::format(" %s%s sways from the attack!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); - break; - case 3: - _messageToBePrinted += Common::String::format(" %s%s looks dazed!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); - break; - default: - break; - } - break; - case 1: - switch (rand3) { - case 1: - _messageToBePrinted += Common::String::format(" %s%s cries out in agony!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); - break; - case 2: - _messageToBePrinted += Common::String::format(" %s%s screams from the abuse!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); - break; - case 3: - _messageToBePrinted += Common::String::format(" %s%s wails terribly!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); - break; - default: - break; - } - break; - case 2: - switch (rand3) { - case 1: - _messageToBePrinted += Common::String::format(" %s%s is staggering!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); - break; - case 2: - _messageToBePrinted += Common::String::format(" %s%s falters for a moment!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); - break; - case 3: - _messageToBePrinted += Common::String::format(" %s%s is stumbling about!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); - break; - default: - break; - } - break; - case 3: - switch (rand3) { - case 1: - _messageToBePrinted += Common::String::format(" %s%s winces from the pain!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); - break; - case 2: - _messageToBePrinted += Common::String::format(" %s%s cringes from the damage!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); - break; - case 3: - _messageToBePrinted += Common::String::format(" %s%s shrinks from the wound!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); - break; - default: - break; - } - break; - case 4: - switch (rand3) { - case 1: - _messageToBePrinted += Common::String::format(" %s%s screams!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); - break; - case 2: - _messageToBePrinted += Common::String::format(" %s%s bellows!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); - break; - case 3: - _messageToBePrinted += Common::String::format(" %s%s shrills!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); - break; - default: - break; - } - break; - case 5: - switch (rand3) { - case 1: - _messageToBePrinted += Common::String::format(" %s%s chortles!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); - break; - case 2: - _messageToBePrinted += Common::String::format(" %s%s seems amused!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); - break; - case 3: - _messageToBePrinted += Common::String::format(" %s%s looks concerned!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); - break; - default: - break; - } - break; - case 6: - switch (rand3) { - case 1: - _messageToBePrinted += Common::String::format(" %s%s laughs at the feeble attack!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); - break; - case 2: - _messageToBePrinted += Common::String::format(" %s%s smiles at the pathetic attack!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); - break; - case 3: - _messageToBePrinted += Common::String::format(" %s%s laughs at the ineffective assault!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); - break; - default: - break; - } - break; - default: - break; - } - -} - void EfhEngine::sub1D8C2(int16 charId, int16 damage) { debug("sub1D8C2 %d %d", charId, damage); @@ -3372,90 +2800,6 @@ void EfhEngine::sub1D8C2(int16 charId, int16 damage) { } } -void EfhEngine::displayMenuItemString(int16 menuBoxId, int16 thisBoxId, int16 minX, int16 maxX, int16 minY, const char *str) { - debugC(6, kDebugEngine, "displayMenuItemString %d %d %d->%d %d %s", menuBoxId, thisBoxId, minX, maxX, minY, str); - - if (menuBoxId == thisBoxId) { - if (_menuDepth == 0) - setTextColorWhite(); - else - setTextColorGrey(); - - Common::String buffer = Common::String::format("> %s <", str); - displayCenteredString(buffer, minX, maxX, minY); - setTextColorRed(); - } else { - if (_menuDepth == 0) - setTextColorRed(); - else - setTextColorGrey(); - - displayCenteredString(str, minX, maxX, minY); - } -} - -void EfhEngine::displayStatusMenu(int16 windowId) { - debugC(3, kDebugEngine, "displayStatusMenu %d", windowId); - - for (uint counter = 0; counter < 9; ++counter) { - drawColoredRect(80, 39 + 14 * counter, 134, 47 + 14 * counter, 0); - } - - if (_menuDepth != 0) - setTextColorGrey(); - - displayMenuItemString(windowId, 0, 80, 134, 39, "EQUIP"); - displayMenuItemString(windowId, 1, 80, 134, 53, "USE"); - displayMenuItemString(windowId, 2, 80, 134, 67, "GIVE"); - displayMenuItemString(windowId, 3, 80, 134, 81, "TRADE"); - displayMenuItemString(windowId, 4, 80, 134, 95, "DROP"); - displayMenuItemString(windowId, 5, 80, 134, 109, "INFO."); - displayMenuItemString(windowId, 6, 80, 134, 123, "PASSIVE"); - displayMenuItemString(windowId, 7, 80, 134, 137, "ACTIVE"); - displayMenuItemString(windowId, 8, 80, 134, 151, "LEAVE"); - - setTextColorRed(); -} - -void EfhEngine::prepareStatusRightWindowIndexes(int16 menuId, int16 charId) { - debugC(6, kDebugEngine, "prepareStatusRightWindowIndexes %d %d", menuId, charId); - - int16 maxId = 0; - int16 minId; - _menuItemCounter = 0; - - switch (menuId) { - case 5: - minId = 26; - maxId = 36; - break; - case 6: - minId = 15; - maxId = 25; - break; - case 7: - minId = 0; - maxId = 14; - break; - default: - minId = -1; - break; - } - - if (minId == -1) { - for (uint counter = 0; counter < 10; ++counter) { - if (_npcBuf[charId]._inventory[counter]._ref != 0x7FFF) { - _menuStatItemArr[_menuItemCounter++] = counter; - } - } - } else { - for (int16 counter = minId; counter < maxId; ++counter) { - if (_npcBuf[charId]._activeScore[counter] != 0) { - _menuStatItemArr[_menuItemCounter++] = counter; - } - } - } -} int16 EfhEngine::getXPLevel(int32 xp) { debugC(6, kDebugEngine, "getXPLevel %ld", xp); @@ -3478,212 +2822,6 @@ int16 EfhEngine::getXPLevel(int32 xp) { return level; } -void EfhEngine::displayCharacterSummary(int16 curMenuLine, int16 npcId) { - debugC(3, kDebugEngine, "displayCharacterSummary %d %d", curMenuLine, npcId); - - setTextColorRed(); - Common::String buffer1 = _npcBuf[npcId]._name; - setTextPos(146, 27); - displayStringAtTextPos("Name: "); - displayStringAtTextPos(buffer1); - buffer1 = Common::String::format("Level: %d", getXPLevel(_npcBuf[npcId]._xp)); - setTextPos(146, 36); - displayStringAtTextPos(buffer1); - buffer1 = Common::String::format("XP: %lu", _npcBuf[npcId]._xp); - setTextPos(227, 36); - displayStringAtTextPos(buffer1); - buffer1 = Common::String::format("Speed: %d", _npcBuf[npcId]._speed); - setTextPos(146, 45); - displayStringAtTextPos(buffer1); - buffer1 = Common::String::format("Defense: %d", getEquipmentDefense(npcId, false)); - setTextPos(146, 54); - displayStringAtTextPos(buffer1); - buffer1 = Common::String::format("Hit Points: %d", _npcBuf[npcId]._hitPoints); - setTextPos(146, 63); - displayStringAtTextPos(buffer1); - buffer1 = Common::String::format("Max HP: %d", _npcBuf[npcId]._maxHP); - setTextPos(227, 63); - displayStringAtTextPos(buffer1); - displayCenteredString("Inventory", 144, 310, 72); - - if (_menuItemCounter == 0) { - if (curMenuLine != -1) - setTextColorWhite(); - - displayCenteredString("Nothing Carried", 144, 310, 117); - setTextColorRed(); - return; - } - - for (int counter = 0; counter < _menuItemCounter; ++counter) { - if (_menuDepth == 0) - setTextColorGrey(); - else { - if (counter == curMenuLine) - setTextColorWhite(); - } - int16 textPosY = 81 + counter * 9; - int16 itemId = _npcBuf[npcId]._inventory[_menuStatItemArr[counter]]._ref; - if (itemId != 0x7FFF) { - if (_npcBuf[npcId]._inventory[_menuStatItemArr[counter]]._stat1 & 0x80) { - setTextPos(146, textPosY); - displayCharAtTextPos('E'); - } - } - - setTextPos(152, textPosY); - if (counter == curMenuLine) { - buffer1 = Common::String::format("%c>", 'A' + counter); - } else { - buffer1 = Common::String::format("%c)", 'A' + counter); - } - displayStringAtTextPos(buffer1); - - if (itemId != 0x7FFF) { - setTextPos(168, textPosY); - buffer1 = Common::String::format(" %s", _items[itemId]._name); - displayStringAtTextPos(buffer1); - setTextPos(262, textPosY); - - if (_items[itemId]._defense > 0) { - int16 stat2 = _npcBuf[npcId]._inventory[_menuStatItemArr[counter]]._stat2; - if (stat2 != 0xFF) { - buffer1 = Common::String::format("%d", 1 + stat2 / 8); - displayStringAtTextPos(buffer1); - setTextPos(286, textPosY); - displayStringAtTextPos("Def"); - } - // useless code removed. - // else { - // var54 = _items[_npcBuf[npcId]._inventory[_menuStatItemArr[counter]]._ref]._defense; - // { - } else if (_items[itemId]._uses != 0x7F) { - int16 stat1 = _npcBuf[npcId]._inventory[_menuStatItemArr[counter]]._stat1; - if (stat1 != 0x7F) { - buffer1 = Common::String::format("%d", stat1); - displayStringAtTextPos(buffer1); - setTextPos(286, textPosY); - if (stat1 == 1) - displayStringAtTextPos("Use"); - else - displayStringAtTextPos("Uses"); - } - } - } - setTextColorRed(); - } -} - -void EfhEngine::displayCharacterInformationOrSkills(int16 curMenuLine, int16 charId) { - debugC(3, kDebugEngine, "displayCharacterInformationOrSkills %d %d", curMenuLine, charId); - - setTextColorRed(); - Common::String buffer = _npcBuf[charId]._name; - setTextPos(146, 27); - displayStringAtTextPos("Name: "); - displayStringAtTextPos(buffer); - if (_menuItemCounter <= 0) { - if (curMenuLine != -1) - setTextColorWhite(); - displayCenteredString("No Skills To Select", 144, 310, 96); - setTextColorRed(); - return; - } - - for (int counter = 0; counter < _menuItemCounter; ++counter) { - if (counter == curMenuLine) - setTextColorWhite(); - int16 textPosY = 38 + counter * 9; - setTextPos(146, textPosY); - if (counter == curMenuLine) { - buffer = Common::String::format("%c>", 'A' + counter); - } else { - buffer = Common::String::format("%c)", 'A' + counter); - } - - displayStringAtTextPos(buffer); - setTextPos(163, textPosY); - displayStringAtTextPos(kSkillArray[_menuStatItemArr[counter]]); - buffer = Common::String::format("%d", _npcBuf[charId]._activeScore[_menuStatItemArr[counter]]); - setTextPos(278, textPosY); - displayStringAtTextPos(buffer); - setTextColorRed(); - } -} - -void EfhEngine::displayStatusMenuActions(int16 menuId, int16 curMenuLine, int16 npcId) { - debugC(6, kDebugEngine, "displayStatusMenuActions %d %d %d", menuId, curMenuLine, npcId); - - drawColoredRect(144, 15, 310, 184, 0); - displayCenteredString("(ESCape Aborts)", 144, 310, 175); - _textColor = 0x0E; - switch (menuId) { - case 0: - displayCenteredString("Select Item to Equip", 144, 310, 15); - displayCharacterSummary(curMenuLine, npcId); - break; - case 1: - displayCenteredString("Select Item to Use", 144, 310, 15); - displayCharacterSummary(curMenuLine, npcId); - break; - case 2: - displayCenteredString("Select Item to Give", 144, 310, 15); - displayCharacterSummary(curMenuLine, npcId); - break; - case 3: - displayCenteredString("Select Item to Trade", 144, 310, 15); - displayCharacterSummary(curMenuLine, npcId); - break; - case 4: - displayCenteredString("Select Item to Drop", 144, 310, 15); - displayCharacterSummary(curMenuLine, npcId); - break; - case 5: - displayCenteredString("Character Information", 144, 310, 15); - displayCharacterInformationOrSkills(curMenuLine, npcId); - break; - case 6: - displayCenteredString("Passive Skills", 144, 310, 15); - displayCharacterInformationOrSkills(curMenuLine, npcId); - break; - case 7: - displayCenteredString("Active Skills", 144, 310, 15); - displayCharacterInformationOrSkills(curMenuLine, npcId); - break; - case 8: - case 9: - displayCenteredString("Character Summary", 144, 310, 15); - displayCharacterSummary(curMenuLine, npcId); - break; - default: - break; - } -} - -void EfhEngine::prepareStatusMenu(int16 windowId, int16 menuId, int16 curMenuLine, int16 charId, bool unusedFl, bool refreshFl) { - debugC(6, kDebugEngine, "prepareStatusMenu %d %d %d %d %s", windowId, menuId, curMenuLine, charId, refreshFl ? "True" : "False"); - - displayStatusMenu(windowId); - - prepareStatusRightWindowIndexes(menuId, charId); - displayStatusMenuActions(menuId, curMenuLine, charId); - - if (refreshFl) - displayFctFullScreen(); -} - -void EfhEngine::sub18E80(int16 charId, int16 windowId, int16 menuId, int16 curMenuLine) { - debug("sub18E80 %d %d %d %d", charId, windowId, menuId, curMenuLine); - - for (int counter = 0; counter < 2; ++counter) { - displayWindow(_menuBuf, 0, 0, _hiResImageBuf); - prepareStatusMenu(windowId, menuId, curMenuLine, charId, true, false); - - if (counter == 0) - displayFctFullScreen(); - } -} - int16 EfhEngine::displayString_3(Common::String str, bool animFl, int16 charId, int16 windowId, int16 menuId, int16 curMenuLine) { debug("displayString_3 %s %s %d %d %d %d", str.c_str(), animFl ? "True" : "False", charId, windowId, menuId, curMenuLine); diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 65a04aa60bcb..34c9da9af2d2 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -319,7 +319,6 @@ class EfhEngine : public Engine { void displayMiddleLeftTempText(uint8 *impArray, bool flag); void sub15A28(int16 arg0, int16 arg2); void sub2455E(int16 arg0, int16 arg1, int16 arg2); - int16 sub1C219(Common::String str, int16 menuType, int16 displayOption, bool displayTeamWindowFl); int16 sub151FD(int16 posX, int16 posY); bool isPosOutOfMap(int16 mapPosX, int16 mapPosY); void goSouth(); @@ -332,7 +331,6 @@ class EfhEngine : public Engine { void goSouthWest(); void handleNewRoundEffects(); void resetGame(); - bool handleDeathMenu(); void computeMapAnimation(); void handleAnimations(); int8 sub16B08(int16 monsterId); @@ -363,27 +361,8 @@ class EfhEngine : public Engine { void sub1BE9A(int16 monsterId); int16 getTeamMonsterAnimId(); int16 countMonsterGroupMembers(int16 monsterGroup); - void sub1C4CA(bool WhiteFl); - void displayCombatMenu(int16 charId); - void drawCombatScreen(int16 charId, bool whiteFl, bool forceDrawFl); - int16 sub1DEC8(int16 groupNumber); - int16 getCharacterScore(int16 charId, int16 itemId); - bool checkSpecialItemsOnCurrentPlace(int16 itemId); - bool hasAdequateDefense(int16 monsterId, uint8 attackType); - bool hasAdequateDefense_2(int16 charId, uint8 attackType); - bool characterSearchesMonsterCorpse(int16 charId, int16 monsterId); - void getXPAndSearchCorpse(int16 charId, Common::String namePt1, Common::String namePt2, int16 monsterId); - void addReactionText(int16 id); void sub1D8C2(int16 charId, int16 damage); - void displayMenuItemString(int16 menuBoxId, int16 thisBoxId, int16 minX, int16 maxX, int16 minY, const char *str); - void displayStatusMenu(int16 windowId); - void prepareStatusRightWindowIndexes(int16 menuId, int16 charId); int16 getXPLevel(int32 xp); - void displayCharacterSummary(int16 curMenuLine, int16 npcId); - void displayCharacterInformationOrSkills(int16 curMenuLine, int16 npcId); - void displayStatusMenuActions(int16 menuId, int16 curMenuLine, int16 npcId); - void prepareStatusMenu(int16 windowId, int16 menuId, int16 curMenuLine, int16 charId, bool unusedFl, bool refreshFl); - void sub18E80(int16 charId, int16 windowId, int16 menuId, int16 curMenuLine); int16 displayString_3(Common::String str, bool animFl, int16 charId, int16 windowId, int16 menuId, int16 curMenuLine); bool isItemCursed(int16 itemId); bool hasObjectEquipped(int16 charId, int16 objectId); @@ -415,6 +394,16 @@ class EfhEngine : public Engine { void getDeathTypeDescription(int16 attackerId, int16 victimId); int16 sub1C956(int16 charId, int16 unkFied18Val, bool arg4); bool sub1CB27(); + void drawCombatScreen(int16 charId, bool whiteFl, bool forceDrawFl); + void getXPAndSearchCorpse(int16 charId, Common::String namePt1, Common::String namePt2, int16 monsterId); + bool characterSearchesMonsterCorpse(int16 charId, int16 monsterId); + void addReactionText(int16 id); + void sub1C4CA(bool WhiteFl); + int16 sub1DEC8(int16 groupNumber); + int16 getCharacterScore(int16 charId, int16 itemId); + bool checkSpecialItemsOnCurrentPlace(int16 itemId); + bool hasAdequateDefense(int16 monsterId, uint8 attackType); + bool hasAdequateDefense_2(int16 charId, uint8 attackType); // Files int32 readFileToBuffer(Common::String &filename, uint8 *destBuffer); @@ -466,6 +455,19 @@ class EfhEngine : public Engine { void displayWindow(uint8 *buffer, int16 posX, int16 posY, uint8 *dest); void displayColoredMenuBox(int16 minX, int16 minY, int16 maxX, int16 maxY, int16 color); + // Menu + int16 sub1C219(Common::String str, int16 menuType, int16 displayOption, bool displayTeamWindowFl); + bool handleDeathMenu(); + void displayCombatMenu(int16 charId); + void displayMenuItemString(int16 menuBoxId, int16 thisBoxId, int16 minX, int16 maxX, int16 minY, const char *str); + void displayStatusMenu(int16 windowId); + void prepareStatusRightWindowIndexes(int16 menuId, int16 charId); + void displayCharacterSummary(int16 curMenuLine, int16 npcId); + void displayCharacterInformationOrSkills(int16 curMenuLine, int16 npcId); + void displayStatusMenuActions(int16 menuId, int16 curMenuLine, int16 npcId); + void prepareStatusMenu(int16 windowId, int16 menuId, int16 curMenuLine, int16 charId, bool unusedFl, bool refreshFl); + void sub18E80(int16 charId, int16 windowId, int16 menuId, int16 curMenuLine); + // Savegames void synchronize(Common::Serializer &s); diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index 3ca3c8e41f89..30e4f99eb6f6 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -1139,4 +1139,406 @@ bool EfhEngine::sub1CB27() { return var4; } +void EfhEngine::drawCombatScreen(int16 charId, bool whiteFl, bool forceDrawFl) { + debug("drawCombatScreen %d %s %s", charId, whiteFl ? "True" : "False", forceDrawFl ? "True" : "False"); + + for (uint counter = 0; counter < 2; ++counter) { + if (counter == 0 || forceDrawFl) { + drawMapWindow(); + displayCenteredString("Combat", 128, 303, 9); + drawColoredRect(200, 112, 278, 132, 0); + displayCenteredString("'T' for Terrain", 128, 303, 117); + sub1C219("", 1, 0, false); + sub1C4CA(whiteFl); + displayCombatMenu(charId); + displayLowStatusScreen(false); + } + + if (counter == 0 && forceDrawFl) + displayFctFullScreen(); + } +} + +void EfhEngine::getXPAndSearchCorpse(int16 charId, Common::String namePt1, Common::String namePt2, int16 monsterId) { + debug("getXPAndSearchCorpse %d %s%s %d", charId, namePt1.c_str(), namePt2.c_str(), monsterId); + + int16 xpLevel = getXPLevel(_npcBuf[charId]._xp); + _npcBuf[charId]._xp += kEncounters[_mapMonsters[monsterId]._monsterRef]._xpGiven; + + if (getXPLevel(_npcBuf[charId]._xp) > xpLevel) { + generateSound(15); + int16 var2 = getRandom(20) + getRandom(_npcBuf[charId]._infoScore[4]); + _npcBuf[charId]._hitPoints += var2; + _npcBuf[charId]._maxHP += var2; + _npcBuf[charId]._infoScore[0] += getRandom(3) - 1; + _npcBuf[charId]._infoScore[1] += getRandom(3) - 1; + _npcBuf[charId]._infoScore[2] += getRandom(3) - 1; + _npcBuf[charId]._infoScore[3] += getRandom(3) - 1; + _npcBuf[charId]._infoScore[4] += getRandom(3) - 1; + } + + _messageToBePrinted += Common::String::format(" %s%s gains %d experience", namePt1.c_str(), namePt2.c_str(), kEncounters[_mapMonsters[monsterId]._monsterRef]._xpGiven); + if (!characterSearchesMonsterCorpse(charId, monsterId)) + _messageToBePrinted += "!"; +} + +bool EfhEngine::characterSearchesMonsterCorpse(int16 charId, int16 monsterId) { + debug("characterSearchesMonsterCorpse %d %d", charId, monsterId); + + int16 rndVal = getRandom(100); + if (kEncounters[_mapMonsters[monsterId]._monsterRef]._dropOccurrencePct < rndVal) + return false; + + rndVal = getRandom(5) - 1; + int16 itemId = kEncounters[_mapMonsters[monsterId]._monsterRef]._dropItemId[rndVal]; + if (itemId == -1) + return false; + + if (!giveItemTo(charId, itemId, 0xFF)) + return false; + + _messageToBePrinted += Common::String::format(" and finds a %s!", _items[itemId]._name); + return true; +} + +void EfhEngine::addReactionText(int16 id) { + debug("addReactionText %d", id); + + int16 rand3 = getRandom(3); + + switch (id) { + case 0: + switch (rand3) { + case 1: + _messageToBePrinted += Common::String::format(" %s%s reels from the blow!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); + break; + case 2: + _messageToBePrinted += Common::String::format(" %s%s sways from the attack!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); + break; + case 3: + _messageToBePrinted += Common::String::format(" %s%s looks dazed!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); + break; + default: + break; + } + break; + case 1: + switch (rand3) { + case 1: + _messageToBePrinted += Common::String::format(" %s%s cries out in agony!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); + break; + case 2: + _messageToBePrinted += Common::String::format(" %s%s screams from the abuse!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); + break; + case 3: + _messageToBePrinted += Common::String::format(" %s%s wails terribly!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); + break; + default: + break; + } + break; + case 2: + switch (rand3) { + case 1: + _messageToBePrinted += Common::String::format(" %s%s is staggering!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); + break; + case 2: + _messageToBePrinted += Common::String::format(" %s%s falters for a moment!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); + break; + case 3: + _messageToBePrinted += Common::String::format(" %s%s is stumbling about!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); + break; + default: + break; + } + break; + case 3: + switch (rand3) { + case 1: + _messageToBePrinted += Common::String::format(" %s%s winces from the pain!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); + break; + case 2: + _messageToBePrinted += Common::String::format(" %s%s cringes from the damage!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); + break; + case 3: + _messageToBePrinted += Common::String::format(" %s%s shrinks from the wound!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); + break; + default: + break; + } + break; + case 4: + switch (rand3) { + case 1: + _messageToBePrinted += Common::String::format(" %s%s screams!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); + break; + case 2: + _messageToBePrinted += Common::String::format(" %s%s bellows!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); + break; + case 3: + _messageToBePrinted += Common::String::format(" %s%s shrills!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); + break; + default: + break; + } + break; + case 5: + switch (rand3) { + case 1: + _messageToBePrinted += Common::String::format(" %s%s chortles!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); + break; + case 2: + _messageToBePrinted += Common::String::format(" %s%s seems amused!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); + break; + case 3: + _messageToBePrinted += Common::String::format(" %s%s looks concerned!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); + break; + default: + break; + } + break; + case 6: + switch (rand3) { + case 1: + _messageToBePrinted += Common::String::format(" %s%s laughs at the feeble attack!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); + break; + case 2: + _messageToBePrinted += Common::String::format(" %s%s smiles at the pathetic attack!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); + break; + case 3: + _messageToBePrinted += Common::String::format(" %s%s laughs at the ineffective assault!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); + break; + default: + break; + } + break; + default: + break; + } +} + +void EfhEngine::sub1C4CA(bool whiteFl) { + debug("sub1C4CA %s", whiteFl ? "True" : "False"); + + int16 textPosY = 20; + for (uint counter = 0; counter < 5; ++counter) { + if (_teamMonsterIdArray[counter] == -1) + continue; + + int16 var6C = computeMonsterGroupDistance(_teamMonsterIdArray[counter]); + int16 var6E = countMonsterGroupMembers(counter); + if (whiteFl) + setTextColorWhite(); + else + setTextColorGrey(); + + setTextPos(129, textPosY); + char buffer[80]; + snprintf(buffer, 80, "%c)", 'A' + counter); + displayStringAtTextPos(buffer); + setTextColorRed(); + int16 var1 = _mapMonsters[_teamMonsterIdArray[counter]]._possessivePronounSHL6 & 0x3F; + if (var1 <= 0x3D) { + snprintf(buffer, 80, "%d %s", var6E, kEncounters[_mapMonsters[_teamMonsterIdArray[counter]]._monsterRef]._name); + displayStringAtTextPos(buffer); + if (var6E > 1) + displayStringAtTextPos("s"); + } else if (var1 == 0x3E) { + displayStringAtTextPos("(NOT DEFINED)"); + } else if (var1 == 0x3F) { + Common::String stringToDisplay = _npcBuf[_mapMonsters[_teamMonsterIdArray[counter]]._field_1]._name; + displayStringAtTextPos(stringToDisplay); + } + + setTextPos(228, textPosY); + if (unkFct_checkMonsterField8(counter, true)) { + _textColor = 0xE; + displayStringAtTextPos("Hostile"); + } else { + _textColor = 0x2; + displayStringAtTextPos("Friendly"); + } + + setTextColorRed(); + switch (var6C) { + case 1: + displayCenteredString("S", 290, 302, textPosY); + break; + case 2: + displayCenteredString("M", 290, 302, textPosY); + break; + case 3: + displayCenteredString("L", 290, 302, textPosY); + break; + default: + displayCenteredString("?", 290, 302, textPosY); + break; + } + + textPosY += 9; + } +} + +int16 EfhEngine::sub1DEC8(int16 groupNumber) { + debug("sub1DEC8 %d", groupNumber); + + int16 var4 = -1; + int16 monsterId = _teamMonsterIdArray[groupNumber]; + + if (monsterId == -1) + return -1; + + for (uint counter = 0; counter < 9; ++counter) { + if (isMonsterActive(groupNumber, counter)) { + var4 = counter; + break; + } + } + + for (int16 counter = var4 + 1; counter < 9; ++counter) { + if (!isMonsterActive(groupNumber, counter)) + continue; + + if (_mapMonsters[monsterId]._pictureRef[var4] > _mapMonsters[monsterId]._pictureRef[counter]) + var4 = counter; + } + + if (_mapMonsters[monsterId]._pictureRef[var4] <= 0) + return -1; + + return var4; +} + +int16 EfhEngine::getCharacterScore(int16 charId, int16 itemId) { + debug("getCharacterScore %d %d", charId, itemId); + + int16 totalScore = 0; + switch (_items[itemId]._range) { + case 0: + totalScore = _npcBuf[charId]._passiveScore[5] + _npcBuf[charId]._passiveScore[3] + _npcBuf[charId]._passiveScore[4]; + totalScore += _npcBuf[charId]._infoScore[0] / 5; + totalScore += _npcBuf[charId]._infoScore[2] * 2, + totalScore += _npcBuf[charId]._infoScore[6] / 5; + totalScore += 2 * _npcBuf[charId]._infoScore[5] / 5; + break; + case 1: + totalScore = _npcBuf[charId]._passiveScore[3] + _npcBuf[charId]._passiveScore[4]; + totalScore += _npcBuf[charId]._infoScore[2] * 2; + totalScore += _npcBuf[charId]._infoScore[1] / 5; + totalScore += _npcBuf[charId]._infoScore[3] / 5; + break; + case 2: + case 3: + case 4: + totalScore = _npcBuf[charId]._passiveScore[1]; + totalScore += _npcBuf[charId]._infoScore[2] * 2; + totalScore += _npcBuf[charId]._infoScore[1] / 5; + totalScore += _npcBuf[charId]._infoScore[3] / 5; + totalScore += _npcBuf[charId]._infoScore[8] / 5; + default: + break; + } + + int16 extraScore = 0; + switch (_items[itemId]._attackType) { + case 0: + case 1: + case 2: + if (itemId == 0x3F) + extraScore = _npcBuf[charId]._passiveScore[2]; + else if (itemId == 0x41 || itemId == 0x42 || itemId == 0x6A || itemId == 0x6C || itemId == 0x6D) + extraScore = _npcBuf[charId]._passiveScore[0]; + break; + case 3: + case 4: + case 6: + extraScore = _npcBuf[charId]._infoScore[7]; + break; + case 5: + case 7: + extraScore = _npcBuf[charId]._infoScore[9]; + break; + case 8: + case 9: + extraScore = _npcBuf[charId]._activeScore[12]; + break; + case 10: + extraScore = _npcBuf[charId]._passiveScore[10]; + break; + case 11: + extraScore = _npcBuf[charId]._passiveScore[6]; + break; + case 12: + extraScore = _npcBuf[charId]._passiveScore[7]; + break; + case 13: + extraScore = _npcBuf[charId]._passiveScore[8]; + break; + case 14: + extraScore = _npcBuf[charId]._activeScore[13]; + break; + case 15: + extraScore = _npcBuf[charId]._passiveScore[9]; + break; + default: + break; + } + + extraScore += _items[itemId].field_13; + + int16 grandTotalScore = totalScore + extraScore; + if (grandTotalScore > 60) + grandTotalScore = 60; + + int16 retVal = CLIP(grandTotalScore + 30, 5, 90); + return retVal; +} + +bool EfhEngine::checkSpecialItemsOnCurrentPlace(int16 itemId) { + debug("checkSpecialItemsOnCurrentPlace %d", itemId); + + switch (_techDataArr[_techId][_techDataId_MapPosX * 64 + _techDataId_MapPosY]) { + case 1: + if ((itemId < 0x58 || itemId > 0x68) && (itemId < 0x86 || itemId > 0x89) && (itemId < 0x74 || itemId > 0x76) && (itemId != 0x8C)) + return true; + return false; + case 2: + if ((itemId < 0x61 || itemId > 0x63) && (itemId < 0x74 || itemId > 0x76) && (itemId < 0x86 || itemId > 0x89) && (itemId < 0x5B || itemId > 0x5E) && (itemId < 0x66 || itemId > 0x68) && (itemId != 0x8C)) + return true; + return false; + default: + return true; + } +} + +bool EfhEngine::hasAdequateDefense(int16 monsterId, uint8 attackType) { + debug("hasAdequateDefense %d %d", monsterId, attackType); + + int16 itemId = _mapMonsters[monsterId]._itemId_Weapon; + + if (_items[itemId].field_16 != 0) + return false; + + return _items[itemId].field17_attackTypeDefense == attackType; +} + +bool EfhEngine::hasAdequateDefense_2(int16 charId, uint8 attackType) { + debug("hasAdequateDefense_2 %d %d", charId, attackType); + + int16 itemId = _npcBuf[charId]._unkItemId; + + if (_items[itemId].field_16 == 0 && _items[itemId].field17_attackTypeDefense == attackType) + return true; + + for (uint counter = 0; counter < 10; ++counter) { + if (_npcBuf[charId]._inventory[counter]._ref == 0x7FFF || _npcBuf[charId]._inventory[counter]._stat1 == 0x80) + continue; + + itemId = _npcBuf[charId]._inventory[counter]._ref; + if (_items[itemId].field_16 == 0 && _items[itemId].field17_attackTypeDefense == attackType) + return true; + } + return false; +} + } // End of namespace Efh diff --git a/engines/efh/menu.cpp b/engines/efh/menu.cpp new file mode 100644 index 000000000000..9fea7b774a54 --- /dev/null +++ b/engines/efh/menu.cpp @@ -0,0 +1,486 @@ +/* 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 "efh/efh.h" + +namespace Efh { + +int16 EfhEngine::sub1C219(Common::String str, int16 menuType, int16 displayOption, bool displayTeamWindowFl) { + debug("sub1C219 %s %d %d %s", str.c_str(), menuType, displayOption, displayTeamWindowFl ? "True" : "False"); + + int16 varA = 0xFF; + int16 minX, maxX, minY, maxY; + + switch (menuType) { + case 0: + minX = 129; + minY = 9; + maxX = 302; + maxY = 18; + break; + case 1: + minX = 129; + minY = 9; + maxX = 302; + maxY = 110; + break; + case 2: + minX = 129; + minY = 112; + maxX = 302; + maxY = 132; + break; + case 3: + minX = 129; + minY = 79; + maxX = 303; + maxY = 107; + break; + default: + minX = minY = 0; + maxX = 320; + maxY = 200; + break; + } + + drawColoredRect(minX, minY, maxX, maxY, 0); + if (str.size()) + varA = script_parse(str, minX, minY, maxX, maxY, true); + + if (displayTeamWindowFl) + displayLowStatusScreen(false); + + if (displayOption != 0) { + displayFctFullScreen(); + if (_word2C87A) + _word2C87A = false; + else { + drawColoredRect(minX, minY, maxX, maxY, 0); + if (str.size()) + script_parse(str, minX, minY, maxX, maxY, false); + } + + if (displayTeamWindowFl) + displayLowStatusScreen(false); + + if (displayOption >= 2) + getLastCharAfterAnimCount(_guessAnimationAmount); + + if (displayOption == 3) + drawColoredRect(minX, minY, maxX, maxY, 0); + } + + return varA; +} + +bool EfhEngine::handleDeathMenu() { + debug("handleDeathMenu"); + + _saveAuthorized = false; + + displayAnimFrames(20, true); + _imageSetSubFilesIdx = 213; + drawScreen(); + + for (uint counter = 0; counter < 2; ++counter) { + clearBottomTextZone(0); + displayCenteredString("Darkness Prevails...Death Has Taken You!", 24, 296, 153); + setTextPos(100, 162); + setTextColorWhite(); + displayCharAtTextPos('L'); + setTextColorRed(); + displayStringAtTextPos("oad last saved game"); + setTextPos(100, 171); + setTextColorWhite(); + displayCharAtTextPos('R'); + setTextColorRed(); + displayStringAtTextPos("estart from beginning"); + setTextPos(100, 180); + setTextColorWhite(); + displayCharAtTextPos('Q'); + setTextColorRed(); + displayStringAtTextPos("uit for now"); + if (counter == 0) + displayFctFullScreen(); + } + + for (bool found = false; !found;) { + Common::KeyCode input = waitForKey(); + switch (input) { + case Common::KEYCODE_l: + //loadEfhGame(); + //TODO: + //SaveEfhGame opens the GUI save/load screen. It's not possible to save at this point, which is fine, but it's possible to close the screen without loading. + //Maybe adding the _saveAuthorized flag in the savegame would do the trick and could then be used tp keep found at false and loop on the input selection? + //like: found = _saveAuthorized + saveEfhGame(); + found = true; + _saveAuthorized = true; + break; + case Common::KEYCODE_q: + _shouldQuit = true; + return true; + break; + case Common::KEYCODE_r: + loadEfhGame(); + resetGame(); + found = true; + _saveAuthorized = true; + break; + case Common::KEYCODE_x: // mysterious and unexpected keycode ? + found = true; + break; + default: + break; + } + } + + displayAnimFrames(0xFE, true); + return false; +} + +void EfhEngine::displayCombatMenu(int16 charId) { + debug("displayCombatMenu %d", charId); + + Common::String buffer = _npcBuf[charId]._name; + buffer += ":"; + setTextColorWhite(); + setTextPos(144, 7); + displayStringAtTextPos(buffer); + setTextPos(152, 79); + displayStringAtTextPos("A"); + setTextColorRed(); + displayStringAtTextPos("ttack"); + setTextPos(195, 79); + setTextColorWhite(); + displayStringAtTextPos("H"); + setTextColorRed(); + displayStringAtTextPos("ide"); + setTextPos(152, 88); + setTextColorWhite(); + displayStringAtTextPos("D"); + setTextColorRed(); + displayStringAtTextPos("efend"); + setTextPos(195, 88); + setTextColorWhite(); + displayStringAtTextPos("R"); + setTextColorRed(); + displayStringAtTextPos("un"); + setTextPos(152, 97); + setTextColorWhite(); + displayStringAtTextPos("S"); + setTextColorRed(); + displayStringAtTextPos("tatus"); +} + +void EfhEngine::displayMenuItemString(int16 menuBoxId, int16 thisBoxId, int16 minX, int16 maxX, int16 minY, const char *str) { + debugC(6, kDebugEngine, "displayMenuItemString %d %d %d->%d %d %s", menuBoxId, thisBoxId, minX, maxX, minY, str); + + if (menuBoxId == thisBoxId) { + if (_menuDepth == 0) + setTextColorWhite(); + else + setTextColorGrey(); + + Common::String buffer = Common::String::format("> %s <", str); + displayCenteredString(buffer, minX, maxX, minY); + setTextColorRed(); + } else { + if (_menuDepth == 0) + setTextColorRed(); + else + setTextColorGrey(); + + displayCenteredString(str, minX, maxX, minY); + } +} + +void EfhEngine::displayStatusMenu(int16 windowId) { + debugC(3, kDebugEngine, "displayStatusMenu %d", windowId); + + for (uint counter = 0; counter < 9; ++counter) { + drawColoredRect(80, 39 + 14 * counter, 134, 47 + 14 * counter, 0); + } + + if (_menuDepth != 0) + setTextColorGrey(); + + displayMenuItemString(windowId, 0, 80, 134, 39, "EQUIP"); + displayMenuItemString(windowId, 1, 80, 134, 53, "USE"); + displayMenuItemString(windowId, 2, 80, 134, 67, "GIVE"); + displayMenuItemString(windowId, 3, 80, 134, 81, "TRADE"); + displayMenuItemString(windowId, 4, 80, 134, 95, "DROP"); + displayMenuItemString(windowId, 5, 80, 134, 109, "INFO."); + displayMenuItemString(windowId, 6, 80, 134, 123, "PASSIVE"); + displayMenuItemString(windowId, 7, 80, 134, 137, "ACTIVE"); + displayMenuItemString(windowId, 8, 80, 134, 151, "LEAVE"); + + setTextColorRed(); +} + +void EfhEngine::prepareStatusRightWindowIndexes(int16 menuId, int16 charId) { + debugC(6, kDebugEngine, "prepareStatusRightWindowIndexes %d %d", menuId, charId); + + int16 maxId = 0; + int16 minId; + _menuItemCounter = 0; + + switch (menuId) { + case 5: + minId = 26; + maxId = 36; + break; + case 6: + minId = 15; + maxId = 25; + break; + case 7: + minId = 0; + maxId = 14; + break; + default: + minId = -1; + break; + } + + if (minId == -1) { + for (uint counter = 0; counter < 10; ++counter) { + if (_npcBuf[charId]._inventory[counter]._ref != 0x7FFF) { + _menuStatItemArr[_menuItemCounter++] = counter; + } + } + } else { + for (int16 counter = minId; counter < maxId; ++counter) { + if (_npcBuf[charId]._activeScore[counter] != 0) { + _menuStatItemArr[_menuItemCounter++] = counter; + } + } + } +} + +void EfhEngine::displayCharacterSummary(int16 curMenuLine, int16 npcId) { + debugC(3, kDebugEngine, "displayCharacterSummary %d %d", curMenuLine, npcId); + + setTextColorRed(); + Common::String buffer1 = _npcBuf[npcId]._name; + setTextPos(146, 27); + displayStringAtTextPos("Name: "); + displayStringAtTextPos(buffer1); + buffer1 = Common::String::format("Level: %d", getXPLevel(_npcBuf[npcId]._xp)); + setTextPos(146, 36); + displayStringAtTextPos(buffer1); + buffer1 = Common::String::format("XP: %lu", _npcBuf[npcId]._xp); + setTextPos(227, 36); + displayStringAtTextPos(buffer1); + buffer1 = Common::String::format("Speed: %d", _npcBuf[npcId]._speed); + setTextPos(146, 45); + displayStringAtTextPos(buffer1); + buffer1 = Common::String::format("Defense: %d", getEquipmentDefense(npcId, false)); + setTextPos(146, 54); + displayStringAtTextPos(buffer1); + buffer1 = Common::String::format("Hit Points: %d", _npcBuf[npcId]._hitPoints); + setTextPos(146, 63); + displayStringAtTextPos(buffer1); + buffer1 = Common::String::format("Max HP: %d", _npcBuf[npcId]._maxHP); + setTextPos(227, 63); + displayStringAtTextPos(buffer1); + displayCenteredString("Inventory", 144, 310, 72); + + if (_menuItemCounter == 0) { + if (curMenuLine != -1) + setTextColorWhite(); + + displayCenteredString("Nothing Carried", 144, 310, 117); + setTextColorRed(); + return; + } + + for (int counter = 0; counter < _menuItemCounter; ++counter) { + if (_menuDepth == 0) + setTextColorGrey(); + else { + if (counter == curMenuLine) + setTextColorWhite(); + } + int16 textPosY = 81 + counter * 9; + int16 itemId = _npcBuf[npcId]._inventory[_menuStatItemArr[counter]]._ref; + if (itemId != 0x7FFF) { + if (_npcBuf[npcId]._inventory[_menuStatItemArr[counter]]._stat1 & 0x80) { + setTextPos(146, textPosY); + displayCharAtTextPos('E'); + } + } + + setTextPos(152, textPosY); + if (counter == curMenuLine) { + buffer1 = Common::String::format("%c>", 'A' + counter); + } else { + buffer1 = Common::String::format("%c)", 'A' + counter); + } + displayStringAtTextPos(buffer1); + + if (itemId != 0x7FFF) { + setTextPos(168, textPosY); + buffer1 = Common::String::format(" %s", _items[itemId]._name); + displayStringAtTextPos(buffer1); + setTextPos(262, textPosY); + + if (_items[itemId]._defense > 0) { + int16 stat2 = _npcBuf[npcId]._inventory[_menuStatItemArr[counter]]._stat2; + if (stat2 != 0xFF) { + buffer1 = Common::String::format("%d", 1 + stat2 / 8); + displayStringAtTextPos(buffer1); + setTextPos(286, textPosY); + displayStringAtTextPos("Def"); + } + // useless code removed. + // else { + // var54 = _items[_npcBuf[npcId]._inventory[_menuStatItemArr[counter]]._ref]._defense; + // { + } else if (_items[itemId]._uses != 0x7F) { + int16 stat1 = _npcBuf[npcId]._inventory[_menuStatItemArr[counter]]._stat1; + if (stat1 != 0x7F) { + buffer1 = Common::String::format("%d", stat1); + displayStringAtTextPos(buffer1); + setTextPos(286, textPosY); + if (stat1 == 1) + displayStringAtTextPos("Use"); + else + displayStringAtTextPos("Uses"); + } + } + } + setTextColorRed(); + } +} + +void EfhEngine::displayCharacterInformationOrSkills(int16 curMenuLine, int16 charId) { + debugC(3, kDebugEngine, "displayCharacterInformationOrSkills %d %d", curMenuLine, charId); + + setTextColorRed(); + Common::String buffer = _npcBuf[charId]._name; + setTextPos(146, 27); + displayStringAtTextPos("Name: "); + displayStringAtTextPos(buffer); + if (_menuItemCounter <= 0) { + if (curMenuLine != -1) + setTextColorWhite(); + displayCenteredString("No Skills To Select", 144, 310, 96); + setTextColorRed(); + return; + } + + for (int counter = 0; counter < _menuItemCounter; ++counter) { + if (counter == curMenuLine) + setTextColorWhite(); + int16 textPosY = 38 + counter * 9; + setTextPos(146, textPosY); + if (counter == curMenuLine) { + buffer = Common::String::format("%c>", 'A' + counter); + } else { + buffer = Common::String::format("%c)", 'A' + counter); + } + + displayStringAtTextPos(buffer); + setTextPos(163, textPosY); + displayStringAtTextPos(kSkillArray[_menuStatItemArr[counter]]); + buffer = Common::String::format("%d", _npcBuf[charId]._activeScore[_menuStatItemArr[counter]]); + setTextPos(278, textPosY); + displayStringAtTextPos(buffer); + setTextColorRed(); + } +} + +void EfhEngine::displayStatusMenuActions(int16 menuId, int16 curMenuLine, int16 npcId) { + debugC(6, kDebugEngine, "displayStatusMenuActions %d %d %d", menuId, curMenuLine, npcId); + + drawColoredRect(144, 15, 310, 184, 0); + displayCenteredString("(ESCape Aborts)", 144, 310, 175); + _textColor = 0x0E; + switch (menuId) { + case 0: + displayCenteredString("Select Item to Equip", 144, 310, 15); + displayCharacterSummary(curMenuLine, npcId); + break; + case 1: + displayCenteredString("Select Item to Use", 144, 310, 15); + displayCharacterSummary(curMenuLine, npcId); + break; + case 2: + displayCenteredString("Select Item to Give", 144, 310, 15); + displayCharacterSummary(curMenuLine, npcId); + break; + case 3: + displayCenteredString("Select Item to Trade", 144, 310, 15); + displayCharacterSummary(curMenuLine, npcId); + break; + case 4: + displayCenteredString("Select Item to Drop", 144, 310, 15); + displayCharacterSummary(curMenuLine, npcId); + break; + case 5: + displayCenteredString("Character Information", 144, 310, 15); + displayCharacterInformationOrSkills(curMenuLine, npcId); + break; + case 6: + displayCenteredString("Passive Skills", 144, 310, 15); + displayCharacterInformationOrSkills(curMenuLine, npcId); + break; + case 7: + displayCenteredString("Active Skills", 144, 310, 15); + displayCharacterInformationOrSkills(curMenuLine, npcId); + break; + case 8: + case 9: + displayCenteredString("Character Summary", 144, 310, 15); + displayCharacterSummary(curMenuLine, npcId); + break; + default: + break; + } +} + +void EfhEngine::prepareStatusMenu(int16 windowId, int16 menuId, int16 curMenuLine, int16 charId, bool unusedFl, bool refreshFl) { + debugC(6, kDebugEngine, "prepareStatusMenu %d %d %d %d %s", windowId, menuId, curMenuLine, charId, refreshFl ? "True" : "False"); + + displayStatusMenu(windowId); + + prepareStatusRightWindowIndexes(menuId, charId); + displayStatusMenuActions(menuId, curMenuLine, charId); + + if (refreshFl) + displayFctFullScreen(); +} + +void EfhEngine::sub18E80(int16 charId, int16 windowId, int16 menuId, int16 curMenuLine) { + debug("sub18E80 %d %d %d %d", charId, windowId, menuId, curMenuLine); + + for (int counter = 0; counter < 2; ++counter) { + displayWindow(_menuBuf, 0, 0, _hiResImageBuf); + prepareStatusMenu(windowId, menuId, curMenuLine, charId, true, false); + + if (counter == 0) + displayFctFullScreen(); + } +} + +} // End of namespace Efh + diff --git a/engines/efh/module.mk b/engines/efh/module.mk index 9cfeeb35953c..f6d074368082 100644 --- a/engines/efh/module.mk +++ b/engines/efh/module.mk @@ -6,6 +6,7 @@ MODULE_OBJS = \ fight.o \ files.o \ graphics.o \ + menu.o \ savegames.o \ script.o \ sound.o \ From eaee54c0836acd893c2332b8eb323dcf9c81ff0e Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sat, 24 Dec 2022 13:17:29 +0100 Subject: [PATCH 195/412] EFH: Move more functions to menu.cpp, change savegame format, some renaming --- engines/efh/efh.cpp | 1014 +------------------------------------ engines/efh/efh.h | 12 +- engines/efh/fight.cpp | 2 +- engines/efh/menu.cpp | 996 +++++++++++++++++++++++++++++++++++- engines/efh/savegames.cpp | 2 + 5 files changed, 1005 insertions(+), 1021 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 278859bcd3ab..783376510cfd 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -1025,22 +1025,15 @@ void EfhEngine::drawScreen() { void EfhEngine::displayLowStatusScreen(bool flag) { debugC(6, kDebugEngine, "displayLowStatusScreen %s", flag ? "True" : "False"); - Common::String strName = "Name"; - Common::String strDef = "DEF"; - Common::String strHp = "HP"; - Common::String strMaxHp = "Max HP"; - Common::String strWeapon = "Weapon"; - Common::String strDead = "* DEAD *"; - for (int counter = 0; counter < 2; ++counter) { if (counter == 0 || flag) { clearBottomTextZone(0); setTextColorWhite(); - displayCenteredString(strName, 16, 88, 152); - displayCenteredString(strDef, 104, 128, 152); - displayCenteredString(strHp, 144, 176, 152); - displayCenteredString(strMaxHp, 192, 224, 152); - displayCenteredString(strWeapon, 225, 302, 152); + displayCenteredString("Name", 16, 88, 152); + displayCenteredString("DEF", 104, 128, 152); + displayCenteredString("HP", 144, 176, 152); + displayCenteredString("Max HP", 192, 224, 152); + displayCenteredString("* DEAD *", 225, 302, 152); setTextColorRed(); for (int i = 0; i < 3; ++i) { @@ -1059,7 +1052,7 @@ void EfhEngine::displayLowStatusScreen(bool flag) { displayCenteredString(buffer, 192, 224, textPosY); if (_npcBuf[charId]._hitPoints <= 0) { - displayCenteredString(strDead, 225, 302, textPosY); + displayCenteredString("* DEAD *", 225, 302, textPosY); continue; } @@ -1260,7 +1253,7 @@ int16 EfhEngine::chooseCharacterToReplace() { debug("chooseCharacterToReplace"); Common::KeyCode maxVal = (Common::KeyCode)(Common::KEYCODE_0 + _teamSize); - Common::KeyCode input = Common::KEYCODE_INVALID; + Common::KeyCode input; for (;;) { input = waitForKey(); if (input == Common::KEYCODE_ESCAPE || input == Common::KEYCODE_0 || (input > Common::KEYCODE_1 && input <= maxVal)) @@ -2311,6 +2304,7 @@ void EfhEngine::displayImp1Text(int16 textId) { bool maxReached = false; if (textId <= 0xFE) { + // Clear temp text on the lower left part of the screen if (_tempTextPtr) { _tempTextPtr = nullptr; displayMiddleLeftTempText(_tempTextPtr, true); @@ -2461,7 +2455,7 @@ bool EfhEngine::sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemI continue; for (uint var2 = 0; var2 < 39; ++var2) { - // CHECKME : the whole look doesn't make much sense as it's using var6 instead of var2, plus _activeScore is an array of 15 bytes, not 0x77... + // CHECKME : the whole loop doesn't make much sense as it's using var6 instead of var2, plus _activeScore is an array of 15 bytes, not 0x77... // Also, 39 correspond to the size of activeScore + passiveScore + infoScore + the 2 remaining bytes of the struct if (_npcBuf[_teamCharId[counter]]._activeScore[var6] >= _mapUnknown[var8]._field4) { displayImp1Text(_mapUnknown[var8]._field5_textId); @@ -2822,31 +2816,6 @@ int16 EfhEngine::getXPLevel(int32 xp) { return level; } -int16 EfhEngine::displayString_3(Common::String str, bool animFl, int16 charId, int16 windowId, int16 menuId, int16 curMenuLine) { - debug("displayString_3 %s %s %d %d %d %d", str.c_str(), animFl ? "True" : "False", charId, windowId, menuId, curMenuLine); - - int16 retVal = 0; - - for (uint counter = 0; counter < 2; ++counter) { - prepareStatusMenu(windowId, menuId, curMenuLine, charId, true, false); - displayWindow(_windowWithBorderBuf, 19, 113, _hiResImageBuf); - - if (counter == 0) { - script_parse(str, 28, 122, 105, 166, false); - displayFctFullScreen(); - } else { - retVal = script_parse(str, 28, 122, 105, 166, true); - } - } - - if (animFl) { - getLastCharAfterAnimCount(_guessAnimationAmount); - sub18E80(charId, windowId, menuId, curMenuLine); - } - - return retVal; -} - bool EfhEngine::isItemCursed(int16 itemId) { debugC(6, kDebugEngine, "isItemCursed %d", itemId); @@ -2864,49 +2833,18 @@ bool EfhEngine::hasObjectEquipped(int16 charId, int16 objectId) { return true; } -void EfhEngine::equipCursedItem(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine) { - debug("equipCursedItem %d %d %d %d %d", charId, objectId, windowId, menuId, curMenuLine); - - int16 itemId = _npcBuf[charId]._inventory[objectId]._ref; - - if (isItemCursed(itemId)) { - _npcBuf[charId]._inventory[objectId]._stat1 &= 0x7F; - } else { - displayString_3("Cursed Item Already Equipped!", true, charId, windowId, menuId, curMenuLine); - } - -} - -void EfhEngine::sub191FF(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine) { - debug("sub191FF %d %d %d %d %d", charId, objectId, windowId, menuId, curMenuLine); - - int16 itemId = _npcBuf[charId]._inventory[objectId]._ref; - if (hasObjectEquipped(charId, objectId)) { - equipCursedItem(charId, objectId, windowId, menuId, curMenuLine); - } else { - int16 var2 = _items[itemId].field_18; - if (var2 != 4) { - for (uint counter = 0; counter < 10; ++counter) { - if (var2 == _items[_npcBuf[charId]._inventory[counter]._ref].field_18) - equipCursedItem(charId, objectId, windowId, menuId, curMenuLine); - } - } - - _npcBuf[charId]._inventory[objectId]._stat1 |= 0x80; - } -} - -void EfhEngine::sub1E028(int16 id, uint8 mask, int16 groupFl) { - debug("sub1E028 %d 0x%X %d", id, mask, groupFl); +void EfhEngine::setMapMonsterField8(int16 id, uint8 mask, bool groupFl) { + debugC(2, kDebugEngine, "setMapMonsterField8 %d 0x%X %s", id, mask, groupFl ? "True" : "False"); int16 monsterId; - if (groupFl) { + if (groupFl) { // groupFl is always True monsterId = _teamMonsterIdArray[id]; } else { monsterId = id; } + mask &= 0x0F; _mapMonsters[monsterId]._field_8 &= 0xF0; _mapMonsters[monsterId]._field_8 |= mask; } @@ -2951,932 +2889,6 @@ int16 EfhEngine::selectOtherCharFromTeam() { return (int16)input - (int16)Common::KEYCODE_1; } -int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine, int16 argA) { - debug("sub19E2E %d %d %d %d %d %d", charId, objectId, windowId, menuId, curMenuLine, argA); - - Common::String buffer1 = ""; - - bool varA6 = false; - bool retVal = false; - - int16 itemId = _npcBuf[charId]._inventory[objectId]._ref; - switch (_items[itemId].field_16 - 1) { - case 0: // "Demonic Powers", "MindDomination", "Guilt Trip", "Sleep Grenade", "SleepGrenader" - if (argA == 2) { - displayString_3("The item emits a low droning hum...", false, charId, windowId, menuId, curMenuLine); - } else { - int16 victims = 0; - _messageToBePrinted += " The item emits a low droning hum..."; - if (getRandom(100) < 50) { - for (uint counter = 0; counter < 9; ++counter) { - if (isMonsterActive(windowId, counter)) { - ++victims; - _stru32686[windowId]._field0[counter] = 1; - _stru32686[windowId]._field2[counter] = getRandom(8); - } - } - } else { - int16 NumberOfTargets = getRandom(9); - for (uint counter = 0; counter < 9; ++counter) { - if (NumberOfTargets == 0) - break; - - if (isMonsterActive(windowId, counter)) { - ++victims; - --NumberOfTargets; - _stru32686[windowId]._field0[counter] = 1; - _stru32686[windowId]._field2[counter] = getRandom(8); - } - } - } - // The original was duplicating this code in each branch of the previous random check. - if (victims > 1) { - buffer1 = Common::String::format("%d %ss fall asleep!", victims, kEncounters[_mapMonsters[_teamMonsterIdArray[windowId]]._monsterRef]._name); - } else { - buffer1 = Common::String::format("%d %s falls asleep!", victims, kEncounters[_mapMonsters[_teamMonsterIdArray[windowId]]._monsterRef]._name); - } - _messageToBePrinted += buffer1; - } - - varA6 = true; - break; - case 1: // "Chilling Touch", "Guilt", "Petrify Rod", "Elmer's Gun" - if (argA == 2) { - displayString_3("The item grows very cold for a moment...", false, charId, windowId, menuId, curMenuLine); - } else { - _messageToBePrinted += " The item emits a blue beam..."; - int16 victim = 0; - if (getRandom(100) < 50) { - for (uint varA8 = 0; varA8 < 9; ++varA8) { - if (isMonsterActive(windowId, varA8)) { - ++victim; - _stru32686[windowId]._field0[varA8] = 2; - _stru32686[windowId]._field2[varA8] = getRandom(8); - } - } - } else { - int16 varAC = getRandom(9); - for (uint varA8 = 0; varA8 < 9; ++varA8) { - if (varAC == 0) - break; - - if (isMonsterActive(windowId, varA8)) { - ++victim; - --varAC; - _stru32686[windowId]._field0[varA8] = 2; - _stru32686[windowId]._field2[varA8] = getRandom(8); - } - } - } - // : This part is only present in the original in the case < 50, but for me - // it's missing in the other case as there's an effect (frozen enemies) but no feedback to the player - if (victim > 1) { - buffer1 = Common::String::format("%d %ss are frozen in place!", victim, kEncounters[_mapMonsters[_teamMonsterIdArray[windowId]]._monsterRef]._name); - } else { - buffer1 = Common::String::format("%d %s is frozen in place!", victim, kEncounters[_mapMonsters[_teamMonsterIdArray[windowId]]._monsterRef]._name); - } - _messageToBePrinted += buffer1; - // - } - - varA6 = true; - break; - case 2: - if (argA == 2) { - displayString_3("A serene feeling passes through the air...", false, charId, windowId, menuId, curMenuLine); - } else { - _messageToBePrinted += " The combat pauses...as there is a moment of forgiveness..."; - _unkArray2C8AA[0] = 0; - } - - varA6 = true; - break; - case 4: // "Unholy Sinwave", "Holy Water" - if (argA == 2) { - displayString_3("A dark sense fills your soul...then fades!", false, charId, windowId, menuId, curMenuLine); - } else { - _messageToBePrinted += " A dark gray fiery whirlwind surrounds the poor victim...the power fades and death abounds!"; - if (getRandom(100) < 50) { - for (uint counter = 0; counter < 9; ++counter) { - if (getRandom(100) < 50) { - _mapMonsters[_teamMonsterIdArray[windowId]]._pictureRef[counter] = 0; - } - } - } else { - for (uint counter = 0; counter < 9; ++counter) { - if (isMonsterActive(windowId, counter)) { - if (getRandom(100) < 50) { - _mapMonsters[_teamMonsterIdArray[windowId]]._pictureRef[counter] = 0; - } - break; - } - } - } - } - varA6 = true; - break; - case 5: // "Lucifer'sTouch", "Book of Death", "Holy Cross" - if (argA == 2) { - displayString_3("A dark sense fills your soul...then fades!", false, charId, windowId, menuId, curMenuLine); - } else { - if (getRandom(100) < 50) { - _messageToBePrinted += " A dark fiery whirlwind surrounds the poor victim...the power fades and all targeted die!"; - for (uint counter = 0; counter < 9; ++counter) { - _mapMonsters[_teamMonsterIdArray[windowId]]._pictureRef[counter] = 0; - } - } else { - _messageToBePrinted += " A dark fiery whirlwind surrounds the poor victim...the power fades and one victim dies!"; - for (uint counter = 0; counter < 9; ++counter) { - if (isMonsterActive(windowId, counter)) { - _mapMonsters[_teamMonsterIdArray[windowId]]._pictureRef[counter] = 0; - } - } - } - } - - varA6 = true; - break; - case 12: // "Terror Gaze", "Servitude Rod", "Despair Ankh", "ConfusionPrism", "Pipe of Peace", "Red Cape", "Peace Symbol", "Hell Badge" - if (argA == 2) { - displayString_3("There is no apparent affect!", false, charId, windowId, menuId, curMenuLine); - } else { - _messageToBePrinted += " The magic sparkles brilliant hues in the air!"; - sub1E028(windowId, _items[itemId].field17_attackTypeDefense, true); - } - varA6 = true; - break; - case 14: { // "Feathered Cap" - int16 varAA; - if (argA == 2) { - displayString_3("Who will use the item?", false, charId, windowId, menuId, curMenuLine); - varAA = selectOtherCharFromTeam(); - } else { - varAA = windowId; - } - - if (varAA != 0x1B) { - buffer1 = " The magic makes the user as quick and agile as a bird!"; - if (argA == 2) { - displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); - } else { - _messageToBePrinted += buffer1; - } - _word32482[varAA] -= 50; - if (_word32482[varAA] < 0) - _word32482[varAA] = 0; - } - - varA6 = true; - } - break; - case 15: { // "Regal Crown" - int16 teamCharId; - if (argA == 2) { - displayString_3("Who will use the item?", false, charId, windowId, menuId, curMenuLine); - teamCharId = selectOtherCharFromTeam(); - } else { - teamCharId = windowId; - } - - if (teamCharId != 0x1B) { - buffer1 = " The magic makes the user invisible!"; - if (argA == 2) { - displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); - } else { - _messageToBePrinted += buffer1; - } - - _teamPctVisible[teamCharId] -= 50; - if (_teamPctVisible[teamCharId] < 0) - _teamPctVisible[teamCharId] = 0; - } - - varA6 = true; - } - break; - case 16: { // Fairy Dust - _mapPosX = getRandom(_largeMapFlag ? 63 : 23); - _mapPosY = getRandom(_largeMapFlag ? 63 : 23); - int16 varAE = sub15538(_mapPosX, _mapPosY); - - if (_tileFact[varAE]._field0 == 0) { - totalPartyKill(); - buffer1 = "The entire party vanishes in a flash... only to appear in stone !"; - if (argA == 2) { - displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); - } else { - _messageToBePrinted += buffer1; - retVal = true; - } - // emptyFunction(2); - } else { - if (varAE == 0 || varAE == 0x48) { - buffer1 = "The entire party vanishes in a flash...but re-appears, as if nothing happened!"; - if (argA == 2) { - displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); - } else { - _messageToBePrinted += buffer1; - retVal = true; - } - } else { - buffer1 = "The entire party vanishes in a flash...only to appear elsewhere!"; - if (argA == 2) { - displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); - } else { - _messageToBePrinted += buffer1; - retVal = true; - } - } - } - - varA6 = true; - } - break; - case 17: { // "Devil Dust" - _mapPosX = _items[itemId].field_19; - _mapPosY = _items[itemId].field_1A; - int16 varAE = sub15538(_mapPosX, _mapPosY); - if (_tileFact[varAE]._field0 == 0) { - totalPartyKill(); - buffer1 = "The entire party vanishes in a flash... only to appear in stone !"; - if (argA == 2) { - displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); - } else { - _messageToBePrinted += buffer1; - retVal = true; - } - // emptyFunction(2); - } else { - if (varAE == 0 || varAE == 0x48) { - buffer1 = "The entire party vanishes in a flash...but re-appears, as if nothing happened!"; - if (argA == 2) { - displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); - } else { - _messageToBePrinted += buffer1; - retVal = true; - } - } else { - buffer1 = "The entire party vanishes in a flash...only to appear elsewhere!"; - if (argA == 2) { - displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); - } else { - _messageToBePrinted += buffer1; - retVal = true; - } - } - } - - varA6 = true; - } - break; - case 18: - if (argA == 2) { - displayString_3("The item makes a loud noise!", false, charId, windowId, menuId, curMenuLine); - } else { - int16 teamCharId = windowId; - if (teamCharId != 0x1B) { - if (_teamCharStatus[teamCharId]._status == 2) { // frozen - _messageToBePrinted += " The item makes a loud noise, awakening the character!"; - _teamCharStatus[teamCharId]._status = 0; - _teamCharStatus[teamCharId]._duration = 0; - } else { - _messageToBePrinted += " The item makes a loud noise, but has no effect!"; - } - } - } - - varA6 = true; - break; - case 19: // "Junk" - buffer1 = " * The item breaks!"; - if (argA == 2) { - displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); - } else { - _messageToBePrinted += buffer1; - } - setCharacterObjectToBroken(charId, objectId); - varA6 = true; - break; - case 23: // "Divining Rod" - buffer1 = Common::String::format("The %s says, '", _items[itemId]._name); - if (_items[itemId].field_19 < _mapPosX) { - if (_items[itemId].field_1A < _mapPosY) { - buffer1 += "North West!"; - } else if (_items[itemId].field_1A > _mapPosY) { - buffer1 += "South West!"; - } else { - buffer1 += "West!"; - } - } else if (_items[itemId].field_19 > _mapPosX) { - if (_items[itemId].field_1A < _mapPosY) { - buffer1 += "North East!"; - } else if (_items[itemId].field_1A > _mapPosY) { - buffer1 += "South East!"; - } else { - buffer1 += "East!"; - } - } else { // equals _mapPosX - if (_items[itemId].field_1A < _mapPosY) { - buffer1 += "North!"; - } else if (_items[itemId].field_1A > _mapPosY) { - buffer1 += "South!"; - } else { - buffer1 += "Here!!!"; - } - } - buffer1 += "'"; - if (argA == 2) { - displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); - } else { - _messageToBePrinted += buffer1; - retVal = true; - } - - varA6 = true; - break; - case 24: { - int16 teamCharId; - if (argA == 2) { - displayString_3("Who will use this item?", false, charId, windowId, menuId, curMenuLine); - teamCharId = selectOtherCharFromTeam(); - } else - teamCharId = windowId; - - if (teamCharId != 0x1B) { - uint8 varAE = _items[itemId].field17_attackTypeDefense; - uint8 effectPoints = getRandom(_items[itemId].field_19); - _npcBuf[_teamCharId[teamCharId]]._activeScore[varAE] += effectPoints; - if (_npcBuf[_teamCharId[teamCharId]]._activeScore[varAE] > 20) { - _npcBuf[_teamCharId[teamCharId]]._activeScore[varAE] = 20; - } - if (effectPoints > 1) - buffer1 = Common::String::format("%s increased %d points!", kSkillArray[varAE], effectPoints); - else - buffer1 = Common::String::format("%s increased 1 point!", kSkillArray[varAE]); - - if (argA == 2) { - displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); - } else { - _messageToBePrinted += buffer1; - retVal = true; - } - } - - varA6 = true; - } - break; - case 25: { - int16 teamCharId; - if (argA == 2) { - displayString_3("Who will use this item?", false, charId, windowId, menuId, curMenuLine); - teamCharId = selectOtherCharFromTeam(); - } else - teamCharId = windowId; - - if (teamCharId != 0x1B) { - uint8 varAE = _items[itemId].field17_attackTypeDefense; - uint8 effectPoints = getRandom(_items[itemId].field_19); - _npcBuf[_teamCharId[teamCharId]]._activeScore[varAE] -= effectPoints; - if (_npcBuf[_teamCharId[teamCharId]]._activeScore[varAE] > 20 || _npcBuf[_teamCharId[teamCharId]]._activeScore[varAE] < 0) { - _npcBuf[_teamCharId[teamCharId]]._activeScore[varAE] = 1; - } - if (effectPoints > 1) - buffer1 = Common::String::format("%s lowered %d points!", kSkillArray[varAE], effectPoints); - else - buffer1 = Common::String::format("%s lowered 1 point!", kSkillArray[varAE]); - - if (argA == 2) { - displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); - } else { - _messageToBePrinted += buffer1; - retVal = true; - } - } - - varA6 = true; - } - break; - case 26: // "Black Sphere" - buffer1 = "The entire party collapses, dead!!!"; - if (argA == 2) { - displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); - } else { - _messageToBePrinted += buffer1; - retVal = true; - } - totalPartyKill(); - // emptyFunction(2); - varA6 = true; - break; - case 27: { // "Magic Pyramid", "Razor Blade" - int16 teamCharId; - if (argA == 2) { - displayString_3("Who will use the item?", false, charId, windowId, menuId, curMenuLine); - teamCharId = selectOtherCharFromTeam(); - } else { - teamCharId = windowId; - } - - if (teamCharId != 0x1B) { - _npcBuf[_teamCharId[teamCharId]]._hitPoints = 0; - buffer1 = Common::String::format("%s collapses, dead!!!", _npcBuf[_teamCharId[teamCharId]]._name); - if (argA == 2) { - displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); - } else { - _messageToBePrinted += buffer1; - retVal = true; - } - // emptyFunction(2); - } - - varA6 = true; - } - break; - case 28: // "Bugle" - if (argA == 2) { - displayString_3("The item makes a loud noise!", false, charId, windowId, menuId, curMenuLine); - } else { - int16 teamCharId = windowId; - if (teamCharId != 0x1B) { - if (_teamCharStatus[teamCharId]._status == 0) { - _messageToBePrinted += " The item makes a loud noise, awakening the character!"; - _teamCharStatus[teamCharId]._status = 0; - _teamCharStatus[teamCharId]._duration = 0; - } else { - _messageToBePrinted += " The item makes a loud noise, but has no effect!"; - } - } - } - - varA6 = true; - break; - case 29: { // "Healing Spray", "Healing Elixir", "Curing Potion", "Magic Potion" - int16 teamCharId; - if (argA == 2) { - displayString_3("Who will use the item?", false, charId, windowId, menuId, curMenuLine); - teamCharId = selectOtherCharFromTeam(); - } else { - teamCharId = windowId; - } - - if (teamCharId != 0x1B) { - int16 effectPoints = getRandom(_items[itemId].field17_attackTypeDefense); - _npcBuf[_teamCharId[teamCharId]]._hitPoints += effectPoints; - if (_npcBuf[_teamCharId[teamCharId]]._hitPoints > _npcBuf[_teamCharId[teamCharId]]._maxHP) - _npcBuf[_teamCharId[teamCharId]]._hitPoints = _npcBuf[_teamCharId[teamCharId]]._maxHP; - - if (effectPoints > 1) - buffer1 = Common::String::format("%s is healed %d points!", _npcBuf[_teamCharId[teamCharId]]._name, effectPoints); - else - buffer1 = Common::String::format("%s is healed 1 point!", _npcBuf[_teamCharId[teamCharId]]._name); - } - - if (argA == 2) { - displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); - } else { - _messageToBePrinted += buffer1; - retVal = true; - } - - varA6 = true; - } - break; - case 30: { - int16 teamCharId; - if (argA == 2) { - displayString_3("Who will use the item?", false, charId, windowId, menuId, curMenuLine); - teamCharId = selectOtherCharFromTeam(); - } else { - teamCharId = windowId; - } - - if (teamCharId != 0x1B) { - int16 effectPoints = getRandom(_items[itemId].field17_attackTypeDefense); - _npcBuf[_teamCharId[teamCharId]]._hitPoints -= effectPoints; - if (_npcBuf[_teamCharId[teamCharId]]._hitPoints < 0) - _npcBuf[_teamCharId[teamCharId]]._hitPoints = 0; - - if (effectPoints > 1) - buffer1 = Common::String::format("%s is harmed for %d points!", _npcBuf[_teamCharId[teamCharId]]._name, effectPoints); - else - buffer1 = Common::String::format("%s is harmed for 1 point!", _npcBuf[_teamCharId[teamCharId]]._name); - } - - if (argA == 2) { - displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); - } else { - _messageToBePrinted += buffer1; - retVal = true; - } - - varA6 = true; - - } - break; - case 3: - case 6: - case 7: - case 8: - case 9: - case 10: - case 11: - case 13: - case 20: - case 21: - case 22: - default: - break; - } - - if (varA6) { - if ((_npcBuf[charId]._inventory[objectId]._stat1 & 0x7F) != 0x7F) { - int8 varA1 = (_npcBuf[charId]._inventory[objectId]._stat1 & 0x7F) - 1; - if (varA1 <= 0) { - buffer1 = " * The item breaks!"; - if (argA == 2) { - getLastCharAfterAnimCount(_guessAnimationAmount); - displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); - } else { - _messageToBePrinted += buffer1; - } - setCharacterObjectToBroken(charId, objectId); - } else { - _npcBuf[charId]._inventory[objectId]._stat1 &= 0x80; - _npcBuf[charId]._inventory[objectId]._stat1 |= 0xA1; - } - } - - if (argA == 2) { - getLastCharAfterAnimCount(_guessAnimationAmount); - sub18E80(charId, windowId, menuId, curMenuLine); - } - } - - return retVal; -} - -int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { - debug("handleStatusMenu %d %d", gameMode, charId); - - int16 menuId = 9; - int16 selectedLine = -1; - int16 windowId = -1; - int16 curMenuLine = -1; - bool var10 = false; - bool var2 = false; - - saveAnimImageSetId(); - - _statusMenuActive = true; - _menuDepth = 0; - - sub18E80(charId, windowId, menuId, curMenuLine); - - for (;;) { - if (windowId != -1) - prepareStatusMenu(windowId, menuId, curMenuLine, charId, true, true); - else - windowId = 0; - - do { - Common::KeyCode var19 = handleAndMapInput(false); - if (_menuDepth == 0) { - switch (var19) { - case Common::KEYCODE_ESCAPE: - windowId = 8; - var19 = Common::KEYCODE_RETURN; - break; - case Common::KEYCODE_a: - windowId = 7; - var19 = Common::KEYCODE_RETURN; - break; - case Common::KEYCODE_d: - windowId = 4; - var19 = Common::KEYCODE_RETURN; - break; - case Common::KEYCODE_e: - windowId = 0; - var19 = Common::KEYCODE_RETURN; - break; - case Common::KEYCODE_g: - windowId = 2; - var19 = Common::KEYCODE_RETURN; - break; - case Common::KEYCODE_i: - windowId = 5; - var19 = Common::KEYCODE_RETURN; - break; - case Common::KEYCODE_l: - windowId = 8; - var19 = Common::KEYCODE_RETURN; - break; - case Common::KEYCODE_p: - windowId = 6; - var19 = Common::KEYCODE_RETURN; - break; - case Common::KEYCODE_t: - windowId = 3; - var19 = Common::KEYCODE_RETURN; - break; - case Common::KEYCODE_u: - windowId = 1; - var19 = Common::KEYCODE_RETURN; - break; - // case 0xFB: Joystick button 2 - default: - // warning("handleStatusMenu - unhandled keys (or joystick event?) 0xBA, 0xBB, 0xBC"); - break; - } - } else if (_menuDepth == 1) { - // in the sub-menus, only a list of selectable items is displayed - if (var19 >= Common::KEYCODE_a && var19 <= Common::KEYCODE_z) { - int16 var8 = var19 - Common::KEYCODE_a; - if (var8 < _menuItemCounter) { - curMenuLine = var8; - var19 = Common::KEYCODE_RETURN; - } - } - - } - - switch (var19) { - case Common::KEYCODE_RETURN: - // case 0xFA: Joystick button 1 - if (_menuDepth == 0) { - menuId = windowId; - if (menuId > 7) - var10 = true; - else { - _menuDepth = 1; - curMenuLine = 0; - } - } else if (_menuDepth == 1) { - if (_menuItemCounter == 0) { - _menuDepth = 0; - curMenuLine = -1; - menuId = 9; - prepareStatusMenu(windowId, menuId, curMenuLine, charId, true, true); - } else { - selectedLine = curMenuLine; - var10 = true; - } - } - break; - case Common::KEYCODE_ESCAPE: - _menuDepth = 0; - curMenuLine = -1; - menuId = 9; - prepareStatusMenu(windowId, menuId, curMenuLine, charId, true, true); - break; - case Common::KEYCODE_2: - case Common::KEYCODE_6: - // Added for ScummVM - case Common::KEYCODE_DOWN: - case Common::KEYCODE_RIGHT: - case Common::KEYCODE_KP2: - case Common::KEYCODE_KP6: - // Original checks joystick axis: case 0xCC, 0xCF - if (_menuDepth == 0) { - if (++windowId > 8) - windowId = 0; - } else if (_menuDepth == 1) { - if (_menuItemCounter != 0) { - ++curMenuLine; - if (curMenuLine > _menuItemCounter - 1) - curMenuLine = 0; - } - } - break; - case Common::KEYCODE_4: - case Common::KEYCODE_8: - // Added for ScummVM - case Common::KEYCODE_LEFT: - case Common::KEYCODE_UP: - case Common::KEYCODE_KP4: - case Common::KEYCODE_KP8: - // Original checks joystick axis: case 0xC7, 0xCA - if (_menuDepth == 0) { - if (--windowId < 0) - windowId = 8; - } else if (_menuDepth == 1) { - if (_menuItemCounter != 0) { - --curMenuLine; - if (curMenuLine < 0) - curMenuLine = _menuItemCounter - 1; - } - } - break; - default: - break; - } - - if (curMenuLine == -1) - prepareStatusMenu(windowId, menuId, curMenuLine, charId, false, true); - else - prepareStatusMenu(windowId, menuId, curMenuLine, charId, true, true); - - } while (!var10); - - bool validationFl = true; - - int16 objectId; - int16 itemId; - switch (menuId) { - case 0: - objectId = _menuStatItemArr[selectedLine]; - itemId = _npcBuf[charId]._inventory[objectId]._ref; - sub191FF(charId, objectId, windowId, menuId, curMenuLine); - if (gameMode == 2) { - restoreAnimImageSetId(); - _statusMenuActive = false; - return 0x7D00; - } - break; - case 1: - objectId = _menuStatItemArr[selectedLine]; - itemId = _npcBuf[charId]._inventory[objectId]._ref; - if (gameMode == 2) { - restoreAnimImageSetId(); - _statusMenuActive = false; - return objectId; - } - - if (sub22293(_mapPosX, _mapPosY, charId, itemId, 2, -1)) { - _statusMenuActive = false; - return -1; - } - - sub19E2E(charId, objectId, windowId, menuId, curMenuLine, 2); - break; - case 2: - objectId = _menuStatItemArr[selectedLine]; - itemId = _npcBuf[charId]._inventory[objectId]._ref; - if (hasObjectEquipped(charId, objectId) && isItemCursed(itemId)) { - displayString_3("The item is cursed! IT IS EVIL!!!!!!!!", true, charId, windowId, menuId, curMenuLine); - } else if (hasObjectEquipped(charId, objectId)){ - displayString_3("Item is Equipped! Give anyway?", false, charId, windowId, menuId, curMenuLine); - if (!getValidationFromUser()) - validationFl = false; - sub18E80(charId, windowId, menuId, curMenuLine); - - if (validationFl) { - if (gameMode == 2) { - displayString_3("Not a Combat Option !", true, charId, windowId, menuId, curMenuLine); - } else { - removeObject(charId, objectId); - int16 var8 = sub22293(_mapPosX, _mapPosY, charId, itemId, 3, -1); - if (var8 != 0) { - _statusMenuActive = false; - return -1; - } - } - } - } - - break; - case 3: - objectId = _menuStatItemArr[selectedLine]; - itemId = _npcBuf[charId]._inventory[objectId]._ref; - if (hasObjectEquipped(charId, objectId) && isItemCursed(itemId)) { - displayString_3("The item is cursed! IT IS EVIL!!!!!!!!", true, charId, windowId, menuId, curMenuLine); - } else if (hasObjectEquipped(charId, objectId)) { - displayString_3("Item is Equipped! Trade anyway?", false, charId, windowId, menuId, curMenuLine); - if (!getValidationFromUser()) - validationFl = false; - sub18E80(charId, windowId, menuId, curMenuLine); - - if (validationFl) { - bool var6; - int16 var8; - do { - if (_teamCharId[2] != -1) { - var8 = displayString_3("Who will you give the item to?", false, charId, windowId, menuId, curMenuLine); - var2 = false; - } else if (_teamCharId[1]) { - var8 = 0x1A; - var2 = false; - } else { - var2 = true; - if (_teamCharId[0] == charId) - var8 = 1; - else - var8 = 0; - } - - if (var8 != 0x1A && var8 != 0x1B) { - var6 = giveItemTo(_teamCharId[var8], objectId, charId); - if (!var6) { - displayString_3("That character cannot carry anymore!", false, charId, windowId, menuId, curMenuLine); - getLastCharAfterAnimCount(_guessAnimationAmount); - } - } else { - if (var8 == 0x1A) { - displayString_3("No one to trade with!", false, charId, windowId, menuId, curMenuLine); - getLastCharAfterAnimCount(_guessAnimationAmount); - var8 = 0x1B; - } - var6 = false; - } - } while (!var6 && !var2 && var8 != 0x1B); - - if (var6) { - removeObject(charId, objectId); - if (gameMode == 2) { - restoreAnimImageSetId(); - _statusMenuActive = false; - return 0x7D00; - } - } - - sub18E80(charId, windowId, menuId, curMenuLine); - } - } - break; - case 4: - objectId = _menuStatItemArr[selectedLine]; - itemId = _npcBuf[charId]._inventory[objectId]._ref; - if (hasObjectEquipped(charId, objectId) && isItemCursed(itemId)) { - displayString_3("The item is cursed! IT IS EVIL!!!!!!!!", true, charId, windowId, menuId, curMenuLine); - } else if (hasObjectEquipped(charId, objectId)) { - displayString_3("Item Is Equipped! Drop Anyway?", false, charId, windowId, menuId, curMenuLine); - if (!getValidationFromUser()) - validationFl = false; - sub18E80(charId, windowId, menuId, curMenuLine); - - if (validationFl) { - removeObject(charId, objectId); - if (gameMode == 2) { - restoreAnimImageSetId(); - _statusMenuActive = false; - return 0x7D00; - } - - bool var8 = sub22293(_mapPosX, _mapPosY, charId, itemId, 1, -1); - if (var8) { - _statusMenuActive = false; - return -1; - } - } - } - break; - case 5: - objectId = _menuStatItemArr[selectedLine]; - if (gameMode == 2) { - displayString_3("Not a Combat Option!", true, charId, windowId, menuId, curMenuLine); - } else { - bool var8 = sub22293(_mapPosX, _mapPosY, charId, objectId, 4, -1); - if (var8) { - _statusMenuActive = false; - return -1; - } - } - break; - case 6: // Identical to case 5? - objectId = _menuStatItemArr[selectedLine]; - if (gameMode == 2) { - displayString_3("Not a Combat Option!", true, charId, windowId, menuId, curMenuLine); - } else { - bool var8 = sub22293(_mapPosX, _mapPosY, charId, objectId, 4, -1); - if (var8) { - _statusMenuActive = false; - return -1; - } - } - break; - case 7: // Identical to case 5? - objectId = _menuStatItemArr[selectedLine]; - if (gameMode == 2) { - displayString_3("Not a Combat Option!", true, charId, windowId, menuId, curMenuLine); - } else { - bool var8 = sub22293(_mapPosX, _mapPosY, charId, objectId, 4, -1); - if (var8) { - _statusMenuActive = false; - return -1; - } - } - break; - default: - break; - } - - if (menuId != 8) { - var10 = false; - _menuDepth = 0; - menuId = 9; - selectedLine = -1; - curMenuLine = -1; - } - - if (menuId == 8) { - restoreAnimImageSetId(); - _statusMenuActive = false; - return 0x7FFF; - } - } - - return 0; -} - bool EfhEngine::checkMonsterCollision() { debug("checkMonsterCollision"); diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 34c9da9af2d2..b59fac80aca2 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -363,18 +363,13 @@ class EfhEngine : public Engine { int16 countMonsterGroupMembers(int16 monsterGroup); void sub1D8C2(int16 charId, int16 damage); int16 getXPLevel(int32 xp); - int16 displayString_3(Common::String str, bool animFl, int16 charId, int16 windowId, int16 menuId, int16 curMenuLine); bool isItemCursed(int16 itemId); bool hasObjectEquipped(int16 charId, int16 objectId); - void equipCursedItem(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine); - void sub191FF(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine); - void sub1E028(int16 id, uint8 mask, int16 groupFl); + void setMapMonsterField8(int16 id, uint8 mask, bool groupFl); bool isMonsterActive(int16 groupId, int16 id); int16 sub15538(int16 mapPosX, int16 mapPosY); void setCharacterObjectToBroken(int16 charId, int16 objectId); int16 selectOtherCharFromTeam(); - int16 sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine, int16 argA); - int16 handleStatusMenu(int16 gameMode, int16 charId); bool checkMonsterCollision(); // Fight @@ -467,6 +462,11 @@ class EfhEngine : public Engine { void displayStatusMenuActions(int16 menuId, int16 curMenuLine, int16 npcId); void prepareStatusMenu(int16 windowId, int16 menuId, int16 curMenuLine, int16 charId, bool unusedFl, bool refreshFl); void sub18E80(int16 charId, int16 windowId, int16 menuId, int16 curMenuLine); + int16 displayString_3(Common::String str, bool animFl, int16 charId, int16 windowId, int16 menuId, int16 curMenuLine); + int16 handleStatusMenu(int16 gameMode, int16 charId); + void equipCursedItem(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine); + void sub191FF(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine); + int16 sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine, int16 argA); // Savegames void synchronize(Common::Serializer &s); diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index 30e4f99eb6f6..0e375cafaead 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -456,7 +456,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { if (isMonsterActive(groupId, var7E) && var6E) { int16 var5C; if (unkFct_checkMonsterField8(groupId, true)) { - sub1E028(groupId, 9, true); + setMapMonsterField8(groupId, 9, true); _unkArray2C8AA[0] += 500; var5C = -1; } else diff --git a/engines/efh/menu.cpp b/engines/efh/menu.cpp index 9fea7b774a54..5ed31e12ad83 100644 --- a/engines/efh/menu.cpp +++ b/engines/efh/menu.cpp @@ -62,7 +62,7 @@ int16 EfhEngine::sub1C219(Common::String str, int16 menuType, int16 displayOptio } drawColoredRect(minX, minY, maxX, maxY, 0); - if (str.size()) + if (!str.empty()) varA = script_parse(str, minX, minY, maxX, maxY, true); if (displayTeamWindowFl) @@ -74,7 +74,7 @@ int16 EfhEngine::sub1C219(Common::String str, int16 menuType, int16 displayOptio _word2C87A = false; else { drawColoredRect(minX, minY, maxX, maxY, 0); - if (str.size()) + if (!str.empty()) script_parse(str, minX, minY, maxX, maxY, false); } @@ -92,7 +92,7 @@ int16 EfhEngine::sub1C219(Common::String str, int16 menuType, int16 displayOptio } bool EfhEngine::handleDeathMenu() { - debug("handleDeathMenu"); + debugC(3, kDebugEngine, "handleDeathMenu"); _saveAuthorized = false; @@ -126,14 +126,12 @@ bool EfhEngine::handleDeathMenu() { Common::KeyCode input = waitForKey(); switch (input) { case Common::KEYCODE_l: - //loadEfhGame(); - //TODO: - //SaveEfhGame opens the GUI save/load screen. It's not possible to save at this point, which is fine, but it's possible to close the screen without loading. - //Maybe adding the _saveAuthorized flag in the savegame would do the trick and could then be used tp keep found at false and loop on the input selection? - //like: found = _saveAuthorized + // SaveEfhGame opens the GUI save/load screen. It's not possible to save at this point (_saveAuthorizd is false). + // If the user actually loads a savegame, it'll get _saveAuthorized from the savegame (always true) and will set 'found' to true. + // If 'found' remains false, it means the user cancelled the loading and still needs to take a decision + // Original is calling loadEfhGame() because there's only one savegame, so it's not ambiguous saveEfhGame(); - found = true; - _saveAuthorized = true; + found = _saveAuthorized; break; case Common::KEYCODE_q: _shouldQuit = true; @@ -158,10 +156,9 @@ bool EfhEngine::handleDeathMenu() { } void EfhEngine::displayCombatMenu(int16 charId) { - debug("displayCombatMenu %d", charId); + debugC(6, kDebugEngine, "displayCombatMenu %d", charId); - Common::String buffer = _npcBuf[charId]._name; - buffer += ":"; + Common::String buffer = Common::String::format("%s:", _npcBuf[charId]._name); setTextColorWhite(); setTextPos(144, 7); displayStringAtTextPos(buffer); @@ -482,5 +479,978 @@ void EfhEngine::sub18E80(int16 charId, int16 windowId, int16 menuId, int16 curMe } } +int16 EfhEngine::displayString_3(Common::String str, bool animFl, int16 charId, int16 windowId, int16 menuId, int16 curMenuLine) { + debug("displayString_3 %s %s %d %d %d %d", str.c_str(), animFl ? "True" : "False", charId, windowId, menuId, curMenuLine); + + int16 retVal = 0; + + for (uint counter = 0; counter < 2; ++counter) { + prepareStatusMenu(windowId, menuId, curMenuLine, charId, true, false); + displayWindow(_windowWithBorderBuf, 19, 113, _hiResImageBuf); + + if (counter == 0) { + script_parse(str, 28, 122, 105, 166, false); + displayFctFullScreen(); + } else { + retVal = script_parse(str, 28, 122, 105, 166, true); + } + } + + if (animFl) { + getLastCharAfterAnimCount(_guessAnimationAmount); + sub18E80(charId, windowId, menuId, curMenuLine); + } + + return retVal; +} + +int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { + debug("handleStatusMenu %d %d", gameMode, charId); + + int16 menuId = 9; + int16 selectedLine = -1; + int16 windowId = -1; + int16 curMenuLine = -1; + bool var10 = false; + bool var2 = false; + + saveAnimImageSetId(); + + _statusMenuActive = true; + _menuDepth = 0; + + sub18E80(charId, windowId, menuId, curMenuLine); + + for (;;) { + if (windowId != -1) + prepareStatusMenu(windowId, menuId, curMenuLine, charId, true, true); + else + windowId = 0; + + do { + Common::KeyCode var19 = handleAndMapInput(false); + if (_menuDepth == 0) { + switch (var19) { + case Common::KEYCODE_ESCAPE: + windowId = 8; + var19 = Common::KEYCODE_RETURN; + break; + case Common::KEYCODE_a: + windowId = 7; + var19 = Common::KEYCODE_RETURN; + break; + case Common::KEYCODE_d: + windowId = 4; + var19 = Common::KEYCODE_RETURN; + break; + case Common::KEYCODE_e: + windowId = 0; + var19 = Common::KEYCODE_RETURN; + break; + case Common::KEYCODE_g: + windowId = 2; + var19 = Common::KEYCODE_RETURN; + break; + case Common::KEYCODE_i: + windowId = 5; + var19 = Common::KEYCODE_RETURN; + break; + case Common::KEYCODE_l: + windowId = 8; + var19 = Common::KEYCODE_RETURN; + break; + case Common::KEYCODE_p: + windowId = 6; + var19 = Common::KEYCODE_RETURN; + break; + case Common::KEYCODE_t: + windowId = 3; + var19 = Common::KEYCODE_RETURN; + break; + case Common::KEYCODE_u: + windowId = 1; + var19 = Common::KEYCODE_RETURN; + break; + // case 0xFB: Joystick button 2 + default: + // warning("handleStatusMenu - unhandled keys (or joystick event?) 0xBA, 0xBB, 0xBC"); + break; + } + } else if (_menuDepth == 1) { + // in the sub-menus, only a list of selectable items is displayed + if (var19 >= Common::KEYCODE_a && var19 <= Common::KEYCODE_z) { + int16 var8 = var19 - Common::KEYCODE_a; + if (var8 < _menuItemCounter) { + curMenuLine = var8; + var19 = Common::KEYCODE_RETURN; + } + } + } + + switch (var19) { + case Common::KEYCODE_RETURN: + // case 0xFA: Joystick button 1 + if (_menuDepth == 0) { + menuId = windowId; + if (menuId > 7) + var10 = true; + else { + _menuDepth = 1; + curMenuLine = 0; + } + } else if (_menuDepth == 1) { + if (_menuItemCounter == 0) { + _menuDepth = 0; + curMenuLine = -1; + menuId = 9; + prepareStatusMenu(windowId, menuId, curMenuLine, charId, true, true); + } else { + selectedLine = curMenuLine; + var10 = true; + } + } + break; + case Common::KEYCODE_ESCAPE: + _menuDepth = 0; + curMenuLine = -1; + menuId = 9; + prepareStatusMenu(windowId, menuId, curMenuLine, charId, true, true); + break; + case Common::KEYCODE_2: + case Common::KEYCODE_6: + // Added for ScummVM + case Common::KEYCODE_DOWN: + case Common::KEYCODE_RIGHT: + case Common::KEYCODE_KP2: + case Common::KEYCODE_KP6: + // Original checks joystick axis: case 0xCC, 0xCF + if (_menuDepth == 0) { + if (++windowId > 8) + windowId = 0; + } else if (_menuDepth == 1) { + if (_menuItemCounter != 0) { + ++curMenuLine; + if (curMenuLine > _menuItemCounter - 1) + curMenuLine = 0; + } + } + break; + case Common::KEYCODE_4: + case Common::KEYCODE_8: + // Added for ScummVM + case Common::KEYCODE_LEFT: + case Common::KEYCODE_UP: + case Common::KEYCODE_KP4: + case Common::KEYCODE_KP8: + // Original checks joystick axis: case 0xC7, 0xCA + if (_menuDepth == 0) { + if (--windowId < 0) + windowId = 8; + } else if (_menuDepth == 1) { + if (_menuItemCounter != 0) { + --curMenuLine; + if (curMenuLine < 0) + curMenuLine = _menuItemCounter - 1; + } + } + break; + default: + break; + } + + if (curMenuLine == -1) + prepareStatusMenu(windowId, menuId, curMenuLine, charId, false, true); + else + prepareStatusMenu(windowId, menuId, curMenuLine, charId, true, true); + + } while (!var10); + + bool validationFl = true; + + int16 objectId; + int16 itemId; + switch (menuId) { + case 0: + objectId = _menuStatItemArr[selectedLine]; + itemId = _npcBuf[charId]._inventory[objectId]._ref; // CHECKME: Useless? + sub191FF(charId, objectId, windowId, menuId, curMenuLine); + if (gameMode == 2) { + restoreAnimImageSetId(); + _statusMenuActive = false; + return 0x7D00; + } + break; + case 1: + objectId = _menuStatItemArr[selectedLine]; + itemId = _npcBuf[charId]._inventory[objectId]._ref; + if (gameMode == 2) { + restoreAnimImageSetId(); + _statusMenuActive = false; + return objectId; + } + + if (sub22293(_mapPosX, _mapPosY, charId, itemId, 2, -1)) { + _statusMenuActive = false; + return -1; + } + + sub19E2E(charId, objectId, windowId, menuId, curMenuLine, 2); + break; + case 2: + objectId = _menuStatItemArr[selectedLine]; + itemId = _npcBuf[charId]._inventory[objectId]._ref; + if (hasObjectEquipped(charId, objectId) && isItemCursed(itemId)) { + displayString_3("The item is cursed! IT IS EVIL!!!!!!!!", true, charId, windowId, menuId, curMenuLine); + } else if (hasObjectEquipped(charId, objectId)) { + displayString_3("Item is Equipped! Give anyway?", false, charId, windowId, menuId, curMenuLine); + if (!getValidationFromUser()) + validationFl = false; + sub18E80(charId, windowId, menuId, curMenuLine); + + if (validationFl) { + if (gameMode == 2) { + displayString_3("Not a Combat Option !", true, charId, windowId, menuId, curMenuLine); + } else { + removeObject(charId, objectId); + int16 var8 = sub22293(_mapPosX, _mapPosY, charId, itemId, 3, -1); + if (var8 != 0) { + _statusMenuActive = false; + return -1; + } + } + } + } + + break; + case 3: + objectId = _menuStatItemArr[selectedLine]; + itemId = _npcBuf[charId]._inventory[objectId]._ref; + if (hasObjectEquipped(charId, objectId) && isItemCursed(itemId)) { + displayString_3("The item is cursed! IT IS EVIL!!!!!!!!", true, charId, windowId, menuId, curMenuLine); + } else if (hasObjectEquipped(charId, objectId)) { + displayString_3("Item is Equipped! Trade anyway?", false, charId, windowId, menuId, curMenuLine); + if (!getValidationFromUser()) + validationFl = false; + sub18E80(charId, windowId, menuId, curMenuLine); + + if (validationFl) { + bool var6; + int16 var8; + do { + if (_teamCharId[2] != -1) { + var8 = displayString_3("Who will you give the item to?", false, charId, windowId, menuId, curMenuLine); + var2 = false; + } else if (_teamCharId[1]) { + var8 = 0x1A; + var2 = false; + } else { + var2 = true; + if (_teamCharId[0] == charId) + var8 = 1; + else + var8 = 0; + } + + if (var8 != 0x1A && var8 != 0x1B) { + var6 = giveItemTo(_teamCharId[var8], objectId, charId); + if (!var6) { + displayString_3("That character cannot carry anymore!", false, charId, windowId, menuId, curMenuLine); + getLastCharAfterAnimCount(_guessAnimationAmount); + } + } else { + if (var8 == 0x1A) { + displayString_3("No one to trade with!", false, charId, windowId, menuId, curMenuLine); + getLastCharAfterAnimCount(_guessAnimationAmount); + var8 = 0x1B; + } + var6 = false; + } + } while (!var6 && !var2 && var8 != 0x1B); + + if (var6) { + removeObject(charId, objectId); + if (gameMode == 2) { + restoreAnimImageSetId(); + _statusMenuActive = false; + return 0x7D00; + } + } + + sub18E80(charId, windowId, menuId, curMenuLine); + } + } + break; + case 4: + objectId = _menuStatItemArr[selectedLine]; + itemId = _npcBuf[charId]._inventory[objectId]._ref; + if (hasObjectEquipped(charId, objectId) && isItemCursed(itemId)) { + displayString_3("The item is cursed! IT IS EVIL!!!!!!!!", true, charId, windowId, menuId, curMenuLine); + } else if (hasObjectEquipped(charId, objectId)) { + displayString_3("Item Is Equipped! Drop Anyway?", false, charId, windowId, menuId, curMenuLine); + if (!getValidationFromUser()) + validationFl = false; + sub18E80(charId, windowId, menuId, curMenuLine); + + if (validationFl) { + removeObject(charId, objectId); + if (gameMode == 2) { + restoreAnimImageSetId(); + _statusMenuActive = false; + return 0x7D00; + } + + bool var8 = sub22293(_mapPosX, _mapPosY, charId, itemId, 1, -1); + if (var8) { + _statusMenuActive = false; + return -1; + } + } + } + break; + case 5: + objectId = _menuStatItemArr[selectedLine]; + if (gameMode == 2) { + displayString_3("Not a Combat Option!", true, charId, windowId, menuId, curMenuLine); + } else { + bool var8 = sub22293(_mapPosX, _mapPosY, charId, objectId, 4, -1); + if (var8) { + _statusMenuActive = false; + return -1; + } + } + break; + case 6: // Identical to case 5? + objectId = _menuStatItemArr[selectedLine]; + if (gameMode == 2) { + displayString_3("Not a Combat Option!", true, charId, windowId, menuId, curMenuLine); + } else { + bool var8 = sub22293(_mapPosX, _mapPosY, charId, objectId, 4, -1); + if (var8) { + _statusMenuActive = false; + return -1; + } + } + break; + case 7: // Identical to case 5? + objectId = _menuStatItemArr[selectedLine]; + if (gameMode == 2) { + displayString_3("Not a Combat Option!", true, charId, windowId, menuId, curMenuLine); + } else { + bool var8 = sub22293(_mapPosX, _mapPosY, charId, objectId, 4, -1); + if (var8) { + _statusMenuActive = false; + return -1; + } + } + break; + default: + break; + } + + if (menuId != 8) { + var10 = false; + _menuDepth = 0; + menuId = 9; + selectedLine = -1; + curMenuLine = -1; + } + + if (menuId == 8) { + restoreAnimImageSetId(); + _statusMenuActive = false; + return 0x7FFF; + } + } + + return 0; +} + +void EfhEngine::equipCursedItem(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine) { + debug("equipCursedItem %d %d %d %d %d", charId, objectId, windowId, menuId, curMenuLine); + + int16 itemId = _npcBuf[charId]._inventory[objectId]._ref; + + if (isItemCursed(itemId)) { + _npcBuf[charId]._inventory[objectId]._stat1 &= 0x7F; + } else { + displayString_3("Cursed Item Already Equipped!", true, charId, windowId, menuId, curMenuLine); + } +} + +void EfhEngine::sub191FF(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine) { + debug("sub191FF %d %d %d %d %d", charId, objectId, windowId, menuId, curMenuLine); + + int16 itemId = _npcBuf[charId]._inventory[objectId]._ref; + + if (hasObjectEquipped(charId, objectId)) { + equipCursedItem(charId, objectId, windowId, menuId, curMenuLine); + } else { + int16 var2 = _items[itemId].field_18; + if (var2 != 4) { + for (uint counter = 0; counter < 10; ++counter) { + if (var2 == _items[_npcBuf[charId]._inventory[counter]._ref].field_18) + equipCursedItem(charId, objectId, windowId, menuId, curMenuLine); + } + } + + _npcBuf[charId]._inventory[objectId]._stat1 |= 0x80; + } +} + +int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine, int16 argA) { + debug("sub19E2E %d %d %d %d %d %d", charId, objectId, windowId, menuId, curMenuLine, argA); + + Common::String buffer1 = ""; + + bool varA6 = false; + bool retVal = false; + + int16 itemId = _npcBuf[charId]._inventory[objectId]._ref; + switch (_items[itemId].field_16 - 1) { + case 0: // "Demonic Powers", "MindDomination", "Guilt Trip", "Sleep Grenade", "SleepGrenader" + if (argA == 2) { + displayString_3("The item emits a low droning hum...", false, charId, windowId, menuId, curMenuLine); + } else { + int16 victims = 0; + _messageToBePrinted += " The item emits a low droning hum..."; + if (getRandom(100) < 50) { + for (uint counter = 0; counter < 9; ++counter) { + if (isMonsterActive(windowId, counter)) { + ++victims; + _stru32686[windowId]._field0[counter] = 1; + _stru32686[windowId]._field2[counter] = getRandom(8); + } + } + } else { + int16 NumberOfTargets = getRandom(9); + for (uint counter = 0; counter < 9; ++counter) { + if (NumberOfTargets == 0) + break; + + if (isMonsterActive(windowId, counter)) { + ++victims; + --NumberOfTargets; + _stru32686[windowId]._field0[counter] = 1; + _stru32686[windowId]._field2[counter] = getRandom(8); + } + } + } + // The original was duplicating this code in each branch of the previous random check. + if (victims > 1) { + buffer1 = Common::String::format("%d %ss fall asleep!", victims, kEncounters[_mapMonsters[_teamMonsterIdArray[windowId]]._monsterRef]._name); + } else { + buffer1 = Common::String::format("%d %s falls asleep!", victims, kEncounters[_mapMonsters[_teamMonsterIdArray[windowId]]._monsterRef]._name); + } + _messageToBePrinted += buffer1; + } + + varA6 = true; + break; + case 1: // "Chilling Touch", "Guilt", "Petrify Rod", "Elmer's Gun" + if (argA == 2) { + displayString_3("The item grows very cold for a moment...", false, charId, windowId, menuId, curMenuLine); + } else { + _messageToBePrinted += " The item emits a blue beam..."; + int16 victim = 0; + if (getRandom(100) < 50) { + for (uint varA8 = 0; varA8 < 9; ++varA8) { + if (isMonsterActive(windowId, varA8)) { + ++victim; + _stru32686[windowId]._field0[varA8] = 2; + _stru32686[windowId]._field2[varA8] = getRandom(8); + } + } + } else { + int16 varAC = getRandom(9); + for (uint varA8 = 0; varA8 < 9; ++varA8) { + if (varAC == 0) + break; + + if (isMonsterActive(windowId, varA8)) { + ++victim; + --varAC; + _stru32686[windowId]._field0[varA8] = 2; + _stru32686[windowId]._field2[varA8] = getRandom(8); + } + } + } + // : This part is only present in the original in the case < 50, but for me + // it's missing in the other case as there's an effect (frozen enemies) but no feedback to the player + if (victim > 1) { + buffer1 = Common::String::format("%d %ss are frozen in place!", victim, kEncounters[_mapMonsters[_teamMonsterIdArray[windowId]]._monsterRef]._name); + } else { + buffer1 = Common::String::format("%d %s is frozen in place!", victim, kEncounters[_mapMonsters[_teamMonsterIdArray[windowId]]._monsterRef]._name); + } + _messageToBePrinted += buffer1; + // + } + + varA6 = true; + break; + case 2: + if (argA == 2) { + displayString_3("A serene feeling passes through the air...", false, charId, windowId, menuId, curMenuLine); + } else { + _messageToBePrinted += " The combat pauses...as there is a moment of forgiveness..."; + _unkArray2C8AA[0] = 0; + } + + varA6 = true; + break; + case 4: // "Unholy Sinwave", "Holy Water" + if (argA == 2) { + displayString_3("A dark sense fills your soul...then fades!", false, charId, windowId, menuId, curMenuLine); + } else { + _messageToBePrinted += " A dark gray fiery whirlwind surrounds the poor victim...the power fades and death abounds!"; + if (getRandom(100) < 50) { + for (uint counter = 0; counter < 9; ++counter) { + if (getRandom(100) < 50) { + _mapMonsters[_teamMonsterIdArray[windowId]]._pictureRef[counter] = 0; + } + } + } else { + for (uint counter = 0; counter < 9; ++counter) { + if (isMonsterActive(windowId, counter)) { + if (getRandom(100) < 50) { + _mapMonsters[_teamMonsterIdArray[windowId]]._pictureRef[counter] = 0; + } + break; + } + } + } + } + varA6 = true; + break; + case 5: // "Lucifer'sTouch", "Book of Death", "Holy Cross" + if (argA == 2) { + displayString_3("A dark sense fills your soul...then fades!", false, charId, windowId, menuId, curMenuLine); + } else { + if (getRandom(100) < 50) { + _messageToBePrinted += " A dark fiery whirlwind surrounds the poor victim...the power fades and all targeted die!"; + for (uint counter = 0; counter < 9; ++counter) { + _mapMonsters[_teamMonsterIdArray[windowId]]._pictureRef[counter] = 0; + } + } else { + _messageToBePrinted += " A dark fiery whirlwind surrounds the poor victim...the power fades and one victim dies!"; + for (uint counter = 0; counter < 9; ++counter) { + if (isMonsterActive(windowId, counter)) { + _mapMonsters[_teamMonsterIdArray[windowId]]._pictureRef[counter] = 0; + } + } + } + } + + varA6 = true; + break; + case 12: // "Terror Gaze", "Servitude Rod", "Despair Ankh", "ConfusionPrism", "Pipe of Peace", "Red Cape", "Peace Symbol", "Hell Badge" + if (argA == 2) { + displayString_3("There is no apparent affect!", false, charId, windowId, menuId, curMenuLine); + } else { + _messageToBePrinted += " The magic sparkles brilliant hues in the air!"; + setMapMonsterField8(windowId, _items[itemId].field17_attackTypeDefense, true); + } + varA6 = true; + break; + case 14: { // "Feathered Cap" + int16 varAA; + if (argA == 2) { + displayString_3("Who will use the item?", false, charId, windowId, menuId, curMenuLine); + varAA = selectOtherCharFromTeam(); + } else { + varAA = windowId; + } + + if (varAA != 0x1B) { + buffer1 = " The magic makes the user as quick and agile as a bird!"; + if (argA == 2) { + displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + } else { + _messageToBePrinted += buffer1; + } + _word32482[varAA] -= 50; + if (_word32482[varAA] < 0) + _word32482[varAA] = 0; + } + + varA6 = true; + } break; + case 15: { // "Regal Crown" + int16 teamCharId; + if (argA == 2) { + displayString_3("Who will use the item?", false, charId, windowId, menuId, curMenuLine); + teamCharId = selectOtherCharFromTeam(); + } else { + teamCharId = windowId; + } + + if (teamCharId != 0x1B) { + buffer1 = " The magic makes the user invisible!"; + if (argA == 2) { + displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + } else { + _messageToBePrinted += buffer1; + } + + _teamPctVisible[teamCharId] -= 50; + if (_teamPctVisible[teamCharId] < 0) + _teamPctVisible[teamCharId] = 0; + } + + varA6 = true; + } break; + case 16: { // Fairy Dust + _mapPosX = getRandom(_largeMapFlag ? 63 : 23); + _mapPosY = getRandom(_largeMapFlag ? 63 : 23); + int16 varAE = sub15538(_mapPosX, _mapPosY); + + if (_tileFact[varAE]._field0 == 0) { + totalPartyKill(); + buffer1 = "The entire party vanishes in a flash... only to appear in stone !"; + if (argA == 2) { + displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + } else { + _messageToBePrinted += buffer1; + retVal = true; + } + // emptyFunction(2); + } else { + if (varAE == 0 || varAE == 0x48) { + buffer1 = "The entire party vanishes in a flash...but re-appears, as if nothing happened!"; + if (argA == 2) { + displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + } else { + _messageToBePrinted += buffer1; + retVal = true; + } + } else { + buffer1 = "The entire party vanishes in a flash...only to appear elsewhere!"; + if (argA == 2) { + displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + } else { + _messageToBePrinted += buffer1; + retVal = true; + } + } + } + + varA6 = true; + } break; + case 17: { // "Devil Dust" + _mapPosX = _items[itemId].field_19; + _mapPosY = _items[itemId].field_1A; + int16 varAE = sub15538(_mapPosX, _mapPosY); + if (_tileFact[varAE]._field0 == 0) { + totalPartyKill(); + buffer1 = "The entire party vanishes in a flash... only to appear in stone !"; + if (argA == 2) { + displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + } else { + _messageToBePrinted += buffer1; + retVal = true; + } + // emptyFunction(2); + } else { + if (varAE == 0 || varAE == 0x48) { + buffer1 = "The entire party vanishes in a flash...but re-appears, as if nothing happened!"; + if (argA == 2) { + displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + } else { + _messageToBePrinted += buffer1; + retVal = true; + } + } else { + buffer1 = "The entire party vanishes in a flash...only to appear elsewhere!"; + if (argA == 2) { + displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + } else { + _messageToBePrinted += buffer1; + retVal = true; + } + } + } + + varA6 = true; + } break; + case 18: + if (argA == 2) { + displayString_3("The item makes a loud noise!", false, charId, windowId, menuId, curMenuLine); + } else { + int16 teamCharId = windowId; + if (teamCharId != 0x1B) { + if (_teamCharStatus[teamCharId]._status == 2) { // frozen + _messageToBePrinted += " The item makes a loud noise, awakening the character!"; + _teamCharStatus[teamCharId]._status = 0; + _teamCharStatus[teamCharId]._duration = 0; + } else { + _messageToBePrinted += " The item makes a loud noise, but has no effect!"; + } + } + } + + varA6 = true; + break; + case 19: // "Junk" + buffer1 = " * The item breaks!"; + if (argA == 2) { + displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + } else { + _messageToBePrinted += buffer1; + } + setCharacterObjectToBroken(charId, objectId); + varA6 = true; + break; + case 23: // "Divining Rod" + buffer1 = Common::String::format("The %s says, '", _items[itemId]._name); + if (_items[itemId].field_19 < _mapPosX) { + if (_items[itemId].field_1A < _mapPosY) { + buffer1 += "North West!"; + } else if (_items[itemId].field_1A > _mapPosY) { + buffer1 += "South West!"; + } else { + buffer1 += "West!"; + } + } else if (_items[itemId].field_19 > _mapPosX) { + if (_items[itemId].field_1A < _mapPosY) { + buffer1 += "North East!"; + } else if (_items[itemId].field_1A > _mapPosY) { + buffer1 += "South East!"; + } else { + buffer1 += "East!"; + } + } else { // equals _mapPosX + if (_items[itemId].field_1A < _mapPosY) { + buffer1 += "North!"; + } else if (_items[itemId].field_1A > _mapPosY) { + buffer1 += "South!"; + } else { + buffer1 += "Here!!!"; + } + } + buffer1 += "'"; + if (argA == 2) { + displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + } else { + _messageToBePrinted += buffer1; + retVal = true; + } + + varA6 = true; + break; + case 24: { + int16 teamCharId; + if (argA == 2) { + displayString_3("Who will use this item?", false, charId, windowId, menuId, curMenuLine); + teamCharId = selectOtherCharFromTeam(); + } else + teamCharId = windowId; + + if (teamCharId != 0x1B) { + uint8 varAE = _items[itemId].field17_attackTypeDefense; + uint8 effectPoints = getRandom(_items[itemId].field_19); + _npcBuf[_teamCharId[teamCharId]]._activeScore[varAE] += effectPoints; + if (_npcBuf[_teamCharId[teamCharId]]._activeScore[varAE] > 20) { + _npcBuf[_teamCharId[teamCharId]]._activeScore[varAE] = 20; + } + if (effectPoints > 1) + buffer1 = Common::String::format("%s increased %d points!", kSkillArray[varAE], effectPoints); + else + buffer1 = Common::String::format("%s increased 1 point!", kSkillArray[varAE]); + + if (argA == 2) { + displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + } else { + _messageToBePrinted += buffer1; + retVal = true; + } + } + + varA6 = true; + } break; + case 25: { + int16 teamCharId; + if (argA == 2) { + displayString_3("Who will use this item?", false, charId, windowId, menuId, curMenuLine); + teamCharId = selectOtherCharFromTeam(); + } else + teamCharId = windowId; + + if (teamCharId != 0x1B) { + uint8 varAE = _items[itemId].field17_attackTypeDefense; + uint8 effectPoints = getRandom(_items[itemId].field_19); + _npcBuf[_teamCharId[teamCharId]]._activeScore[varAE] -= effectPoints; + if (_npcBuf[_teamCharId[teamCharId]]._activeScore[varAE] > 20 || _npcBuf[_teamCharId[teamCharId]]._activeScore[varAE] < 0) { + _npcBuf[_teamCharId[teamCharId]]._activeScore[varAE] = 1; + } + if (effectPoints > 1) + buffer1 = Common::String::format("%s lowered %d points!", kSkillArray[varAE], effectPoints); + else + buffer1 = Common::String::format("%s lowered 1 point!", kSkillArray[varAE]); + + if (argA == 2) { + displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + } else { + _messageToBePrinted += buffer1; + retVal = true; + } + } + + varA6 = true; + } break; + case 26: // "Black Sphere" + buffer1 = "The entire party collapses, dead!!!"; + if (argA == 2) { + displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + } else { + _messageToBePrinted += buffer1; + retVal = true; + } + totalPartyKill(); + // emptyFunction(2); + varA6 = true; + break; + case 27: { // "Magic Pyramid", "Razor Blade" + int16 teamCharId; + if (argA == 2) { + displayString_3("Who will use the item?", false, charId, windowId, menuId, curMenuLine); + teamCharId = selectOtherCharFromTeam(); + } else { + teamCharId = windowId; + } + + if (teamCharId != 0x1B) { + _npcBuf[_teamCharId[teamCharId]]._hitPoints = 0; + buffer1 = Common::String::format("%s collapses, dead!!!", _npcBuf[_teamCharId[teamCharId]]._name); + if (argA == 2) { + displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + } else { + _messageToBePrinted += buffer1; + retVal = true; + } + // emptyFunction(2); + } + + varA6 = true; + } break; + case 28: // "Bugle" + if (argA == 2) { + displayString_3("The item makes a loud noise!", false, charId, windowId, menuId, curMenuLine); + } else { + int16 teamCharId = windowId; + if (teamCharId != 0x1B) { + if (_teamCharStatus[teamCharId]._status == 0) { + _messageToBePrinted += " The item makes a loud noise, awakening the character!"; + _teamCharStatus[teamCharId]._status = 0; + _teamCharStatus[teamCharId]._duration = 0; + } else { + _messageToBePrinted += " The item makes a loud noise, but has no effect!"; + } + } + } + + varA6 = true; + break; + case 29: { // "Healing Spray", "Healing Elixir", "Curing Potion", "Magic Potion" + int16 teamCharId; + if (argA == 2) { + displayString_3("Who will use the item?", false, charId, windowId, menuId, curMenuLine); + teamCharId = selectOtherCharFromTeam(); + } else { + teamCharId = windowId; + } + + if (teamCharId != 0x1B) { + int16 effectPoints = getRandom(_items[itemId].field17_attackTypeDefense); + _npcBuf[_teamCharId[teamCharId]]._hitPoints += effectPoints; + if (_npcBuf[_teamCharId[teamCharId]]._hitPoints > _npcBuf[_teamCharId[teamCharId]]._maxHP) + _npcBuf[_teamCharId[teamCharId]]._hitPoints = _npcBuf[_teamCharId[teamCharId]]._maxHP; + + if (effectPoints > 1) + buffer1 = Common::String::format("%s is healed %d points!", _npcBuf[_teamCharId[teamCharId]]._name, effectPoints); + else + buffer1 = Common::String::format("%s is healed 1 point!", _npcBuf[_teamCharId[teamCharId]]._name); + } + + if (argA == 2) { + displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + } else { + _messageToBePrinted += buffer1; + retVal = true; + } + + varA6 = true; + } break; + case 30: { + int16 teamCharId; + if (argA == 2) { + displayString_3("Who will use the item?", false, charId, windowId, menuId, curMenuLine); + teamCharId = selectOtherCharFromTeam(); + } else { + teamCharId = windowId; + } + + if (teamCharId != 0x1B) { + int16 effectPoints = getRandom(_items[itemId].field17_attackTypeDefense); + _npcBuf[_teamCharId[teamCharId]]._hitPoints -= effectPoints; + if (_npcBuf[_teamCharId[teamCharId]]._hitPoints < 0) + _npcBuf[_teamCharId[teamCharId]]._hitPoints = 0; + + if (effectPoints > 1) + buffer1 = Common::String::format("%s is harmed for %d points!", _npcBuf[_teamCharId[teamCharId]]._name, effectPoints); + else + buffer1 = Common::String::format("%s is harmed for 1 point!", _npcBuf[_teamCharId[teamCharId]]._name); + } + + if (argA == 2) { + displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + } else { + _messageToBePrinted += buffer1; + retVal = true; + } + + varA6 = true; + + } break; + case 3: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 13: + case 20: + case 21: + case 22: + default: + break; + } + + if (varA6) { + if ((_npcBuf[charId]._inventory[objectId]._stat1 & 0x7F) != 0x7F) { + int8 varA1 = (_npcBuf[charId]._inventory[objectId]._stat1 & 0x7F) - 1; + if (varA1 <= 0) { + buffer1 = " * The item breaks!"; + if (argA == 2) { + getLastCharAfterAnimCount(_guessAnimationAmount); + displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + } else { + _messageToBePrinted += buffer1; + } + setCharacterObjectToBroken(charId, objectId); + } else { + _npcBuf[charId]._inventory[objectId]._stat1 &= 0x80; + _npcBuf[charId]._inventory[objectId]._stat1 |= 0xA1; + } + } + + if (argA == 2) { + getLastCharAfterAnimCount(_guessAnimationAmount); + sub18E80(charId, windowId, menuId, curMenuLine); + } + } + + return retVal; +} + } // End of namespace Efh diff --git a/engines/efh/savegames.cpp b/engines/efh/savegames.cpp index 55eaf2198aa3..1c7b3bd556d4 100644 --- a/engines/efh/savegames.cpp +++ b/engines/efh/savegames.cpp @@ -219,6 +219,8 @@ void EfhEngine::synchronize(Common::Serializer &s) { s.syncAsByte(_npcBuf[i].field_84); s.syncAsByte(_npcBuf[i].field_85); } + + s.syncAsByte(_saveAuthorized); } } // End of namespace Efh From f0044571570f8c77885f52cbdcb49e588995efb5 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sat, 24 Dec 2022 18:55:00 +0100 Subject: [PATCH 196/412] EFH: turn _unk2C8AA into a int16, lot of renaming related to monster moves --- engines/efh/efh.cpp | 140 ++++++++++++++++++-------------------- engines/efh/efh.h | 12 ++-- engines/efh/fight.cpp | 10 +-- engines/efh/menu.cpp | 2 +- engines/efh/savegames.cpp | 2 +- engines/efh/script.cpp | 4 +- 6 files changed, 80 insertions(+), 90 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 783376510cfd..bff05a2791f8 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -256,13 +256,13 @@ EfhEngine::EfhEngine(OSystem *syst, const ADGameDescription *gd) : Engine(syst), _fullPlaceId = 0xFF; _guessAnimationAmount = 9; _largeMapFlag = 0xFFFF; + _unk2C8AA = 0; _teamCharId[0] = 0; _teamCharId[1] = _teamCharId[2] = -1; for (int i = 0; i < 3; ++i) { _teamCharStatus[i]._status = 0; _teamCharStatus[i]._duration = 0; - _unkArray2C8AA[i] = 0; _teamPctVisible[i] = 0; _word32482[i] = 0; _teamNextAttack[i] = -1; @@ -275,7 +275,6 @@ EfhEngine::EfhEngine(OSystem *syst, const ADGameDescription *gd) : Engine(syst), _stru32686[i].init(); } - _unkArray2C8AA[2] = 1; _teamSize = 1; _word2C872 = 0; _imageSetSubFilesIdx = 144; @@ -538,7 +537,7 @@ Common::Error EfhEngine::run() { } if (!_shouldQuit) { - sub174A0(); + handleMapMonsterMoves(); } if (_redrawNeededFl && !_shouldQuit) { @@ -556,8 +555,8 @@ Common::Error EfhEngine::run() { } } - if (--_unkArray2C8AA[0] < 0 && !_shouldQuit) - _unkArray2C8AA[0] = 0; + if (_unk2C8AA > 0) + --_unk2C8AA; if (isTPK()) { if (handleDeathMenu()) @@ -806,7 +805,7 @@ void EfhEngine::loadMapArrays(int idx) { _mapMonsters[i]._itemId_Weapon = mapMonstersPtr[29 * i + 5]; _mapMonsters[i]._field_6 = mapMonstersPtr[29 * i + 6]; _mapMonsters[i]._monsterRef = mapMonstersPtr[29 * i + 7]; - _mapMonsters[i]._field_8 = mapMonstersPtr[29 * i + 8]; + _mapMonsters[i]._moveInfo = mapMonstersPtr[29 * i + 8]; _mapMonsters[i]._field9_textId = mapMonstersPtr[29 * i + 9]; _mapMonsters[i]._groupSize = mapMonstersPtr[29 * i + 10]; for (int j = 0; j < 9; ++j) @@ -1593,7 +1592,7 @@ void EfhEngine::resetGame() { _oldMapPosX = _mapPosX = 31; _oldMapPosY = _mapPosY = 31; _unkRelatedToAnimImageSetId = 0; - _unkArray2C8AA[0] = 0; + _unk2C8AA = 0; } void EfhEngine::computeMapAnimation() { @@ -1807,8 +1806,8 @@ bool EfhEngine::moveMonsterGroupOther(int16 monsterId, int16 direction) { return retVal; } -bool EfhEngine::moveMonsterGroup(int16 monsterId) { - debugC(2, kDebugEngine, "moveMonsterGroup %d", monsterId); +bool EfhEngine::moveMonsterGroupRandom(int16 monsterId) { + debugC(2, kDebugEngine, "moveMonsterGroupRandom %d", monsterId); int16 rand100 = getRandom(100); @@ -1846,20 +1845,17 @@ bool EfhEngine::checkWeaponRange(int16 monsterId, int16 weaponId) { return true; } -bool EfhEngine::unkFct_checkMonsterField8(int16 id, bool teamFlag) { - debugC(6, kDebugEngine, "unkFct_checkMonsterField8 %d %s", id, teamFlag ? "True" : "False"); +bool EfhEngine::checkMonsterMovementType(int16 id, bool teamFlag) { + debugC(6, kDebugEngine, "checkMonsterMovementType %d %s", id, teamFlag ? "True" : "False"); int16 monsterId = id; if (teamFlag) monsterId = _teamMonsterIdArray[id]; - if ((_mapMonsters[monsterId]._field_8 & 0xF) >= 8) + if ((_mapMonsters[monsterId]._moveInfo & 0xF) >= 8) return true; - if (_unkArray2C8AA[0] == 0) - return false; - - if ((_mapMonsters[monsterId]._field_8 & 0x80) != 0) + if (_unk2C8AA != 0 && (_mapMonsters[monsterId]._moveInfo & 0x80) != 0) return true; return false; @@ -1872,7 +1868,7 @@ bool EfhEngine::checkTeamWeaponRange(int16 monsterId) { return true; for (uint counter = 0; counter < 5; ++counter) { - if (_teamMonsterIdArray[counter] == monsterId && unkFct_checkMonsterField8(monsterId, false) && checkWeaponRange(monsterId, _mapMonsters[monsterId]._itemId_Weapon)) + if (_teamMonsterIdArray[counter] == monsterId && checkMonsterMovementType(monsterId, false) && checkWeaponRange(monsterId, _mapMonsters[monsterId]._itemId_Weapon)) return false; } @@ -1897,14 +1893,11 @@ bool EfhEngine::checkMonsterWeaponRange(int16 monsterId) { return checkWeaponRange(monsterId, _mapMonsters[monsterId]._itemId_Weapon); } -void EfhEngine::sub174A0() { - debug("sub174A0"); - - static int16 sub174A0_monsterPosX = -1; - static int16 sub174A0_monsterPosY = -1; +void EfhEngine::handleMapMonsterMoves() { + debug("handleMapMonsterMoves"); _redrawNeededFl = true; - int16 unkMonsterId = -1; + int16 attackMonsterId = -1; int16 mapSize = _largeMapFlag ? 63 : 23; int16 minDisplayedMapX = CLIP(_mapPosX - 10, 0, mapSize); int16 minDisplayedMapY = CLIP(_mapPosY - 9, 0, mapSize); @@ -1921,82 +1914,79 @@ void EfhEngine::sub174A0() { if (!checkIfMonsterOnSameLargeMapPlace(monsterId)) continue; - int16 var4 = _mapMonsters[monsterId]._posX; - int16 var2 = _mapMonsters[monsterId]._posY; + int16 previousPosX = _mapMonsters[monsterId]._posX; + int16 previousPosY = _mapMonsters[monsterId]._posY; - if (var4 < minDisplayedMapX || var4 > maxDisplayedMapX || var2 < minDisplayedMapY || var2 > maxDisplayedMapY) + if (previousPosX < minDisplayedMapX || previousPosX > maxDisplayedMapX || previousPosY < minDisplayedMapY || previousPosY > maxDisplayedMapY) continue; bool monsterMovedFl = false; int16 lastRangeCheck = 0; - sub174A0_monsterPosX = _mapMonsters[monsterId]._posX; - sub174A0_monsterPosY = _mapMonsters[monsterId]._posY; - int8 var1C = _mapMonsters[monsterId]._field_8 & 0xF; + int8 monsterMoveType = _mapMonsters[monsterId]._moveInfo & 0xF; // 0000 1111 - if (_unkArray2C8AA[0] != 0 && (_mapMonsters[monsterId]._field_8 & 0x80)) - var1C = 9; + if (_unk2C8AA != 0 && (_mapMonsters[monsterId]._moveInfo & 0x80)) // 1000 0000 + monsterMoveType = 9; - int16 var1E = _mapMonsters[monsterId]._field_8 & 0x70; - var1E >>= 4; + int16 randomModPct = _mapMonsters[monsterId]._moveInfo & 0x70; // 0111 0000 + randomModPct >>= 4; // Max 7 (0111) - int16 var16 = var1E; + int16 retryCounter = randomModPct; do { - switch (var1C - 1) { + switch (monsterMoveType - 1) { case 0: - if (getRandom(100) >= 0xE - var1E) + if (getRandom(100) >= 14 - randomModPct) monsterMovedFl = moveMonsterTowardsTeam(monsterId); else - monsterMovedFl = moveMonsterGroup(monsterId); + monsterMovedFl = moveMonsterGroupRandom(monsterId); break; case 1: - if (getRandom(100) >= 0xE - var1E) + if (getRandom(100) >= 14 - randomModPct) monsterMovedFl = moveMonsterAwayFromTeam(monsterId); else - monsterMovedFl = moveMonsterGroup(monsterId); + monsterMovedFl = moveMonsterGroupRandom(monsterId); break; case 2: monsterMovedFl = moveMonsterGroupOther(monsterId, getRandom(8)); break; case 3: - monsterMovedFl = moveMonsterGroup(monsterId); + monsterMovedFl = moveMonsterGroupRandom(monsterId); break; case 4: - if (getRandom(100) > 0x32 - var1E) + if (getRandom(100) > 50 - randomModPct) monsterMovedFl = moveMonsterTowardsTeam(monsterId); else - monsterMovedFl = moveMonsterGroup(monsterId); + monsterMovedFl = moveMonsterGroupRandom(monsterId); break; case 5: - if (getRandom(100) > 0x32 - var1E) + if (getRandom(100) > 50 - randomModPct) monsterMovedFl = moveMonsterAwayFromTeam(monsterId); else - monsterMovedFl = moveMonsterGroup(monsterId); + monsterMovedFl = moveMonsterGroupRandom(monsterId); break; case 6: - if (getRandom(100) >= 0x32 - var1E) - monsterMovedFl = moveMonsterGroup(monsterId); + if (getRandom(100) >= 50 - randomModPct) + monsterMovedFl = moveMonsterGroupRandom(monsterId); break; case 7: - // var14 is not a typo. lastRangeCheck = checkMonsterWeaponRange(monsterId); break; case 8: lastRangeCheck = checkMonsterWeaponRange(monsterId); if (lastRangeCheck == 0) { - if (getRandom(100) >= 0xE - var1E) + if (getRandom(100) >= 14 - randomModPct) monsterMovedFl = moveMonsterTowardsTeam(monsterId); else - monsterMovedFl = moveMonsterGroup(monsterId); + monsterMovedFl = moveMonsterGroupRandom(monsterId); } break; case 9: lastRangeCheck = checkMonsterWeaponRange(monsterId); if (lastRangeCheck == 0) { - if (getRandom(100) >= 0xE - var1E) + if (getRandom(100) >= 14 - randomModPct) monsterMovedFl = moveMonsterAwayFromTeam(monsterId); else - monsterMovedFl = moveMonsterGroup(monsterId); + monsterMovedFl = moveMonsterGroupRandom(monsterId); } break; case 10: @@ -2008,31 +1998,31 @@ void EfhEngine::sub174A0() { case 11: lastRangeCheck = checkMonsterWeaponRange(monsterId); if (lastRangeCheck == 0) { - monsterMovedFl = moveMonsterGroup(monsterId); + monsterMovedFl = moveMonsterGroupRandom(monsterId); } break; case 12: lastRangeCheck = checkMonsterWeaponRange(monsterId); if (lastRangeCheck == 0) { - if (getRandom(100) >= 0x32 - var1E) + if (getRandom(100) >= 50 - randomModPct) monsterMovedFl = moveMonsterTowardsTeam(monsterId); else - monsterMovedFl = moveMonsterGroup(monsterId); + monsterMovedFl = moveMonsterGroupRandom(monsterId); } break; case 13: lastRangeCheck = checkMonsterWeaponRange(monsterId); if (lastRangeCheck == 0) { - if (getRandom(100) >= 0x32 - var1E) + if (getRandom(100) >= 50 - randomModPct) monsterMovedFl = moveMonsterAwayFromTeam(monsterId); else - monsterMovedFl = moveMonsterGroup(monsterId); + monsterMovedFl = moveMonsterGroupRandom(monsterId); } break; case 14: lastRangeCheck = checkMonsterWeaponRange(monsterId); - if (lastRangeCheck == 0 && getRandom(100) >= 0x32 - var1E) - monsterMovedFl = moveMonsterGroup(monsterId); + if (lastRangeCheck == 0 && getRandom(100) >= 50 - randomModPct) + monsterMovedFl = moveMonsterGroupRandom(monsterId); break; default: break; @@ -2043,35 +2033,35 @@ void EfhEngine::sub174A0() { if (lastRangeCheck == 0) { monsterMovedFl = true; } else { - unkMonsterId = monsterId; + attackMonsterId = monsterId; monsterMovedFl = true; } } else { int8 var18 = sub16B08(monsterId); if (var18 == 0) { - _mapMonsters[monsterId]._posX = sub174A0_monsterPosX; - _mapMonsters[monsterId]._posY = sub174A0_monsterPosY; + _mapMonsters[monsterId]._posX = previousPosX; + _mapMonsters[monsterId]._posY = previousPosY; monsterMovedFl = false; - --var16; + --retryCounter; } else if (var18 == 2) { - _mapMonsters[monsterId]._posX = sub174A0_monsterPosX; - _mapMonsters[monsterId]._posY = sub174A0_monsterPosY; + _mapMonsters[monsterId]._posX = previousPosX; + _mapMonsters[monsterId]._posY = previousPosY; } } - if (!monsterMovedFl && var16 == 1 && var1E > 1) { + if (!monsterMovedFl && retryCounter == 1 && randomModPct > 1) { monsterMovedFl = moveMonsterGroupOther(monsterId, getRandom(8)); continue; } break; } - } while (!monsterMovedFl && var16 > 0); + } while (!monsterMovedFl && retryCounter > 0); } - if (unkMonsterId != -1) - handleFight(unkMonsterId); + if (attackMonsterId != -1) + handleFight(attackMonsterId); } bool EfhEngine::checkPictureRefAvailability(int16 monsterId) { @@ -2723,7 +2713,7 @@ int16 EfhEngine::getTeamMonsterAnimId() { if (monsterId == -1) continue; - if (!unkFct_checkMonsterField8(monsterId, false)) + if (!checkMonsterMovementType(monsterId, false)) continue; retVal = kEncounters[_mapMonsters[monsterId]._monsterRef]._animId; @@ -2834,8 +2824,8 @@ bool EfhEngine::hasObjectEquipped(int16 charId, int16 objectId) { } -void EfhEngine::setMapMonsterField8(int16 id, uint8 mask, bool groupFl) { - debugC(2, kDebugEngine, "setMapMonsterField8 %d 0x%X %s", id, mask, groupFl ? "True" : "False"); +void EfhEngine::setMapMonsterField8(int16 id, uint8 movementType, bool groupFl) { + debugC(2, kDebugEngine, "setMapMonsterField8 %d 0x%X %s", id, movementType, groupFl ? "True" : "False"); int16 monsterId; if (groupFl) { // groupFl is always True @@ -2844,9 +2834,9 @@ void EfhEngine::setMapMonsterField8(int16 id, uint8 mask, bool groupFl) { monsterId = id; } - mask &= 0x0F; - _mapMonsters[monsterId]._field_8 &= 0xF0; - _mapMonsters[monsterId]._field_8 |= mask; + movementType &= 0x0F; + _mapMonsters[monsterId]._moveInfo &= 0xF0; + _mapMonsters[monsterId]._moveInfo |= movementType; } bool EfhEngine::isMonsterActive(int16 groupId, int16 id) { @@ -3068,7 +3058,7 @@ void EfhEngine::loadEfhGame() { _teamSize = f.readSint16LE(); - _unkArray2C8AA[0] = f.readSint16LE(); + _unk2C8AA = f.readSint16LE(); _word2C872 = f.readSint16LE(); diff --git a/engines/efh/efh.h b/engines/efh/efh.h index b59fac80aca2..2e9e1eb26591 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -211,7 +211,7 @@ struct MapMonster { uint8 _itemId_Weapon; uint8 _field_6; uint8 _monsterRef; - uint8 _field_8; + uint8 _moveInfo; // abbb cccc a: special move flag, bbb: Pct modifier for random move, cccc movement type uint8 _field9_textId; uint8 _groupSize; int16 _pictureRef[9]; @@ -337,14 +337,14 @@ class EfhEngine : public Engine { bool moveMonsterAwayFromTeam(int16 monsterId); bool moveMonsterTowardsTeam(int16 monsterId); bool moveMonsterGroupOther(int16 monsterId, int16 direction); - bool moveMonsterGroup(int16 monsterId); + bool moveMonsterGroupRandom(int16 monsterId); int16 computeMonsterGroupDistance(int16 monsterId); bool checkWeaponRange(int16 monsterId, int16 weaponId); - bool unkFct_checkMonsterField8(int16 id, bool teamFlag); + bool checkMonsterMovementType(int16 id, bool teamFlag); bool checkTeamWeaponRange(int16 monsterId); bool checkIfMonsterOnSameLargeMapPlace(int16 monsterId); bool checkMonsterWeaponRange(int16 monsterId); - void sub174A0(); + void handleMapMonsterMoves(); bool checkPictureRefAvailability(int16 monsterId); void displayMonsterAnim(int16 monsterId); int16 countPictureRef(int16 id, bool teamMemberFl); @@ -365,7 +365,7 @@ class EfhEngine : public Engine { int16 getXPLevel(int32 xp); bool isItemCursed(int16 itemId); bool hasObjectEquipped(int16 charId, int16 objectId); - void setMapMonsterField8(int16 id, uint8 mask, bool groupFl); + void setMapMonsterField8(int16 id, uint8 movementType, bool groupFl); bool isMonsterActive(int16 groupId, int16 id); int16 sub15538(int16 mapPosX, int16 mapPosY); void setCharacterObjectToBroken(int16 charId, int16 objectId); @@ -571,7 +571,7 @@ class EfhEngine : public Engine { int16 _teamMonsterIdArray[5]; CharStatus _teamCharStatus[3]; - int16 _unkArray2C8AA[3]; + int16 _unk2C8AA; int16 _teamLastAction[3]; int16 _teamSize; int16 _word2C872; diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index 0e375cafaead..0a5946051a79 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -157,7 +157,7 @@ bool EfhEngine::handleFight(int16 monsterId) { break; } } - } else if (unkFct_checkMonsterField8(monsterGroupIdOrMonsterId, true)) { + } else if (checkMonsterMovementType(monsterGroupIdOrMonsterId, true)) { // handleFight - Loop on var86 - Start for (uint var86 = 0; var86 < 9; ++var86) { if (isMonsterActive(monsterGroupIdOrMonsterId, var86)) { @@ -367,7 +367,7 @@ bool EfhEngine::handleFight(int16 monsterId) { } } - sub174A0(); + handleMapMonsterMoves(); sub1BE9A(monsterId); } @@ -455,9 +455,9 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { for (int16 var7E = teamMemberId; var7E < var54; ++var7E) { if (isMonsterActive(groupId, var7E) && var6E) { int16 var5C; - if (unkFct_checkMonsterField8(groupId, true)) { + if (checkMonsterMovementType(groupId, true)) { setMapMonsterField8(groupId, 9, true); - _unkArray2C8AA[0] += 500; + _unk2C8AA += 500; var5C = -1; } else var5C = 0; @@ -1351,7 +1351,7 @@ void EfhEngine::sub1C4CA(bool whiteFl) { } setTextPos(228, textPosY); - if (unkFct_checkMonsterField8(counter, true)) { + if (checkMonsterMovementType(counter, true)) { _textColor = 0xE; displayStringAtTextPos("Hostile"); } else { diff --git a/engines/efh/menu.cpp b/engines/efh/menu.cpp index 5ed31e12ad83..08a9cc0218ed 100644 --- a/engines/efh/menu.cpp +++ b/engines/efh/menu.cpp @@ -992,7 +992,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me displayString_3("A serene feeling passes through the air...", false, charId, windowId, menuId, curMenuLine); } else { _messageToBePrinted += " The combat pauses...as there is a moment of forgiveness..."; - _unkArray2C8AA[0] = 0; + _unk2C8AA = 0; } varA6 = true; diff --git a/engines/efh/savegames.cpp b/engines/efh/savegames.cpp index 1c7b3bd556d4..776a96b4ff80 100644 --- a/engines/efh/savegames.cpp +++ b/engines/efh/savegames.cpp @@ -138,7 +138,7 @@ void EfhEngine::synchronize(Common::Serializer &s) { } s.syncAsSint16LE(_teamSize); - s.syncAsSint16LE(_unkArray2C8AA[0]); + s.syncAsSint16LE(_unk2C8AA); s.syncAsSint16LE(_word2C872); s.syncAsSint16LE(_imageSetSubFilesIdx); s.syncAsSint16LE(_mapPosX); diff --git a/engines/efh/script.cpp b/engines/efh/script.cpp index be42723e2f58..81d6c5be3096 100644 --- a/engines/efh/script.cpp +++ b/engines/efh/script.cpp @@ -311,7 +311,7 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos break; case 0x11: if (flag) - _unkArray2C8AA[0] = 0; + _unk2C8AA = 0; break; case 0x12: // Guess : disable special tile { } @@ -465,7 +465,7 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos case 0x1F: buffer = script_readNumberArray(buffer, 1, scriptNumberArray); if (flag) - _unkArray2C8AA[0] = scriptNumberArray[0]; + _unk2C8AA = scriptNumberArray[0]; break; case 0x20: From 1708c03287ef5193472d456a71b60360715b5733 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sun, 25 Dec 2022 11:40:49 +0100 Subject: [PATCH 197/412] EFH: Fix endian issue, some renaming --- engines/efh/efh.cpp | 2 +- engines/efh/script.cpp | 22 +++++++++++----------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index bff05a2791f8..8a2e73054034 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -1394,7 +1394,7 @@ void EfhEngine::sub2455E(int16 arg0, int16 arg2, int16 arg4) { for (int16 var4 = varC; var4 <= var8; ++var4) { for (int16 var2 = varA; var2 <= var6; ++var2) { - _techDataArr[_techId][var2 + var4 * 64] = varD; + WRITE_LE_INT16(&_techDataArr[_techId][var2 + var4 * 64], varD); } } } diff --git a/engines/efh/script.cpp b/engines/efh/script.cpp index 81d6c5be3096..3cc258f5b867 100644 --- a/engines/efh/script.cpp +++ b/engines/efh/script.cpp @@ -59,7 +59,7 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos bool doneFlag = false; int16 var_F2 = -1; - int16 var_F0 = 0xFF; + int16 retVal = 0xFF; int16 var_EE = 0xFF; uint16 curLineNb = 0; int16 numbLines = (1 + maxY - posY) / 9; @@ -288,9 +288,9 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos } if (found) - var_F0 = scriptNumberArray[1]; + retVal = scriptNumberArray[1]; else - var_F0 = scriptNumberArray[2]; + retVal = scriptNumberArray[2]; } break; case 0x0F: @@ -298,15 +298,15 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos if (flag) { int16 var110 = scriptNumberArray[0]; if (isCharacterATeamMember(var110)) - var_F0 = scriptNumberArray[1]; + retVal = scriptNumberArray[1]; else - var_F0 = scriptNumberArray[2]; + retVal = scriptNumberArray[2]; } break; case 0x10: buffer = script_readNumberArray(buffer, 1, scriptNumberArray); if (flag) - var_F0 = scriptNumberArray[0]; + retVal = scriptNumberArray[0]; break; case 0x11: @@ -328,7 +328,7 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos loadPlacesFile(scriptNumberArray[0], false); sub15A28(scriptNumberArray[1], scriptNumberArray[2]); sub2455E(scriptNumberArray[0], scriptNumberArray[1], scriptNumberArray[2]); - var_F0 = -1; + retVal = -1; } break; case 0x14: @@ -338,7 +338,7 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos int16 var110 = scriptNumberArray[0]; if (!isCharacterATeamMember(var110)) var_EE = var110; - var_F0 = -1; + retVal = -1; } break; case 0x15: @@ -457,9 +457,9 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos buffer = script_readNumberArray(buffer, 3, scriptNumberArray); if (flag) { if (_history[scriptNumberArray[0]] == 0) - var_F0 = scriptNumberArray[2]; + retVal = scriptNumberArray[2]; else - var_F0 = scriptNumberArray[1]; + retVal = scriptNumberArray[1]; } break; case 0x1F: @@ -490,7 +490,7 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos refreshTeamSize(); } - return var_F0; + return retVal; } } // End of namespace Efh From 6aea8334bc04e261a0b61790e33b9a1aa266c070 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sun, 25 Dec 2022 22:59:22 +0100 Subject: [PATCH 198/412] EFH: Verify some more functions, some renaming --- engines/efh/efh.cpp | 67 ++++++++++++++++++++++--------------------- engines/efh/efh.h | 14 ++++----- engines/efh/fight.cpp | 10 +++---- 3 files changed, 47 insertions(+), 44 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 8a2e73054034..9b131dc0dd0c 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -163,8 +163,8 @@ void Stru32686::init() { } } -void Stru3244C::init() { - _field0 = _field2 = 0; +void InitiativeStruct::init() { + _id = _initiative = 0; } void TileFactStruct::init() { @@ -307,7 +307,7 @@ EfhEngine::EfhEngine(OSystem *syst, const ADGameDescription *gd) : Engine(syst), _messageToBePrinted = ""; for (int i = 0; i < 8; ++i) - _stru3244C[i].init(); + _initiatives[i].init(); memset(_bufferCharBM, 0, ARRAYSIZE(_bufferCharBM)); for (int i = 0; i < 3; ++i) @@ -749,7 +749,7 @@ void EfhEngine::initEngine() { } void EfhEngine::initMapMonsters() { - debug("initMapMonsters"); + debugC(3, kDebugEngine, "initMapMonsters"); for (uint monsterId = 0; monsterId < 64; ++monsterId) { if (_mapMonsters[monsterId]._guess_fullPlaceId == 0xFF) @@ -760,8 +760,11 @@ void EfhEngine::initMapMonsters() { uint8 groupSize = _mapMonsters[monsterId]._groupSize; if (groupSize == 0) - groupSize = getRandom(10); + groupSize = getRandom(10) - 1; + if (groupSize == 0) + continue; + for (uint counter = 0; counter < groupSize; ++counter) { uint rand100 = getRandom(100); uint16 pictureRef = kEncounters[_mapMonsters[monsterId]._monsterRef]._pictureRef; @@ -780,7 +783,7 @@ void EfhEngine::initMapMonsters() { } void EfhEngine::loadMapArrays(int idx) { - debug("loadMapArrays %d", idx); + debugC(6, kDebugEngine, "loadMapArrays %d", idx); uint8 *_mapUnknownPtr = &_mapArr[idx][2]; @@ -798,7 +801,7 @@ void EfhEngine::loadMapArrays(int idx) { for (int i = 0; i < 64; ++i) { _mapMonsters[i]._possessivePronounSHL6 = mapMonstersPtr[29 * i]; - _mapMonsters[i]._field_1 = mapMonstersPtr[29 * i + 1]; + _mapMonsters[i]._npcId = mapMonstersPtr[29 * i + 1]; _mapMonsters[i]._guess_fullPlaceId = mapMonstersPtr[29 * i + 2]; _mapMonsters[i]._posX = mapMonstersPtr[29 * i + 3]; _mapMonsters[i]._posY = mapMonstersPtr[29 * i + 4]; @@ -983,7 +986,7 @@ void EfhEngine::drawMap(bool largeMapFl, int16 mapPosX, int16 mapPosY, int16 map int16 var6 = 148 + kEncounters[_mapMonsters[var16]._monsterRef]._animId; int16 var1 = _mapMonsters[var16]._possessivePronounSHL6 & 0x3F; - if (var1 == 0x3F && isCharacterATeamMember(_mapMonsters[var16]._field_1)) + if (var1 == 0x3F && isCharacterATeamMember(_mapMonsters[var16]._npcId)) continue; int16 drawPosX = 128 + (posX - minX) * 16; @@ -1685,7 +1688,7 @@ int8 EfhEngine::sub16B08(int16 monsterId) { return 0; } - return sub15581(_mapMonsters[monsterId]._posX, _mapMonsters[monsterId]._posY, 0); + return sub15581(_mapMonsters[monsterId]._posX, _mapMonsters[monsterId]._posY, false); } bool EfhEngine::moveMonsterAwayFromTeam(int16 monsterId) { @@ -2139,10 +2142,10 @@ bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { return true; } - if (isCharacterATeamMember(_mapMonsters[monsterId]._field_1)) + if (isCharacterATeamMember(_mapMonsters[monsterId]._npcId)) return false; - int16 var58 = _mapMonsters[monsterId]._field_1; + int16 var58 = _mapMonsters[monsterId]._npcId; switch (_npcBuf[var58].field_10 - 0xEE) { case 0: if (arg2 == 4 && _npcBuf[var58].field_11 == itemId) { @@ -2487,15 +2490,15 @@ bool EfhEngine::sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemI return false; } -int8 EfhEngine::sub15581(int16 mapPosX, int16 mapPosY, int16 arg4) { - debug("sub15581 %d-%d %d", mapPosX, mapPosY, arg4); +int8 EfhEngine::sub15581(int16 mapPosX, int16 mapPosY, bool arg4) { + debug("sub15581 %d-%d %s", mapPosX, mapPosY, arg4 ? "true" : "false"); int16 curTileInfo = getMapTileInfo(mapPosX, mapPosY); int16 imageSetId = _currentTileBankImageSetId[curTileInfo / 72]; imageSetId *= 72; imageSetId += curTileInfo % 72; - if (arg4 == 1) { + if (arg4) { sub22293(mapPosX, mapPosY, -1, 0x7FFF, 0, imageSetId); } @@ -2504,7 +2507,7 @@ int8 EfhEngine::sub15581(int16 mapPosX, int16 mapPosY, int16 arg4) { return -1; } if (_tileFact[imageSetId]._field1 != 0xFF && !_dbgForceMonsterBlock) { - if ((arg4 == 1) || (arg4 == 0 && imageSetId != 128 && imageSetId != 121)) { + if ((arg4) || (!arg4 && imageSetId != 128 && imageSetId != 121)) { if (_largeMapFlag) { _mapGameMap[mapPosX][mapPosY] = _tileFact[imageSetId]._field1; } else { @@ -2521,36 +2524,36 @@ int8 EfhEngine::sub15581(int16 mapPosX, int16 mapPosY, int16 arg4) { return _tileFact[imageSetId]._field0; } -void EfhEngine::sub1CDFA() { - debug("sub1CDFA"); // Initiatives +void EfhEngine::computeInitiatives() { + debugC(6, kDebugEngine, "computeInitiatives"); for (int counter = 0; counter < 3; ++counter) { if (_teamCharId[counter] != -1 && counter < _teamSize) { - _stru3244C[counter]._field0 = counter + 1000; - _stru3244C[counter]._field2 = _npcBuf[_teamCharId[counter]]._infoScore[3]; + _initiatives[counter]._id = counter + 1000; + _initiatives[counter]._initiative = _npcBuf[_teamCharId[counter]]._infoScore[3]; } else { - _stru3244C[counter]._field0 = -1; - _stru3244C[counter]._field2 = -1; + _initiatives[counter]._id = -1; + _initiatives[counter]._initiative = -1; } } for (int counter = 0; counter < 5; ++counter) { if (_teamMonsterIdArray[counter] == -1) { - _stru3244C[counter + 3]._field0 = -1; - _stru3244C[counter + 3]._field2 = -1; + _initiatives[counter + 3]._id = -1; + _initiatives[counter + 3]._initiative = -1; } else { - _stru3244C[counter + 3]._field0 = counter; - _stru3244C[counter + 3]._field2 = _mapMonsters[_teamMonsterIdArray[counter]]._field_1 + getRandom(20); + _initiatives[counter + 3]._id = counter; + _initiatives[counter + 3]._initiative = _mapMonsters[_teamMonsterIdArray[counter]]._npcId + getRandom(20); } } for (uint counter = 0; counter < 8; ++counter) { for (uint counter2 = 0; counter2 < 8; ++counter2) { - if (_stru3244C[counter]._field2 >= _stru3244C[counter2]._field2) + if (_initiatives[counter]._initiative >= _initiatives[counter2]._initiative) continue; - SWAP(_stru3244C[counter]._field0, _stru3244C[counter2]._field0); - SWAP(_stru3244C[counter]._field2, _stru3244C[counter2]._field2); + SWAP(_initiatives[counter]._id, _initiatives[counter2]._id); + SWAP(_initiatives[counter]._initiative, _initiatives[counter2]._initiative); } } } @@ -2652,7 +2655,7 @@ void EfhEngine::sub1BE9A(int16 monsterId) { if (_mapMonsters[counter1]._guess_fullPlaceId == 0xFF) continue; - if (((_mapMonsters[counter1]._possessivePronounSHL6 & 0x3F) == 0x3F && !isCharacterATeamMember(_mapMonsters[counter1]._field_1)) || (_mapMonsters[counter1]._possessivePronounSHL6 & 0x3F) <= 0x3D) { + if (((_mapMonsters[counter1]._possessivePronounSHL6 & 0x3F) == 0x3F && !isCharacterATeamMember(_mapMonsters[counter1]._npcId)) || (_mapMonsters[counter1]._possessivePronounSHL6 & 0x3F) <= 0x3D) { if (checkIfMonsterOnSameLargeMapPlace(counter1)) { bool var6 = false; for (uint counter2 = 0; counter2 < 9; ++counter2) { @@ -2892,7 +2895,7 @@ bool EfhEngine::checkMonsterCollision() { continue; if ((_mapMonsters[monsterId]._possessivePronounSHL6 & 0x3F) > 0x3D - && !(((_mapMonsters[monsterId]._possessivePronounSHL6 & 0x3F) == 0x3F) && !isCharacterATeamMember(_mapMonsters[monsterId]._field_1))) + && !(((_mapMonsters[monsterId]._possessivePronounSHL6 & 0x3F) == 0x3F) && !isCharacterATeamMember(_mapMonsters[monsterId]._npcId))) continue; if (_mapMonsters[monsterId]._posX != _mapPosX || _mapMonsters[monsterId]._posY != _mapPosY) @@ -2926,7 +2929,7 @@ bool EfhEngine::checkMonsterCollision() { dest = "(NOT DEFINED)"; } else if (var1 == 0x3F) { // Useless check, it's the last possible value // Special character name - dest = _npcBuf[_mapMonsters[monsterId]._field_1]._name; + dest = _npcBuf[_mapMonsters[monsterId]._npcId]._name; buffer = Common::String("with ") + dest; } @@ -2988,7 +2991,7 @@ bool EfhEngine::checkMonsterCollision() { return true; } - int8 check = sub15581(_mapPosX, _mapPosY, 1); + int8 check = sub15581(_mapPosX, _mapPosY, true); if (check == 0 || check == 2) return false; diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 2e9e1eb26591..cb927cc8220e 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -204,7 +204,7 @@ struct CharStatus { struct MapMonster { uint8 _possessivePronounSHL6; - uint8 _field_1; + uint8 _npcId; uint8 _guess_fullPlaceId; // unsigned? Magic values are 0xFF and 0xFE uint8 _posX; uint8 _posY; @@ -224,9 +224,9 @@ struct Stru32686 { void init(); }; -struct Stru3244C { - int16 _field0; - int16 _field2; +struct InitiativeStruct { + int16 _id; + int16 _initiative; void init(); }; @@ -353,8 +353,8 @@ class EfhEngine : public Engine { void sub221D2(int16 monsterId); void displayImp1Text(int16 textId); bool sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemId, int16 arg8, int16 imageSetId); - int8 sub15581(int16 mapPosX, int16 mapPosY, int16 arg4); - void sub1CDFA(); + int8 sub15581(int16 mapPosX, int16 mapPosY, bool arg4); + void computeInitiatives(); void redrawScreenForced(); int16 selectMonsterGroup(); void sub1CAB6(int16 charId); @@ -605,7 +605,7 @@ class EfhEngine : public Engine { int16 _menuStatItemArr[15]; Stru32686 _stru32686[5]; - Stru3244C _stru3244C[8]; + InitiativeStruct _initiatives[8]; }; diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index 0a5946051a79..7e391f61460d 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -40,7 +40,7 @@ void EfhEngine::sub1BCA7(int16 monsterTeamId) { if (_mapMonsters[monsterId]._guess_fullPlaceId == 0xFF) continue; - if (((_mapMonsters[monsterId]._possessivePronounSHL6 & 0x3F) != 0x3F || isCharacterATeamMember(_mapMonsters[monsterId]._field_1)) && (_mapMonsters[monsterId]._possessivePronounSHL6 & 0x3F) > 0x3D) + if (((_mapMonsters[monsterId]._possessivePronounSHL6 & 0x3F) != 0x3F || isCharacterATeamMember(_mapMonsters[monsterId]._npcId)) && (_mapMonsters[monsterId]._possessivePronounSHL6 & 0x3F) > 0x3D) continue; if (!checkIfMonsterOnSameLargeMapPlace(monsterId)) @@ -128,11 +128,11 @@ bool EfhEngine::handleFight(int16 monsterId) { mainLoopCond = true; } - sub1CDFA(); + computeInitiatives(); sub1C219("", 2, 1, false); for (uint counter = 0; counter < 8; ++counter) { - int16 monsterGroupIdOrMonsterId = _stru3244C[counter]._field0; + int16 monsterGroupIdOrMonsterId = _initiatives[counter]._id; if (monsterGroupIdOrMonsterId == -1) continue; if (monsterGroupIdOrMonsterId > 999) { // Team Member @@ -195,7 +195,7 @@ bool EfhEngine::handleFight(int16 monsterId) { int16 hitPoints = 0; int16 originalDamage = 0; int16 damagePointsAbsorbed = 0; - int16 var64 = _mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._field_1 * _items[unk_monsterField5_itemId]._attacks; + int16 var64 = _mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._npcId * _items[unk_monsterField5_itemId]._attacks; for (int var84 = 0; var84 < var64; ++var84) { // handleFight - Loop var84 on var64 (objectId) - Start if (getRandom(100) > _word32482[var7E]) @@ -1346,7 +1346,7 @@ void EfhEngine::sub1C4CA(bool whiteFl) { } else if (var1 == 0x3E) { displayStringAtTextPos("(NOT DEFINED)"); } else if (var1 == 0x3F) { - Common::String stringToDisplay = _npcBuf[_mapMonsters[_teamMonsterIdArray[counter]]._field_1]._name; + Common::String stringToDisplay = _npcBuf[_mapMonsters[_teamMonsterIdArray[counter]]._npcId]._name; displayStringAtTextPos(stringToDisplay); } From 968499e2dc670cb2f8d4a137242fb7485a91f8db Mon Sep 17 00:00:00 2001 From: Strangerke Date: Mon, 26 Dec 2022 19:11:04 +0100 Subject: [PATCH 199/412] EFH: Renaming, validate some more functions --- engines/efh/efh.cpp | 186 +++++++++++++++++++---------------------- engines/efh/efh.h | 10 +-- engines/efh/files.cpp | 2 +- engines/efh/menu.cpp | 16 ++-- engines/efh/script.cpp | 2 +- 5 files changed, 100 insertions(+), 116 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 9b131dc0dd0c..af7c9f7e1fb3 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -168,7 +168,7 @@ void InitiativeStruct::init() { } void TileFactStruct::init() { - _field0 = _field1 = 0; + _field0 = _tileId = 0; } EfhEngine::EfhEngine(OSystem *syst, const ADGameDescription *gd) : Engine(syst), _gameDescription(gd) { @@ -947,11 +947,11 @@ void EfhEngine::drawMap(bool largeMapFl, int16 mapPosX, int16 mapPosY, int16 map int16 drawPosX = 128; for (int16 counterX = minX; counterX <= maxX; ++counterX) { if (largeMapFl) { - int16 idx = _mapGameMap[counterX][counterY]; - displayRawDataAtPos(_imageSetSubFilesArray[idx], drawPosX, drawPosY); + int16 curTile = _mapGameMap[counterX][counterY]; + displayRawDataAtPos(_imageSetSubFilesArray[curTile], drawPosX, drawPosY); } else { - int16 idx = _curPlace[counterX][counterY]; - displayRawDataAtPos(_imageSetSubFilesArray[idx], drawPosX, drawPosY); + int16 curTile = _curPlace[counterX][counterY]; + displayRawDataAtPos(_imageSetSubFilesArray[curTile], drawPosX, drawPosY); } drawPosX += 16; } @@ -1345,32 +1345,32 @@ void EfhEngine::displayMiddleLeftTempText(uint8 *impArray, bool flag) { } } -void EfhEngine::sub15A28(int16 arg0, int16 arg2) { - debug("sub15A28 %d %d", arg0, arg2); +void EfhEngine::transitionMap(int16 centerX, int16 centerY) { + debug("transitionMap %d %d", centerX, centerY); _drawHeroOnMapFl = false; - int16 varE = arg0 - 11; - int16 varC = arg2 - 11; + int16 minX = centerX - 11; + int16 minY = centerY - 11; - if (varE < 0) - varE = 0; - if (varC < 0) - varC = 0; + if (minX < 0) + minX = 0; + if (minY < 0) + minY = 0; - for (uint counter = 0; counter <= 23; counter += 2) { - for (uint var8 = 0; var8 <= 23; ++var8) { - int16 var4 = counter + varE; - int16 var2 = var8 + varC; - _mapGameMap[var4][var2] = _curPlace[counter][var8]; + for (uint counterX = 0; counterX <= 23; counterX += 2) { + for (uint counterY = 0; counterY <= 23; ++counterY) { + int16 curX = counterX + minX; + int16 curY = counterY + minY; + _mapGameMap[curX][curY] = _curPlace[counterX][counterY]; } drawScreen(); } - for (uint counter = 1; counter <= 23; counter += 2) { - for (uint var8 = 0; var8 <= 23; ++var8) { - int16 var4 = counter + varE; - int16 var2 = var8 + varC; - _mapGameMap[var4][var2] = _curPlace[counter][var8]; + for (uint counterX = 1; counterX <= 23; counterX += 2) { + for (uint counterY = 0; counterY <= 23; ++counterY) { + int16 curX = counterX + minX; + int16 curY = counterY + minY; + _mapGameMap[curX][curY] = _curPlace[counterX][counterY]; } drawScreen(); } @@ -1603,43 +1603,31 @@ void EfhEngine::computeMapAnimation() { const int16 maxMapBlocks = _largeMapFlag ? 63 : 23; - int16 minMapX = _mapPosX - 5; - int16 minMapY = _mapPosY - 4; - - if (minMapX < 0) - minMapX = 0; - if (minMapY < 0) - minMapY = 0; - - int16 maxMapX = minMapX + 10; - int16 maxMapY = minMapY + 7; - - if (maxMapX > maxMapBlocks) - maxMapX = maxMapBlocks; - if (maxMapY > maxMapBlocks) - maxMapY = maxMapBlocks; + int16 minMapX = CLIP(_mapPosX - 5, 0, maxMapBlocks); + int16 minMapY = CLIP(_mapPosY - 4, 0, maxMapBlocks); + int16 maxMapX = CLIP(minMapX + 10, 0, maxMapBlocks); + int16 maxMapY = CLIP(minMapY + 7, 0, maxMapBlocks); for (int16 counterY = minMapY; counterY < maxMapY; ++counterY) { for (int16 counterX = minMapX; counterX < maxMapX; ++counterX) { + if (_currentTileBankImageSetId[0] != 0) + continue; + if (_largeMapFlag) { - if (_currentTileBankImageSetId[0] != 0) - continue; - uint8 var4 = _mapGameMap[counterX][counterY]; - if (var4 >= 1 && var4 <= 0xF) { + uint8 curTile = _mapGameMap[counterX][counterY]; + if (curTile >= 1 && curTile <= 0xF) { if (getRandom(100) < 50) _mapGameMap[counterX][counterY] += 0xC5; - } else if (var4 >= 0xC6 && var4 <= 0xD5) { + } else if (curTile >= 0xC6 && curTile <= 0xD5) { if (getRandom(100) < 50) _mapGameMap[counterX][counterY] -= 0xC5; } } else { - if (_currentTileBankImageSetId[0] != 0) - continue; - uint8 var4 = _curPlace[counterX][counterY]; - if (var4 >= 1 && var4 <= 0xF) { + uint8 curTile = _curPlace[counterX][counterY]; + if (curTile >= 1 && curTile <= 0xF) { if (getRandom(100) < 50) _curPlace[counterX][counterY] += 0xC5; - } else if (var4 >= 0xC6 && var4 <= 0xD5) { + } else if (curTile >= 0xC6 && curTile <= 0xD5) { if (getRandom(100) < 50) _curPlace[counterX][counterY] -= 0xC5; } @@ -1665,8 +1653,8 @@ void EfhEngine::handleAnimations() { computeMapAnimation(); } -int8 EfhEngine::sub16B08(int16 monsterId) { - debugC(3, kDebugEngine,"sub16B08 %d", monsterId); +int8 EfhEngine::checkMonsterMoveCollisionAndTileTexture(int16 monsterId) { + debugC(3, kDebugEngine,"checkMonsterMoveCollisionAndTileTexture %d", monsterId); int16 maxSize = _largeMapFlag ? 63 : 23; if (_mapMonsters[monsterId]._posX < 0 || _mapMonsters[monsterId]._posY < 0 || _mapMonsters[monsterId]._posX > maxSize || _mapMonsters[monsterId]._posY > maxSize) @@ -1688,7 +1676,7 @@ int8 EfhEngine::sub16B08(int16 monsterId) { return 0; } - return sub15581(_mapMonsters[monsterId]._posX, _mapMonsters[monsterId]._posY, false); + return checkTileStatus(_mapMonsters[monsterId]._posX, _mapMonsters[monsterId]._posY, false); } bool EfhEngine::moveMonsterAwayFromTeam(int16 monsterId) { @@ -1897,7 +1885,7 @@ bool EfhEngine::checkMonsterWeaponRange(int16 monsterId) { } void EfhEngine::handleMapMonsterMoves() { - debug("handleMapMonsterMoves"); + debugC(3, kDebugEngine, "handleMapMonsterMoves"); _redrawNeededFl = true; int16 attackMonsterId = -1; @@ -2040,14 +2028,14 @@ void EfhEngine::handleMapMonsterMoves() { monsterMovedFl = true; } } else { - int8 var18 = sub16B08(monsterId); + int8 checkMoveFl = checkMonsterMoveCollisionAndTileTexture(monsterId); - if (var18 == 0) { + if (checkMoveFl == 0) { // Blocked _mapMonsters[monsterId]._posX = previousPosX; _mapMonsters[monsterId]._posY = previousPosY; monsterMovedFl = false; --retryCounter; - } else if (var18 == 2) { + } else if (checkMoveFl == 2) { // Wall _mapMonsters[monsterId]._posX = previousPosX; _mapMonsters[monsterId]._posY = previousPosY; } @@ -2145,36 +2133,36 @@ bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { if (isCharacterATeamMember(_mapMonsters[monsterId]._npcId)) return false; - int16 var58 = _mapMonsters[monsterId]._npcId; - switch (_npcBuf[var58].field_10 - 0xEE) { + int16 npcId = _mapMonsters[monsterId]._npcId; + switch (_npcBuf[npcId].field_10 - 0xEE) { case 0: - if (arg2 == 4 && _npcBuf[var58].field_11 == itemId) { + if (arg2 == 4 && _npcBuf[npcId].field_11 == itemId) { displayMonsterAnim(monsterId); - displayImp1Text(_npcBuf[var58].field14_textId); + displayImp1Text(_npcBuf[npcId].field14_textId); displayAnimFrames(0xFE, true); return true; } break; case 1: - if (arg2 == 2 && _npcBuf[var58].field_11 == itemId) { + if (arg2 == 2 && _npcBuf[npcId].field_11 == itemId) { displayMonsterAnim(monsterId); - displayImp1Text(_npcBuf[var58].field14_textId); + displayImp1Text(_npcBuf[npcId].field14_textId); displayAnimFrames(0xFE, true); return true; } break; case 2: - if (arg2 == 1 && _npcBuf[var58].field_11 == itemId) { + if (arg2 == 1 && _npcBuf[npcId].field_11 == itemId) { displayMonsterAnim(monsterId); - displayImp1Text(_npcBuf[var58].field14_textId); + displayImp1Text(_npcBuf[npcId].field14_textId); displayAnimFrames(0xFE, true); return true; } break; case 3: - if (_history[_npcBuf[var58].field_11] != 0) { + if (_history[_npcBuf[npcId].field_11] != 0) { displayMonsterAnim(monsterId); - displayImp1Text(_npcBuf[var58].field14_textId); + displayImp1Text(_npcBuf[npcId].field14_textId); displayAnimFrames(0xFE, true); return true; } @@ -2182,10 +2170,10 @@ bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { case 4: for (int counter = 0; counter < _teamSize; ++counter) { for (uint charId = 0; charId < 10; ++charId) { - if (_npcBuf[_teamCharId[counter]]._inventory[charId]._ref == _npcBuf[var58].field_11) { + if (_npcBuf[_teamCharId[counter]]._inventory[charId]._ref == _npcBuf[npcId].field_11) { removeObject(_teamCharId[counter], charId); displayMonsterAnim(monsterId); - displayImp1Text(_npcBuf[var58].field14_textId); + displayImp1Text(_npcBuf[npcId].field14_textId); displayAnimFrames(0xFE, true); return true; } @@ -2193,9 +2181,9 @@ bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { } break; case 5: - if (arg2 == 2 && _npcBuf[var58].field_11 == itemId) { + if (arg2 == 2 && _npcBuf[npcId].field_11 == itemId) { displayMonsterAnim(monsterId); - displayImp1Text(_npcBuf[var58].field14_textId); + displayImp1Text(_npcBuf[npcId].field14_textId); displayAnimFrames(0xFE, true); return true; } @@ -2203,9 +2191,9 @@ bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { case 6: for (int counter = 0; counter < _teamSize; ++counter) { for (uint charId = 0; charId < 10; ++charId) { - if (_npcBuf[_teamCharId[counter]]._inventory[charId]._ref == _npcBuf[var58].field_11) { + if (_npcBuf[_teamCharId[counter]]._inventory[charId]._ref == _npcBuf[npcId].field_11) { displayMonsterAnim(monsterId); - displayImp1Text(_npcBuf[var58].field14_textId); + displayImp1Text(_npcBuf[npcId].field14_textId); displayAnimFrames(0xFE, true); return true; } @@ -2214,10 +2202,10 @@ bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { break; case 7: for (int counter = 0; counter < _teamSize; ++counter) { - if (_npcBuf[var58].field_11 == _teamCharId[counter]) { + if (_npcBuf[npcId].field_11 == _teamCharId[counter]) { removeCharacterFromTeam(counter); displayMonsterAnim(monsterId); - displayImp1Text(_npcBuf[var58].field14_textId); + displayImp1Text(_npcBuf[npcId].field14_textId); displayAnimFrames(0xFE, true); return true; } @@ -2225,9 +2213,9 @@ bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { break; case 8: for (int counter = 0; counter < _teamSize; ++counter) { - if (_npcBuf[var58].field_11 == _teamCharId[counter]) { + if (_npcBuf[npcId].field_11 == _teamCharId[counter]) { displayMonsterAnim(monsterId); - _enemyNamePt2 = _npcBuf[var58]._name; + _enemyNamePt2 = _npcBuf[npcId]._name; _characterNamePt2 = _npcBuf[_teamCharId[counter]]._name; Common::String buffer = Common::String::format("%s asks that %s leave your party.", _enemyNamePt2.c_str(), _characterNamePt2.c_str()); for (uint i = 0; i < 2; ++i) { @@ -2243,7 +2231,7 @@ bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { Common::KeyCode input = mapInputCode(waitForKey()); if (input == Common::KEYCODE_y) { removeCharacterFromTeam(counter); - displayImp1Text(_npcBuf[var58].field14_textId); + displayImp1Text(_npcBuf[npcId].field14_textId); } displayAnimFrames(0xFE, true); return true; @@ -2252,9 +2240,9 @@ bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { break; case 9: for (int counter = 0; counter < _teamSize; ++counter) { - if (_npcBuf[var58].field_11 == _teamCharId[counter]) { + if (_npcBuf[npcId].field_11 == _teamCharId[counter]) { displayMonsterAnim(monsterId); - displayImp1Text(_npcBuf[var58].field14_textId); + displayImp1Text(_npcBuf[npcId].field14_textId); displayAnimFrames(0xFE, true); return true; } @@ -2262,7 +2250,7 @@ bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { break; case 16: displayMonsterAnim(monsterId); - displayImp1Text(_npcBuf[var58].field14_textId); + displayImp1Text(_npcBuf[npcId].field14_textId); displayAnimFrames(0xFE, true); return true; default: @@ -2270,11 +2258,11 @@ bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { break; } - if (_npcBuf[var58].field12_textId == 0x7FFF || arg2 != 5) + if (_npcBuf[npcId].field12_textId == 0x7FFF || arg2 != 5) return false; displayMonsterAnim(monsterId); - displayImp1Text(_npcBuf[var58].field12_textId); + displayImp1Text(_npcBuf[npcId].field12_textId); displayAnimFrames(0xFE, true); return true; } @@ -2490,38 +2478,37 @@ bool EfhEngine::sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemI return false; } -int8 EfhEngine::sub15581(int16 mapPosX, int16 mapPosY, bool arg4) { - debug("sub15581 %d-%d %s", mapPosX, mapPosY, arg4 ? "true" : "false"); +int8 EfhEngine::checkTileStatus(int16 mapPosX, int16 mapPosY, bool arg4) { + debugC(3, kDebugEngine, "checkTileStatus %d-%d %s", mapPosX, mapPosY, arg4 ? "true" : "false"); int16 curTileInfo = getMapTileInfo(mapPosX, mapPosY); - int16 imageSetId = _currentTileBankImageSetId[curTileInfo / 72]; - imageSetId *= 72; - imageSetId += curTileInfo % 72; + int16 tileFactId = _currentTileBankImageSetId[curTileInfo / 72] * 72; + tileFactId += curTileInfo % 72; if (arg4) { - sub22293(mapPosX, mapPosY, -1, 0x7FFF, 0, imageSetId); + sub22293(mapPosX, mapPosY, -1, 0x7FFF, 0, tileFactId); } if (_word2C880) { _word2C880 = false; return -1; } - if (_tileFact[imageSetId]._field1 != 0xFF && !_dbgForceMonsterBlock) { - if ((arg4) || (!arg4 && imageSetId != 128 && imageSetId != 121)) { + if (_tileFact[tileFactId]._tileId != 0xFF && !_dbgForceMonsterBlock) { + if ((arg4) || (!arg4 && tileFactId != 128 && tileFactId != 121)) { if (_largeMapFlag) { - _mapGameMap[mapPosX][mapPosY] = _tileFact[imageSetId]._field1; + _mapGameMap[mapPosX][mapPosY] = _tileFact[tileFactId]._tileId; } else { - _curPlace[mapPosX][mapPosY] = _tileFact[imageSetId]._field1; + _curPlace[mapPosX][mapPosY] = _tileFact[tileFactId]._tileId; } _redrawNeededFl = true; - if (_tileFact[imageSetId]._field0 == 0) + if (_tileFact[tileFactId]._field0 == 0) return 2; return 1; } } - return _tileFact[imageSetId]._field0; + return _tileFact[tileFactId]._field0; } void EfhEngine::computeInitiatives() { @@ -2850,13 +2837,14 @@ bool EfhEngine::isMonsterActive(int16 groupId, int16 id) { return false; } -int16 EfhEngine::sub15538(int16 mapPosX, int16 mapPosY) { - debug("sub15538 %d-%d", mapPosX, mapPosY); +int16 EfhEngine::getTileFactId(int16 mapPosX, int16 mapPosY) { + debug("getTileFactId %d-%d", mapPosX, mapPosY); - int16 mapTileInfo = getMapTileInfo(mapPosX, mapPosY); - int16 imageSetId = mapTileInfo / 72; + int16 curTileInfo = getMapTileInfo(mapPosX, mapPosY); + int16 imageSetId = _currentTileBankImageSetId[curTileInfo / 72] * 72; + imageSetId += curTileInfo % 72; - return (_currentTileBankImageSetId[imageSetId] * 72) + (mapTileInfo % 72); + return imageSetId; } void EfhEngine::setCharacterObjectToBroken(int16 charId, int16 objectId) { @@ -2991,7 +2979,7 @@ bool EfhEngine::checkMonsterCollision() { return true; } - int8 check = sub15581(_mapPosX, _mapPosY, true); + int8 check = checkTileStatus(_mapPosX, _mapPosY, true); if (check == 0 || check == 2) return false; diff --git a/engines/efh/efh.h b/engines/efh/efh.h index cb927cc8220e..cb8b2265012c 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -233,7 +233,7 @@ struct InitiativeStruct { struct TileFactStruct { uint8 _field0; - uint8 _field1; + uint8 _tileId; void init(); }; @@ -317,7 +317,7 @@ class EfhEngine : public Engine { int16 handleCharacterJoining(); void drawText(uint8 *impPtr, int16 posX, int16 posY, int16 maxX, int16 maxY, bool flag); void displayMiddleLeftTempText(uint8 *impArray, bool flag); - void sub15A28(int16 arg0, int16 arg2); + void transitionMap(int16 centerX, int16 centerY); void sub2455E(int16 arg0, int16 arg1, int16 arg2); int16 sub151FD(int16 posX, int16 posY); bool isPosOutOfMap(int16 mapPosX, int16 mapPosY); @@ -333,7 +333,7 @@ class EfhEngine : public Engine { void resetGame(); void computeMapAnimation(); void handleAnimations(); - int8 sub16B08(int16 monsterId); + int8 checkMonsterMoveCollisionAndTileTexture(int16 monsterId); bool moveMonsterAwayFromTeam(int16 monsterId); bool moveMonsterTowardsTeam(int16 monsterId); bool moveMonsterGroupOther(int16 monsterId, int16 direction); @@ -353,7 +353,7 @@ class EfhEngine : public Engine { void sub221D2(int16 monsterId); void displayImp1Text(int16 textId); bool sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemId, int16 arg8, int16 imageSetId); - int8 sub15581(int16 mapPosX, int16 mapPosY, bool arg4); + int8 checkTileStatus(int16 mapPosX, int16 mapPosY, bool arg4); void computeInitiatives(); void redrawScreenForced(); int16 selectMonsterGroup(); @@ -367,7 +367,7 @@ class EfhEngine : public Engine { bool hasObjectEquipped(int16 charId, int16 objectId); void setMapMonsterField8(int16 id, uint8 movementType, bool groupFl); bool isMonsterActive(int16 groupId, int16 id); - int16 sub15538(int16 mapPosX, int16 mapPosY); + int16 getTileFactId(int16 mapPosX, int16 mapPosY); void setCharacterObjectToBroken(int16 charId, int16 objectId); int16 selectOtherCharFromTeam(); bool checkMonsterCollision(); diff --git a/engines/efh/files.cpp b/engines/efh/files.cpp index e43026a2b1ce..c80db8c20a02 100644 --- a/engines/efh/files.cpp +++ b/engines/efh/files.cpp @@ -249,7 +249,7 @@ void EfhEngine::readTileFact() { for (int i = 0; i < 432; ++i) { _tileFact[i]._field0 = f.readByte(); - _tileFact[i]._field1 = f.readByte(); + _tileFact[i]._tileId = f.readByte(); } } diff --git a/engines/efh/menu.cpp b/engines/efh/menu.cpp index 08a9cc0218ed..fcbfe23624af 100644 --- a/engines/efh/menu.cpp +++ b/engines/efh/menu.cpp @@ -1101,9 +1101,9 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me case 16: { // Fairy Dust _mapPosX = getRandom(_largeMapFlag ? 63 : 23); _mapPosY = getRandom(_largeMapFlag ? 63 : 23); - int16 varAE = sub15538(_mapPosX, _mapPosY); + int16 tileFactId = getTileFactId(_mapPosX, _mapPosY); - if (_tileFact[varAE]._field0 == 0) { + if (_tileFact[tileFactId]._field0 == 0) { totalPartyKill(); buffer1 = "The entire party vanishes in a flash... only to appear in stone !"; if (argA == 2) { @@ -1112,9 +1112,8 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me _messageToBePrinted += buffer1; retVal = true; } - // emptyFunction(2); } else { - if (varAE == 0 || varAE == 0x48) { + if (tileFactId == 0 || tileFactId == 0x48) { buffer1 = "The entire party vanishes in a flash...but re-appears, as if nothing happened!"; if (argA == 2) { displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); @@ -1138,8 +1137,8 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me case 17: { // "Devil Dust" _mapPosX = _items[itemId].field_19; _mapPosY = _items[itemId].field_1A; - int16 varAE = sub15538(_mapPosX, _mapPosY); - if (_tileFact[varAE]._field0 == 0) { + int16 tileFactId = getTileFactId(_mapPosX, _mapPosY); + if (_tileFact[tileFactId]._field0 == 0) { totalPartyKill(); buffer1 = "The entire party vanishes in a flash... only to appear in stone !"; if (argA == 2) { @@ -1148,9 +1147,8 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me _messageToBePrinted += buffer1; retVal = true; } - // emptyFunction(2); } else { - if (varAE == 0 || varAE == 0x48) { + if (tileFactId == 0 || tileFactId == 0x48) { buffer1 = "The entire party vanishes in a flash...but re-appears, as if nothing happened!"; if (argA == 2) { displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); @@ -1305,7 +1303,6 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me retVal = true; } totalPartyKill(); - // emptyFunction(2); varA6 = true; break; case 27: { // "Magic Pyramid", "Razor Blade" @@ -1326,7 +1323,6 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me _messageToBePrinted += buffer1; retVal = true; } - // emptyFunction(2); } varA6 = true; diff --git a/engines/efh/script.cpp b/engines/efh/script.cpp index 3cc258f5b867..336caa9cc436 100644 --- a/engines/efh/script.cpp +++ b/engines/efh/script.cpp @@ -326,7 +326,7 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos if (flag && _largeMapFlag) { _word2C87A = true; loadPlacesFile(scriptNumberArray[0], false); - sub15A28(scriptNumberArray[1], scriptNumberArray[2]); + transitionMap(scriptNumberArray[1], scriptNumberArray[2]); sub2455E(scriptNumberArray[0], scriptNumberArray[1], scriptNumberArray[2]); retVal = -1; } From 88c3402688770e58ca59e4626dd8d851b27fd783 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Tue, 27 Dec 2022 10:03:41 +0100 Subject: [PATCH 200/412] EFH: Move initialization code to init.cpp, fix bug in script_parse (case 6), renaming --- engines/efh/efh.cpp | 311 +------------------------------------- engines/efh/efh.h | 2 - engines/efh/init.cpp | 332 +++++++++++++++++++++++++++++++++++++++++ engines/efh/module.mk | 1 + engines/efh/script.cpp | 111 +++++++------- 5 files changed, 387 insertions(+), 370 deletions(-) create mode 100644 engines/efh/init.cpp diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index af7c9f7e1fb3..82fa304ab4e3 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -22,33 +22,14 @@ #include "common/system.h" #include "common/random.h" #include "common/error.h" -#include "common/config-manager.h" #include "common/events.h" #include "engines/util.h" -#include "graphics/palette.h" #include "efh/efh.h" #include "efh/constants.h" namespace Efh { -EfhEngine *EfhEngine::s_Engine = nullptr; - -EfhGraphicsStruct::EfhGraphicsStruct() { - _vgaLineBuffer = nullptr; - _shiftValue = 0; - _width = 0; - _height = 0; - _area = Common::Rect(0, 0, 0, 0); -} -EfhGraphicsStruct::EfhGraphicsStruct(int8 **lineBuf, int16 x, int16 y, int16 width, int16 height) { - _vgaLineBuffer = lineBuf; - _shiftValue = 0; - _width = width; - _height = height; - _area = Common::Rect(x, y, x + width - 1, y + height - 1); -} - void EfhGraphicsStruct::copy(EfhGraphicsStruct *src) { // Same buffer address _vgaLineBuffer = src->_vgaLineBuffer; @@ -58,296 +39,6 @@ void EfhGraphicsStruct::copy(EfhGraphicsStruct *src) { _area = src->_area; } -void InvObject::init() { - _ref = 0; - _stat1 = 0; - _stat2 = 0; -} - -void UnkMapStruct::init() { - _placeId = _posX = _posY = _field3 = _field4 = 0; - _field5_textId = _field7_textId = 0; -} - -void UnkAnimStruct::init() { - memset(_field, 0, 4); -} - -void AnimInfo::init() { - for (int i = 0; i < 15; ++i) - _unkAnimArray[i].init(); - - for (int i = 0; i < 10; ++i) { - _field3C_startY[i] = 0; - _field46_startX[i] = 0; - } -} - -void ItemStruct::init() { - for (uint idx = 0; idx < 15; ++idx) - _name[idx] = 0; - - _damage = 0; - _defense = 0; - _attacks = 0; - _uses = 0; - field_13 = 0; - _range = 0; - _attackType = 0; - field_16 = 0; - field17_attackTypeDefense = 0; - field_18 = 0; - field_19 = 0; - field_1A = 0; -} - -void NPCStruct::init() { - for (int i = 0; i < 11; ++i) - _name[i] = 0; - fieldB_textId = 0; - field_C = 0; - field_D = 0; - fieldE_textId = 0; - field_F = 0; - field_10 = 0; - field_11 = 0; - field12_textId = 0; - field14_textId = 0; - _xp = 0; - - for (int i = 0; i < 15; ++i) - _activeScore[i] = 0; - - for (int i = 0; i < 11; ++i) { - _passiveScore[i] = 0; - _infoScore[i] = 0; - } - - field_3F = 0; - field_40 = 0; - - for (int i = 0; i < 10; ++i) - _inventory[i].init(); - - _possessivePronounSHL6 = 0; - _speed = 0; - field_6B = 0; - field_6C = 0; - field_6D = 0; - _unkItemId = 0; - field_6F = 0; - field_70 = 0; - field_71 = 0; - field_72 = 0; - field_73 = 0; - _hitPoints = 0; - _maxHP = 0; - field_78 = 0; - field_79 = 0; - field_7B = 0; - field_7D = 0; - field_7E = 0; - field_7F = 0; - field_80 = 0; - field_81 = 0; - field_82 = 0; - field_83 = 0; - field_84 = 0; - field_85 = 0; -} - -void Stru32686::init() { - for (int i = 0; i < 9; ++i) { - _field0[i] = 0; - _field2[i] = 0; - } -} - -void InitiativeStruct::init() { - _id = _initiative = 0; -} - -void TileFactStruct::init() { - _field0 = _tileId = 0; -} - -EfhEngine::EfhEngine(OSystem *syst, const ADGameDescription *gd) : Engine(syst), _gameDescription(gd) { - const Common::FSNode gameDataDir(ConfMan.get("path")); - - SearchMan.addSubDirectoryMatching(gameDataDir, "gendata"); - SearchMan.addSubDirectoryMatching(gameDataDir, "images"); - SearchMan.addSubDirectoryMatching(gameDataDir, "imp"); - SearchMan.addSubDirectoryMatching(gameDataDir, "maps"); - - _system = syst; - _rnd = nullptr; - - _shouldQuit = false; - _eventMan = nullptr; - _lastTime = 0; - _platform = Common::kPlatformUnknown; - _mainSurface = nullptr; - - _vgaGraphicsStruct1 = new EfhGraphicsStruct(_vgaLineBuffer, 0, 0, 320, 200); - _vgaGraphicsStruct2 = new EfhGraphicsStruct(); - - _videoMode = 0; - _graphicsStruct = nullptr; - - for (int i = 0; i < 19; ++i) - _mapBitmapRefArr[i] = nullptr; - - _defaultBoxColor = 0; - - _fontDescr._widthArray = nullptr; - _fontDescr._extraLines = nullptr; - _fontDescr._fontData = nullptr; - _fontDescr._charHeight = 0; - _fontDescr._extraHorizontalSpace = _fontDescr._extraVerticalSpace = 0; - - _introDoneFl = false; - _oldAnimImageSetId = -1; - _animImageSetId = 0xFE; - _paletteTransformationConstant = 10; - - for (int i = 0; i < 12; ++i) - _circleImageSubFileArray[i] = nullptr; - - _imageDataPtr._dataPtr = nullptr; - _imageDataPtr._width = 0; - _imageDataPtr._startX = _imageDataPtr._startY = 0; - _imageDataPtr._height = 0; - _imageDataPtr._lineDataSize = 0; - _imageDataPtr._paletteTransformation = 0; - _imageDataPtr._fieldD = 0; - - for (int i = 0; i < 3; ++i) - _currentTileBankImageSetId[i] = -1; - - _unkRelatedToAnimImageSetId = 0; - _techId = 0; - _currentAnimImageSetId = 0xFF; - - for (int i = 0; i < 20; ++i) { - _portraitSubFilesArray[i] = nullptr; - } - - _characterNamePt1 = ""; - _characterNamePt2 = ""; - _enemyNamePt1 = ""; - _enemyNamePt2 = ""; - _nameBuffer = ""; - _attackBuffer = ""; - - for (int i = 0; i < 100; ++i) { - _imp1PtrArray[i] = nullptr; - _mapUnknown[i].init(); - } - - for (int i = 0; i < 432; ++i) - _imp2PtrArray[i] = nullptr; - - _unkAnimRelatedIndex = -1; - - _initRect = Common::Rect(0, 0, 0, 0); - _engineInitPending = true; - _textColor = 0x0E; // Yellow - _protectionPassed = false; - _fullPlaceId = 0xFF; - _guessAnimationAmount = 9; - _largeMapFlag = 0xFFFF; - _unk2C8AA = 0; - _teamCharId[0] = 0; - _teamCharId[1] = _teamCharId[2] = -1; - - for (int i = 0; i < 3; ++i) { - _teamCharStatus[i]._status = 0; - _teamCharStatus[i]._duration = 0; - _teamPctVisible[i] = 0; - _word32482[i] = 0; - _teamNextAttack[i] = -1; - _word31780[i] = 0; - _teamLastAction[i] = 0; - } - - for (int i = 0; i < 5; ++i) { - _teamMonsterIdArray[i] = -1; - _stru32686[i].init(); - } - - _teamSize = 1; - _word2C872 = 0; - _imageSetSubFilesIdx = 144; - _oldImageSetSubFilesIdx = 143; - - _mapPosX = _mapPosY = 31; - _oldMapPosX = _oldMapPosY = 31; - _techDataId_MapPosX = _techDataId_MapPosY = 31; - - _textPosX = 0; - _textPosY = 0; - - _lastMainPlaceId = 0; - _tempTextDelay = 0; - _tempTextPtr = nullptr; - _word2C880 = false; - _redrawNeededFl = false; - _drawHeroOnMapFl = true; - _drawMonstersOnMapFl = true; - _word2C87A = false; - _dbgForceMonsterBlock = false; - _ongoingFightFl = false; - _statusMenuActive = false; - _menuDepth = 0; - _menuItemCounter = 0; - - for (int i = 0; i < 15; ++i) { - _menuStatItemArr[i] = 0; - } - - _messageToBePrinted = ""; - for (int i = 0; i < 8; ++i) - _initiatives[i].init(); - - memset(_bufferCharBM, 0, ARRAYSIZE(_bufferCharBM)); - for (int i = 0; i < 3; ++i) - memset(_tileBank[i], 0, ARRAYSIZE(_tileBank[i])); - memset(_circleImageBuf, 0, ARRAYSIZE(_circleImageBuf)); - memset(_portraitBuf, 0, ARRAYSIZE(_portraitBuf)); - memset(_hiResImageBuf, 0, ARRAYSIZE(_hiResImageBuf)); - memset(_loResImageBuf, 0, ARRAYSIZE(_loResImageBuf)); - memset(_menuBuf, 0, ARRAYSIZE(_menuBuf)); - memset(_windowWithBorderBuf, 0, ARRAYSIZE(_windowWithBorderBuf)); - memset(_places, 0, ARRAYSIZE(_places)); - for (int i = 0; i < 24; ++i) - memset(_curPlace[i], 0, ARRAYSIZE(_curPlace[i])); - memset(_npcBuf, 0, ARRAYSIZE(_npcBuf)); - memset(_imp1, 0, ARRAYSIZE(_imp1)); - memset(_imp2, 0, ARRAYSIZE(_imp2)); - memset(_titleSong, 0, ARRAYSIZE(_titleSong)); - memset(_items, 0, ARRAYSIZE(_items)); - memset(_tileFact, 0, ARRAYSIZE(_tileFact)); - memset(_animInfo, 0, ARRAYSIZE(_animInfo)); - memset(_history, 0, ARRAYSIZE(_history)); - for (int i = 0; i < 19; ++i) { - memset(_techDataArr[i], 0, ARRAYSIZE(_techDataArr[i])); - memset(_mapArr[i], 0, ARRAYSIZE(_mapArr[i])); - } - memset(_mapMonsters, 0, ARRAYSIZE(_mapMonsters)); - memset(_mapGameMap, 0, ARRAYSIZE(_mapGameMap)); - memset(_imageSetSubFilesArray, 0, ARRAYSIZE(_imageSetSubFilesArray)); - - // If requested, load a savegame instead of showing the intro - _loadSaveSlot = -1; - _saveAuthorized = false; - - if (ConfMan.hasKey("save_slot")) { - int saveSlot = ConfMan.getInt("save_slot"); - if (saveSlot >= 0 && saveSlot <= 999) - _loadSaveSlot = saveSlot; - } -} - EfhEngine::~EfhEngine() { delete _rnd; delete _graphicsStruct; @@ -363,7 +54,7 @@ void EfhEngine::syncSoundSettings() { Common::Error EfhEngine::run() { debug("run"); - s_Engine = this; + initialize(); initGraphics(320, 200); diff --git a/engines/efh/efh.h b/engines/efh/efh.h index cb8b2265012c..0acda53c6f97 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -275,8 +275,6 @@ class EfhEngine : public Engine { Common::Error run() override; private: - static EfhEngine *s_Engine; - Common::Platform _platform; int _loadSaveSlot; bool _saveAuthorized; diff --git a/engines/efh/init.cpp b/engines/efh/init.cpp new file mode 100644 index 000000000000..0b357862987d --- /dev/null +++ b/engines/efh/init.cpp @@ -0,0 +1,332 @@ +/* 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/config-manager.h" +#include "efh/efh.h" + +namespace Efh { +EfhGraphicsStruct::EfhGraphicsStruct() { + _vgaLineBuffer = nullptr; + _shiftValue = 0; + _width = 0; + _height = 0; + _area = Common::Rect(0, 0, 0, 0); +} +EfhGraphicsStruct::EfhGraphicsStruct(int8 **lineBuf, int16 x, int16 y, int16 width, int16 height) { + _vgaLineBuffer = lineBuf; + _shiftValue = 0; + _width = width; + _height = height; + _area = Common::Rect(x, y, x + width - 1, y + height - 1); +} + +void InvObject::init() { + _ref = 0; + _stat1 = 0; + _stat2 = 0; +} + +void UnkMapStruct::init() { + _placeId = _posX = _posY = _field3 = _field4 = 0; + _field5_textId = _field7_textId = 0; +} + +void UnkAnimStruct::init() { + memset(_field, 0, 4); +} + +void AnimInfo::init() { + for (int i = 0; i < 15; ++i) + _unkAnimArray[i].init(); + + for (int i = 0; i < 10; ++i) { + _field3C_startY[i] = 0; + _field46_startX[i] = 0; + } +} + +void ItemStruct::init() { + for (uint idx = 0; idx < 15; ++idx) + _name[idx] = 0; + + _damage = 0; + _defense = 0; + _attacks = 0; + _uses = 0; + field_13 = 0; + _range = 0; + _attackType = 0; + field_16 = 0; + field17_attackTypeDefense = 0; + field_18 = 0; + field_19 = 0; + field_1A = 0; +} + +void NPCStruct::init() { + for (int i = 0; i < 11; ++i) + _name[i] = 0; + fieldB_textId = 0; + field_C = 0; + field_D = 0; + fieldE_textId = 0; + field_F = 0; + field_10 = 0; + field_11 = 0; + field12_textId = 0; + field14_textId = 0; + _xp = 0; + + for (int i = 0; i < 15; ++i) + _activeScore[i] = 0; + + for (int i = 0; i < 11; ++i) { + _passiveScore[i] = 0; + _infoScore[i] = 0; + } + + field_3F = 0; + field_40 = 0; + + for (int i = 0; i < 10; ++i) + _inventory[i].init(); + + _possessivePronounSHL6 = 0; + _speed = 0; + field_6B = 0; + field_6C = 0; + field_6D = 0; + _unkItemId = 0; + field_6F = 0; + field_70 = 0; + field_71 = 0; + field_72 = 0; + field_73 = 0; + _hitPoints = 0; + _maxHP = 0; + field_78 = 0; + field_79 = 0; + field_7B = 0; + field_7D = 0; + field_7E = 0; + field_7F = 0; + field_80 = 0; + field_81 = 0; + field_82 = 0; + field_83 = 0; + field_84 = 0; + field_85 = 0; +} + +void Stru32686::init() { + for (int i = 0; i < 9; ++i) { + _field0[i] = 0; + _field2[i] = 0; + } +} + +void InitiativeStruct::init() { + _id = _initiative = 0; +} + +void TileFactStruct::init() { + _field0 = _tileId = 0; +} + +EfhEngine::EfhEngine(OSystem *syst, const ADGameDescription *gd) : Engine(syst), _gameDescription(gd) { + const Common::FSNode gameDataDir(ConfMan.get("path")); + + SearchMan.addSubDirectoryMatching(gameDataDir, "gendata"); + SearchMan.addSubDirectoryMatching(gameDataDir, "images"); + SearchMan.addSubDirectoryMatching(gameDataDir, "imp"); + SearchMan.addSubDirectoryMatching(gameDataDir, "maps"); + + _system = syst; + _rnd = nullptr; + + _shouldQuit = false; + _eventMan = nullptr; + _lastTime = 0; + _platform = Common::kPlatformUnknown; + _mainSurface = nullptr; + + _vgaGraphicsStruct1 = new EfhGraphicsStruct(_vgaLineBuffer, 0, 0, 320, 200); + _vgaGraphicsStruct2 = new EfhGraphicsStruct(); + + _videoMode = 0; + _graphicsStruct = nullptr; + + for (int i = 0; i < 19; ++i) + _mapBitmapRefArr[i] = nullptr; + + _defaultBoxColor = 0; + + _fontDescr._widthArray = nullptr; + _fontDescr._extraLines = nullptr; + _fontDescr._fontData = nullptr; + _fontDescr._charHeight = 0; + _fontDescr._extraHorizontalSpace = _fontDescr._extraVerticalSpace = 0; + + _introDoneFl = false; + _oldAnimImageSetId = -1; + _animImageSetId = 0xFE; + _paletteTransformationConstant = 10; + + for (int i = 0; i < 12; ++i) + _circleImageSubFileArray[i] = nullptr; + + _imageDataPtr._dataPtr = nullptr; + _imageDataPtr._width = 0; + _imageDataPtr._startX = _imageDataPtr._startY = 0; + _imageDataPtr._height = 0; + _imageDataPtr._lineDataSize = 0; + _imageDataPtr._paletteTransformation = 0; + _imageDataPtr._fieldD = 0; + + for (int i = 0; i < 3; ++i) + _currentTileBankImageSetId[i] = -1; + + _unkRelatedToAnimImageSetId = 0; + _techId = 0; + _currentAnimImageSetId = 0xFF; + + for (int i = 0; i < 20; ++i) { + _portraitSubFilesArray[i] = nullptr; + } + + _characterNamePt1 = ""; + _characterNamePt2 = ""; + _enemyNamePt1 = ""; + _enemyNamePt2 = ""; + _nameBuffer = ""; + _attackBuffer = ""; + + for (int i = 0; i < 100; ++i) { + _imp1PtrArray[i] = nullptr; + _mapUnknown[i].init(); + } + + for (int i = 0; i < 432; ++i) + _imp2PtrArray[i] = nullptr; + + _unkAnimRelatedIndex = -1; + + _initRect = Common::Rect(0, 0, 0, 0); + _engineInitPending = true; + _textColor = 0x0E; // Yellow + _protectionPassed = false; + _fullPlaceId = 0xFF; + _guessAnimationAmount = 9; + _largeMapFlag = 0xFFFF; + _unk2C8AA = 0; + _teamCharId[0] = 0; + _teamCharId[1] = _teamCharId[2] = -1; + + for (int i = 0; i < 3; ++i) { + _teamCharStatus[i]._status = 0; + _teamCharStatus[i]._duration = 0; + _teamPctVisible[i] = 0; + _word32482[i] = 0; + _teamNextAttack[i] = -1; + _word31780[i] = 0; + _teamLastAction[i] = 0; + } + + for (int i = 0; i < 5; ++i) { + _teamMonsterIdArray[i] = -1; + _stru32686[i].init(); + } + + _teamSize = 1; + _word2C872 = 0; + _imageSetSubFilesIdx = 144; + _oldImageSetSubFilesIdx = 143; + + _mapPosX = _mapPosY = 31; + _oldMapPosX = _oldMapPosY = 31; + _techDataId_MapPosX = _techDataId_MapPosY = 31; + + _textPosX = 0; + _textPosY = 0; + + _lastMainPlaceId = 0; + _tempTextDelay = 0; + _tempTextPtr = nullptr; + _word2C880 = false; + _redrawNeededFl = false; + _drawHeroOnMapFl = true; + _drawMonstersOnMapFl = true; + _word2C87A = false; + _dbgForceMonsterBlock = false; + _ongoingFightFl = false; + _statusMenuActive = false; + _menuDepth = 0; + _menuItemCounter = 0; + + for (int i = 0; i < 15; ++i) { + _menuStatItemArr[i] = 0; + } + + _messageToBePrinted = ""; + for (int i = 0; i < 8; ++i) + _initiatives[i].init(); + + memset(_bufferCharBM, 0, ARRAYSIZE(_bufferCharBM)); + for (int i = 0; i < 3; ++i) + memset(_tileBank[i], 0, ARRAYSIZE(_tileBank[i])); + memset(_circleImageBuf, 0, ARRAYSIZE(_circleImageBuf)); + memset(_portraitBuf, 0, ARRAYSIZE(_portraitBuf)); + memset(_hiResImageBuf, 0, ARRAYSIZE(_hiResImageBuf)); + memset(_loResImageBuf, 0, ARRAYSIZE(_loResImageBuf)); + memset(_menuBuf, 0, ARRAYSIZE(_menuBuf)); + memset(_windowWithBorderBuf, 0, ARRAYSIZE(_windowWithBorderBuf)); + memset(_places, 0, ARRAYSIZE(_places)); + for (int i = 0; i < 24; ++i) + memset(_curPlace[i], 0, ARRAYSIZE(_curPlace[i])); + memset(_npcBuf, 0, ARRAYSIZE(_npcBuf)); + memset(_imp1, 0, ARRAYSIZE(_imp1)); + memset(_imp2, 0, ARRAYSIZE(_imp2)); + memset(_titleSong, 0, ARRAYSIZE(_titleSong)); + memset(_items, 0, ARRAYSIZE(_items)); + memset(_tileFact, 0, ARRAYSIZE(_tileFact)); + memset(_animInfo, 0, ARRAYSIZE(_animInfo)); + memset(_history, 0, ARRAYSIZE(_history)); + for (int i = 0; i < 19; ++i) { + memset(_techDataArr[i], 0, ARRAYSIZE(_techDataArr[i])); + memset(_mapArr[i], 0, ARRAYSIZE(_mapArr[i])); + } + memset(_mapMonsters, 0, ARRAYSIZE(_mapMonsters)); + memset(_mapGameMap, 0, ARRAYSIZE(_mapGameMap)); + memset(_imageSetSubFilesArray, 0, ARRAYSIZE(_imageSetSubFilesArray)); + + // If requested, load a savegame instead of showing the intro + _loadSaveSlot = -1; + _saveAuthorized = false; + + if (ConfMan.hasKey("save_slot")) { + int saveSlot = ConfMan.getInt("save_slot"); + if (saveSlot >= 0 && saveSlot <= 999) + _loadSaveSlot = saveSlot; + } +} + +} // End of namespace Efh + diff --git a/engines/efh/module.mk b/engines/efh/module.mk index f6d074368082..a81d60c278d7 100644 --- a/engines/efh/module.mk +++ b/engines/efh/module.mk @@ -6,6 +6,7 @@ MODULE_OBJS = \ fight.o \ files.o \ graphics.o \ + init.o \ menu.o \ savegames.o \ script.o \ diff --git a/engines/efh/script.cpp b/engines/efh/script.cpp index 336caa9cc436..354c9bcf6391 100644 --- a/engines/efh/script.cpp +++ b/engines/efh/script.cpp @@ -162,11 +162,11 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos case 0x03: buffer = script_readNumberArray(buffer, 4, scriptNumberArray); if (flag) { - int16 var110 = scriptNumberArray[2] - scriptNumberArray[0]; - int16 var10E = scriptNumberArray[3] - scriptNumberArray[1]; + int16 rangeX = scriptNumberArray[2] - scriptNumberArray[0]; + int16 rangeY = scriptNumberArray[3] - scriptNumberArray[1]; - _mapPosX = getRandom(var110) + scriptNumberArray[0] - 1; - _mapPosY = getRandom(var10E) + scriptNumberArray[1] - 1; + _mapPosX = getRandom(rangeX) + scriptNumberArray[0] - 1; + _mapPosY = getRandom(rangeY) + scriptNumberArray[1] - 1; _word2C880 = true; _redrawNeededFl = true; } @@ -183,28 +183,27 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos case 0x05: buffer = script_readNumberArray(buffer, 4, scriptNumberArray); if (flag) { - int16 var110 = _teamCharId[scriptNumberArray[0]]; - if (var110 != -1) { - int16 var10E = scriptNumberArray[1]; - _npcBuf[var110]._activeScore[var10E] += scriptNumberArray[2] & 0xFF; - _npcBuf[var110]._activeScore[var10E] -= scriptNumberArray[3] & 0xFF; + int16 npcId = _teamCharId[scriptNumberArray[0]]; + if (npcId != -1) { + int16 scoreId = scriptNumberArray[1]; + _npcBuf[npcId]._activeScore[scoreId] += scriptNumberArray[2] & 0xFF; + _npcBuf[npcId]._activeScore[scoreId] -= scriptNumberArray[3] & 0xFF; } } break; case 0x06: buffer = script_readNumberArray(buffer, 2, scriptNumberArray); if (flag) { - int16 var110 = _teamCharId[scriptNumberArray[0]]; - if (var110 != -1) { - int16 var10E = scriptNumberArray[1]; - _npcBuf[var110]._activeScore[var10E] = scriptNumberArray[1]; + int16 npcId = _teamCharId[scriptNumberArray[0]]; + if (npcId != -1) { + int16 scoreId = scriptNumberArray[1]; + _npcBuf[npcId]._activeScore[scoreId] = scriptNumberArray[2] & 0xFF; } } break; case 0x07: if (flag) { totalPartyKill(); - // emptyFunction(2); } break; case 0x08: @@ -216,44 +215,42 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos case 0x09: buffer = script_readNumberArray(buffer, 2, scriptNumberArray); if (flag) { - int16 var110 = _teamCharId[scriptNumberArray[0]]; - if (var110 != -1) { - int16 var10E = getRandom(scriptNumberArray[1]); - _npcBuf[var110]._hitPoints += var10E; - if (_npcBuf[var110]._hitPoints > _npcBuf[var110]._maxHP) - _npcBuf[var110]._hitPoints = _npcBuf[var110]._maxHP; + int16 npcId = _teamCharId[scriptNumberArray[0]]; + if (npcId != -1) { + _npcBuf[npcId]._hitPoints += getRandom(scriptNumberArray[1]); + if (_npcBuf[npcId]._hitPoints > _npcBuf[npcId]._maxHP) + _npcBuf[npcId]._hitPoints = _npcBuf[npcId]._maxHP; } } break; case 0x0A: buffer = script_readNumberArray(buffer, 1, scriptNumberArray); if (flag) { - int16 var110 = _teamCharId[scriptNumberArray[0]]; - if (var110 != -1) { - _npcBuf[var110]._hitPoints = _npcBuf[var110]._maxHP; + int16 npcId = _teamCharId[scriptNumberArray[0]]; + if (npcId != -1) { + _npcBuf[npcId]._hitPoints = _npcBuf[npcId]._maxHP; } } break; case 0x0B: buffer = script_readNumberArray(buffer, 2, scriptNumberArray); if (flag) { - int16 var110 = _teamCharId[scriptNumberArray[0]]; - if (var110 != -1) { - int16 var10E = getRandom(scriptNumberArray[1]); - _npcBuf[var110]._hitPoints -= var10E; - if (_npcBuf[var110]._hitPoints < 0) - _npcBuf[var110]._hitPoints = 0; + int16 npcId = _teamCharId[scriptNumberArray[0]]; + if (npcId != -1) { + _npcBuf[npcId]._hitPoints -= getRandom(scriptNumberArray[1]); + if (_npcBuf[npcId]._hitPoints < 0) + _npcBuf[npcId]._hitPoints = 0; } } break; case 0x0C: buffer = script_readNumberArray(buffer, 2, scriptNumberArray); if (flag) { - int16 var110 = scriptNumberArray[0]; + int16 scriptItemId = scriptNumberArray[0]; bool found = false; for (int counter = 0; counter < _teamSize && !found; ++counter) { for (uint objectId = 0; objectId < 10; ++objectId) { - if (_npcBuf[_teamCharId[counter]]._inventory[objectId]._ref == var110) { + if (_npcBuf[_teamCharId[counter]]._inventory[objectId]._ref == scriptItemId) { removeObject(_teamCharId[counter], objectId); found = true; break; @@ -266,9 +263,9 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos // Put item in inventory { objectId } buffer = script_readNumberArray(buffer, 1, scriptNumberArray); if (flag) { - int16 var110 = scriptNumberArray[0]; + int16 scriptObjectId = scriptNumberArray[0]; for (int counter = 0; counter < _teamSize; ++counter) { - if (giveItemTo(_teamCharId[counter], var110, 0xFF)) + if (giveItemTo(_teamCharId[counter], scriptObjectId, 0xFF)) break; } } @@ -276,11 +273,11 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos case 0x0E: buffer = script_readNumberArray(buffer, 3, scriptNumberArray); if (flag) { - int16 var110 = scriptNumberArray[0]; + int16 scriptItemId = scriptNumberArray[0]; bool found = false; for (int counter = 0; counter < _teamSize && !found; ++counter) { for (uint objectId = 0; objectId < 10; ++objectId) { - if (_npcBuf[_teamCharId[counter]]._inventory[objectId]._ref == var110) { + if (_npcBuf[_teamCharId[counter]]._inventory[objectId]._ref == scriptItemId) { found = true; break; } @@ -296,8 +293,7 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos case 0x0F: buffer = script_readNumberArray(buffer, 3, scriptNumberArray); if (flag) { - int16 var110 = scriptNumberArray[0]; - if (isCharacterATeamMember(var110)) + if (isCharacterATeamMember(scriptNumberArray[0])) retVal = scriptNumberArray[1]; else retVal = scriptNumberArray[2]; @@ -335,9 +331,9 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos // Add character to team { charId } buffer = script_readNumberArray(buffer, 1, scriptNumberArray); if (flag) { - int16 var110 = scriptNumberArray[0]; - if (!isCharacterATeamMember(var110)) - var_EE = var110; + int16 scriptNpcId = scriptNumberArray[0]; + if (!isCharacterATeamMember(scriptNpcId)) + var_EE = scriptNpcId; retVal = -1; } break; @@ -353,11 +349,11 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos case 0x16: buffer = script_readNumberArray(buffer, 1, scriptNumberArray); if (flag) { - int16 var110 = scriptNumberArray[0]; + int16 scriptNpcId = scriptNumberArray[0]; // TODO: This "if" is useless, it's doing just the same loop and if statement. Consider removing it. - if (isCharacterATeamMember(var110)) { + if (isCharacterATeamMember(scriptNpcId)) { for (uint counter = 0; counter < 3; ++counter) { - if (_teamCharId[counter] == var110) { + if (_teamCharId[counter] == scriptNpcId) { removeCharacterFromTeam(counter); break; } @@ -375,12 +371,11 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos case 0x18: buffer = script_readNumberArray(buffer, 2, scriptNumberArray); if (flag) { - int16 var110 = scriptNumberArray[1] - scriptNumberArray[0] + 1; bool found = false; - var110 = getRandom(var110) + scriptNumberArray[0] - 1; + int16 scriptRandomItemId = getRandom(scriptNumberArray[1] - scriptNumberArray[0] + 1) + scriptNumberArray[0] - 1; int16 counter; for (counter = 0; counter < _teamSize; ++counter) { - if (giveItemTo(_teamCharId[counter], var110, 0xFF)) { + if (giveItemTo(_teamCharId[counter], scriptRandomItemId, 0xFF)) { found = true; break; } @@ -390,22 +385,22 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos drawMapWindow(); displayFctFullScreen(); drawMapWindow(); - var110 = sub1C219("Nothing...", 1, 2, true); + scriptRandomItemId = sub1C219("Nothing...", 1, 2, true); displayFctFullScreen(); } else { _enemyNamePt2 = _npcBuf[_teamCharId[counter]]._name; - _nameBuffer = _items[var110]._name; + _nameBuffer = _items[scriptRandomItemId]._name; curLine = Common::String::format("%s finds a %s!", _enemyNamePt2.c_str(), _nameBuffer.c_str()); drawMapWindow(); displayFctFullScreen(); drawMapWindow(); - var110 = sub1C219(curLine, 1, 2, true); + scriptRandomItemId = sub1C219(curLine, 1, 2, true); displayFctFullScreen(); } - var110 = sub151FD(_mapPosX, _mapPosY); - if (var110 != -1) { - _mapUnknown[var110]._posX = 0xFF; + int16 mapUnkId = sub151FD(_mapPosX, _mapPosY); + if (mapUnkId != -1) { + _mapUnknown[mapUnkId]._posX = 0xFF; } _redrawNeededFl = true; } @@ -423,18 +418,18 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos case 0x1A: buffer = script_readNumberArray(buffer, 2, scriptNumberArray); if (flag) { - int16 var110 = sub151FD(scriptNumberArray[0], scriptNumberArray[1]); - if (var110 != -1) { - _mapUnknown[var110]._posX = 0xFF; + int16 mapUnkId = sub151FD(scriptNumberArray[0], scriptNumberArray[1]); + if (mapUnkId != -1) { + _mapUnknown[mapUnkId]._posX = 0xFF; } } break; case 0x1B: buffer = script_readNumberArray(buffer, 3, scriptNumberArray); if (flag) { - int16 var110 = sub151FD(scriptNumberArray[0], scriptNumberArray[1]); - if (var110 != -1) { - _mapUnknown[var110]._posX = 0xFF; + int16 mapUnkId = sub151FD(scriptNumberArray[0], scriptNumberArray[1]); + if (mapUnkId != -1) { + _mapUnknown[mapUnkId]._posX = 0xFF; } _mapUnknown[scriptNumberArray[2]]._posX = scriptNumberArray[0]; _mapUnknown[scriptNumberArray[2]]._posY = scriptNumberArray[1]; From d705fe97769d096e134429e67eb414a80782f417 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Thu, 29 Dec 2022 00:39:45 +0100 Subject: [PATCH 201/412] EFH: Fix bugs in handleFight_lastAction_A(), renaming --- engines/efh/efh.cpp | 18 +++++++++--------- engines/efh/efh.h | 12 ++++++------ engines/efh/fight.cpp | 37 ++++++++++++++++++------------------- engines/efh/files.cpp | 4 ++-- engines/efh/init.cpp | 8 ++++---- engines/efh/menu.cpp | 28 +++++++++++++++------------- 6 files changed, 54 insertions(+), 53 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 82fa304ab4e3..adb3c555071e 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -2299,15 +2299,15 @@ void EfhEngine::sub1BE9A(int16 monsterId) { for (uint counter2 = 0; counter2 < 9; ++counter2) { _mapMonsters[_teamMonsterIdArray[counter1]]._pictureRef[counter2] = 0; - _stru32686[counter1]._field0[counter2] = 0; - _stru32686[counter1]._field2[counter2] = 0; + _teamMonsterEffects[counter1]._effect[counter2] = 0; + _teamMonsterEffects[counter1]._duration[counter2] = 0; } _teamMonsterIdArray[counter1] = -1; for (uint counter2 = counter1 + 1; counter2 < 5; ++counter2) { for (uint var8 = 0; var8 < 9; ++var8) { - _stru32686[counter1]._field0[var8] = _stru32686[counter2]._field0[var8]; - _stru32686[counter1]._field2[var8] = _stru32686[counter2]._field2[var8]; + _teamMonsterEffects[counter1]._effect[var8] = _teamMonsterEffects[counter2]._effect[var8]; + _teamMonsterEffects[counter1]._duration[var8] = _teamMonsterEffects[counter2]._duration[var8]; } _teamMonsterIdArray[counter1] = _teamMonsterIdArray[counter2]; } @@ -2356,11 +2356,11 @@ void EfhEngine::sub1BE9A(int16 monsterId) { // The original at this point was doing a loop on counter1, which is not a good idea as // it was resetting the counter1 to 9 whatever its value before the loop. - // Furthermore, it was accessing _stru32686[counter1]._field0[counter1] which doesn't make + // Furthermore, it was accessing _teamMonsterEffects[counter1]._effect[counter1] which doesn't make // sense... // I therefore decided to use another counter as it looks like an original misbehavior/bug. for (uint counter2 = 0; counter2 < 9; ++counter2) { - _stru32686[counter1]._field0[counter2] = 0; + _teamMonsterEffects[counter1]._effect[counter2] = 0; } if (++var4 >= 5) @@ -2379,7 +2379,7 @@ void EfhEngine::sub1BE9A(int16 monsterId) { for (int16 counter1 = var4; counter1 < 5; ++counter1) { _teamMonsterIdArray[counter1] = -1; for (uint counter2 = 0; counter2 < 9; ++counter2) { - _stru32686[counter1]._field0[counter2] = (int16)0x8000; + _teamMonsterEffects[counter1]._effect[counter2] = (int16)0x8000; } } // sub1BE9A - last loop counter1_monsterId - End @@ -2490,7 +2490,7 @@ int16 EfhEngine::getXPLevel(int32 xp) { bool EfhEngine::isItemCursed(int16 itemId) { debugC(6, kDebugEngine, "isItemCursed %d", itemId); - if (_items[itemId].field_16 == 21 || _items[itemId].field_16 == 22 || _items[itemId].field_16 == 23) + if (_items[itemId]._specialEffect == 21 || _items[itemId]._specialEffect == 22 || _items[itemId]._specialEffect == 23) return true; return false; @@ -2523,7 +2523,7 @@ void EfhEngine::setMapMonsterField8(int16 id, uint8 movementType, bool groupFl) bool EfhEngine::isMonsterActive(int16 groupId, int16 id) { debugC(5, kDebugEngine, "isMonsterActive %d %d", groupId, id); - if (_mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[id] > 0 && _stru32686[groupId]._field0[id] == 0) + if (_mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[id] > 0 && _teamMonsterEffects[groupId]._effect[id] == 0) return true; return false; } diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 0acda53c6f97..02b020b4c06a 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -81,7 +81,7 @@ class EfhGraphicsStruct { struct InvObject { int16 _ref; - uint8 _stat1; + uint8 _stat1; // abbb bbbb - a: equipped b: durability uint8 _stat2; void init(); @@ -121,7 +121,7 @@ struct ItemStruct { int8 field_13; // data contains values from -8 to +8 uint8 _range; uint8 _attackType; - uint8 field_16; + uint8 _specialEffect; uint8 field17_attackTypeDefense; uint8 field_18; uint8 field_19; @@ -218,8 +218,8 @@ struct MapMonster { }; struct Stru32686 { - int16 _field0[9]; - int16 _field2[9]; + int16 _effect[9]; + int16 _duration[9]; void init(); }; @@ -462,7 +462,7 @@ class EfhEngine : public Engine { void sub18E80(int16 charId, int16 windowId, int16 menuId, int16 curMenuLine); int16 displayString_3(Common::String str, bool animFl, int16 charId, int16 windowId, int16 menuId, int16 curMenuLine); int16 handleStatusMenu(int16 gameMode, int16 charId); - void equipCursedItem(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine); + void unequipItem(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine); void sub191FF(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine); int16 sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine, int16 argA); @@ -602,7 +602,7 @@ class EfhEngine : public Engine { int16 _word31780[3]; int16 _menuStatItemArr[15]; - Stru32686 _stru32686[5]; + Stru32686 _teamMonsterEffects[5]; InitiativeStruct _initiatives[8]; }; diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index 7e391f61460d..98a94f637380 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -303,7 +303,7 @@ bool EfhEngine::handleFight(int16 monsterId) { // handleFight - Check armor - end // handleFight - Check effect - start - switch (_items[unk_monsterField5_itemId].field_16) { + switch (_items[unk_monsterField5_itemId]._specialEffect) { case 1: if (getRandom(100) < 20) { _teamCharStatus[var7E]._status = 1; @@ -337,9 +337,9 @@ bool EfhEngine::handleFight(int16 monsterId) { } // handleFight - Loop on var7E - End } - } else if (_mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._pictureRef[var86] > 0 && _stru32686[monsterGroupIdOrMonsterId]._field0[var86]) { - --_stru32686[monsterGroupIdOrMonsterId]._field2[var86]; - if (_stru32686[monsterGroupIdOrMonsterId]._field2[var86] <= 0) { + } else if (_mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._pictureRef[var86] > 0 && _teamMonsterEffects[monsterGroupIdOrMonsterId]._effect[var86]) { + --_teamMonsterEffects[monsterGroupIdOrMonsterId]._duration[var86]; + if (_teamMonsterEffects[monsterGroupIdOrMonsterId]._duration[var86] <= 0) { _enemyNamePt2 = kEncounters[_mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._monsterRef]._name; int16 var70 = kEncounters[_mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._monsterRef]._nameArticle; if (var70 == 2) @@ -347,7 +347,7 @@ bool EfhEngine::handleFight(int16 monsterId) { else _enemyNamePt1 = ""; - switch (_stru32686[monsterGroupIdOrMonsterId]._field0[var86]) { + switch (_teamMonsterEffects[monsterGroupIdOrMonsterId]._effect[var86]) { case 1: _messageToBePrinted = Common::String::format("%s%s wakes up!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str()); break; @@ -358,7 +358,7 @@ bool EfhEngine::handleFight(int16 monsterId) { _messageToBePrinted = Common::String::format("%s%s recovers!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str()); break; } - _stru32686[monsterGroupIdOrMonsterId]._field0[var86] = 0; + _teamMonsterEffects[monsterGroupIdOrMonsterId]._effect[var86] = 0; sub1C219(_messageToBePrinted, 1, 2, true); } } @@ -472,7 +472,6 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { int16 charScore = getCharacterScore(_teamCharId[teamCharId], unk_monsterField5_itemId); int16 var80 = _mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E]; int16 var62 = 0; - int16 hitPoints = 0; int16 originalDamage = 0; int16 damagePointsAbsorbed = 0; int16 var64 = _items[unk_monsterField5_itemId]._attacks * _npcBuf[_teamCharId[teamCharId]]._speed; @@ -498,7 +497,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { if (originalDamage < 0) originalDamage = 0; - hitPoints = originalDamage + damagePointsAbsorbed; + int16 hitPoints = originalDamage + damagePointsAbsorbed; if (!checkSpecialItemsOnCurrentPlace(unk_monsterField5_itemId)) var62 = 0; @@ -603,15 +602,15 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { // Action A - Check item durability - End // Action A - Check effect - Start - if (_items[unk_monsterField5_itemId].field_16 == 1 && _mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] > 0) { + if (_items[unk_monsterField5_itemId]._specialEffect == 1 && _mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] > 0) { if (getRandom(100) < 35) { - _stru32686[var7E]._field0[groupId] = 1; - _stru32686[var7E]._field2[groupId] = getRandom(10); + _teamMonsterEffects[groupId]._effect[var7E] = 1; + _teamMonsterEffects[groupId]._duration[var7E] = getRandom(10); _messageToBePrinted += Common::String::format(" %s%s falls asleep!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); } - } else if (_items[unk_monsterField5_itemId].field_16 == 2 && _mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] > 0) { - _stru32686[var7E]._field0[groupId] = 2; - _stru32686[var7E]._field2[groupId] = getRandom(10); + } else if (_items[unk_monsterField5_itemId]._specialEffect == 2 && _mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] > 0) { + _teamMonsterEffects[groupId]._effect[var7E] = 2; + _teamMonsterEffects[groupId]._duration[var7E] = getRandom(10); _messageToBePrinted += Common::String::format(" %s%s is frozen!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); } // Action A - Check effect - End @@ -707,8 +706,8 @@ void EfhEngine::reset_stru32686() { debug("reset_stru32686"); for (uint counter1 = 0; counter1 < 5; ++counter1) { for (uint counter2 = 0; counter2 < 9; ++counter2) { - _stru32686[counter1]._field0[counter2] = 0; - _stru32686[counter1]._field2[counter2] = 0; + _teamMonsterEffects[counter1]._effect[counter2] = 0; + _teamMonsterEffects[counter1]._duration[counter2] = 0; } } } @@ -1516,7 +1515,7 @@ bool EfhEngine::hasAdequateDefense(int16 monsterId, uint8 attackType) { int16 itemId = _mapMonsters[monsterId]._itemId_Weapon; - if (_items[itemId].field_16 != 0) + if (_items[itemId]._specialEffect != 0) return false; return _items[itemId].field17_attackTypeDefense == attackType; @@ -1527,7 +1526,7 @@ bool EfhEngine::hasAdequateDefense_2(int16 charId, uint8 attackType) { int16 itemId = _npcBuf[charId]._unkItemId; - if (_items[itemId].field_16 == 0 && _items[itemId].field17_attackTypeDefense == attackType) + if (_items[itemId]._specialEffect == 0 && _items[itemId].field17_attackTypeDefense == attackType) return true; for (uint counter = 0; counter < 10; ++counter) { @@ -1535,7 +1534,7 @@ bool EfhEngine::hasAdequateDefense_2(int16 charId, uint8 attackType) { continue; itemId = _npcBuf[charId]._inventory[counter]._ref; - if (_items[itemId].field_16 == 0 && _items[itemId].field17_attackTypeDefense == attackType) + if (_items[itemId]._specialEffect == 0 && _items[itemId].field17_attackTypeDefense == attackType) return true; } return false; diff --git a/engines/efh/files.cpp b/engines/efh/files.cpp index c80db8c20a02..ccae0802e5d2 100644 --- a/engines/efh/files.cpp +++ b/engines/efh/files.cpp @@ -148,13 +148,13 @@ void EfhEngine::readItems() { _items[i].field_13 = f.readByte(); _items[i]._range = f.readByte(); _items[i]._attackType = f.readByte(); - _items[i].field_16 = f.readByte(); + _items[i]._specialEffect = f.readByte(); _items[i].field17_attackTypeDefense = f.readByte(); _items[i].field_18 = f.readByte(); _items[i].field_19 = f.readByte(); _items[i].field_1A = f.readByte(); - debugC(7, kDebugEngine, "%s\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x", _items[i]._name, _items[i]._damage, _items[i]._defense, _items[i]._attacks, _items[i]._uses, _items[i].field_13, _items[i]._range, _items[i]._attackType, _items[i].field_16, _items[i].field17_attackTypeDefense, _items[i].field_18, _items[i].field_19, _items[i].field_1A); + debugC(7, kDebugEngine, "%s\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x", _items[i]._name, _items[i]._damage, _items[i]._defense, _items[i]._attacks, _items[i]._uses, _items[i].field_13, _items[i]._range, _items[i]._attackType, _items[i]._specialEffect, _items[i].field17_attackTypeDefense, _items[i].field_18, _items[i].field_19, _items[i].field_1A); } } diff --git a/engines/efh/init.cpp b/engines/efh/init.cpp index 0b357862987d..1cc26d9713ac 100644 --- a/engines/efh/init.cpp +++ b/engines/efh/init.cpp @@ -74,7 +74,7 @@ void ItemStruct::init() { field_13 = 0; _range = 0; _attackType = 0; - field_16 = 0; + _specialEffect = 0; field17_attackTypeDefense = 0; field_18 = 0; field_19 = 0; @@ -138,8 +138,8 @@ void NPCStruct::init() { void Stru32686::init() { for (int i = 0; i < 9; ++i) { - _field0[i] = 0; - _field2[i] = 0; + _effect[i] = 0; + _duration[i] = 0; } } @@ -252,7 +252,7 @@ EfhEngine::EfhEngine(OSystem *syst, const ADGameDescription *gd) : Engine(syst), for (int i = 0; i < 5; ++i) { _teamMonsterIdArray[i] = -1; - _stru32686[i].init(); + _teamMonsterEffects[i].init(); } _teamSize = 1; diff --git a/engines/efh/menu.cpp b/engines/efh/menu.cpp index fcbfe23624af..b6ea94c1cbb8 100644 --- a/engines/efh/menu.cpp +++ b/engines/efh/menu.cpp @@ -865,14 +865,15 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { return 0; } -void EfhEngine::equipCursedItem(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine) { - debug("equipCursedItem %d %d %d %d %d", charId, objectId, windowId, menuId, curMenuLine); +void EfhEngine::unequipItem(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine) { + debugC(6,kDebugEngine, "unequipItem %d %d %d %d %d", charId, objectId, windowId, menuId, curMenuLine); int16 itemId = _npcBuf[charId]._inventory[objectId]._ref; if (isItemCursed(itemId)) { _npcBuf[charId]._inventory[objectId]._stat1 &= 0x7F; } else { + // Original message. "Cursed item can't be unequipped" would make more sense, imho displayString_3("Cursed Item Already Equipped!", true, charId, windowId, menuId, curMenuLine); } } @@ -883,16 +884,17 @@ void EfhEngine::sub191FF(int16 charId, int16 objectId, int16 windowId, int16 men int16 itemId = _npcBuf[charId]._inventory[objectId]._ref; if (hasObjectEquipped(charId, objectId)) { - equipCursedItem(charId, objectId, windowId, menuId, curMenuLine); + unequipItem(charId, objectId, windowId, menuId, curMenuLine); } else { int16 var2 = _items[itemId].field_18; if (var2 != 4) { for (uint counter = 0; counter < 10; ++counter) { if (var2 == _items[_npcBuf[charId]._inventory[counter]._ref].field_18) - equipCursedItem(charId, objectId, windowId, menuId, curMenuLine); + unequipItem(charId, objectId, windowId, menuId, curMenuLine); } } + // Set item as Equipped _npcBuf[charId]._inventory[objectId]._stat1 |= 0x80; } } @@ -906,7 +908,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me bool retVal = false; int16 itemId = _npcBuf[charId]._inventory[objectId]._ref; - switch (_items[itemId].field_16 - 1) { + switch (_items[itemId]._specialEffect - 1) { case 0: // "Demonic Powers", "MindDomination", "Guilt Trip", "Sleep Grenade", "SleepGrenader" if (argA == 2) { displayString_3("The item emits a low droning hum...", false, charId, windowId, menuId, curMenuLine); @@ -917,8 +919,8 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me for (uint counter = 0; counter < 9; ++counter) { if (isMonsterActive(windowId, counter)) { ++victims; - _stru32686[windowId]._field0[counter] = 1; - _stru32686[windowId]._field2[counter] = getRandom(8); + _teamMonsterEffects[windowId]._effect[counter] = 1; + _teamMonsterEffects[windowId]._duration[counter] = getRandom(8); } } } else { @@ -930,8 +932,8 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me if (isMonsterActive(windowId, counter)) { ++victims; --NumberOfTargets; - _stru32686[windowId]._field0[counter] = 1; - _stru32686[windowId]._field2[counter] = getRandom(8); + _teamMonsterEffects[windowId]._effect[counter] = 1; + _teamMonsterEffects[windowId]._duration[counter] = getRandom(8); } } } @@ -956,8 +958,8 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me for (uint varA8 = 0; varA8 < 9; ++varA8) { if (isMonsterActive(windowId, varA8)) { ++victim; - _stru32686[windowId]._field0[varA8] = 2; - _stru32686[windowId]._field2[varA8] = getRandom(8); + _teamMonsterEffects[windowId]._effect[varA8] = 2; + _teamMonsterEffects[windowId]._duration[varA8] = getRandom(8); } } } else { @@ -969,8 +971,8 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me if (isMonsterActive(windowId, varA8)) { ++victim; --varAC; - _stru32686[windowId]._field0[varA8] = 2; - _stru32686[windowId]._field2[varA8] = getRandom(8); + _teamMonsterEffects[windowId]._effect[varA8] = 2; + _teamMonsterEffects[windowId]._duration[varA8] = getRandom(8); } } } From ec7bafa22398cc8ed349b4e7989c7ec0dff906e5 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Fri, 30 Dec 2022 00:00:47 +0100 Subject: [PATCH 202/412] EFH: Renaming, fix bug in sub1BE9A() --- engines/efh/efh.cpp | 55 ++++++++--------- engines/efh/efh.h | 2 +- engines/efh/menu.cpp | 142 +++++++++++++++++++++---------------------- 3 files changed, 99 insertions(+), 100 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index adb3c555071e..4a268d24d373 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -2290,8 +2290,6 @@ void EfhEngine::sub1CAB6(int16 charId) { void EfhEngine::sub1BE9A(int16 monsterId) { debug("sub1BE9A %d", monsterId); - int16 var4 = 1; - // sub1BE9A - 1rst loop counter1_monsterId - Start for (uint counter1 = 0; counter1 < 5; ++counter1) { if (countMonsterGroupMembers(counter1)) @@ -2304,6 +2302,9 @@ void EfhEngine::sub1BE9A(int16 monsterId) { } _teamMonsterIdArray[counter1] = -1; + + // CHECKME: counter1 is not incrementing, which is very, very suspicious as we are copying over and over to the same destination + // if the purpose is compact the array, it should be handle differently for (uint counter2 = counter1 + 1; counter2 < 5; ++counter2) { for (uint var8 = 0; var8 < 9; ++var8) { _teamMonsterEffects[counter1]._effect[var8] = _teamMonsterEffects[counter2]._effect[var8]; @@ -2315,55 +2316,53 @@ void EfhEngine::sub1BE9A(int16 monsterId) { } // sub1BE9A - 1rst loop counter1_monsterId - End - var4 = -1; + int16 teamMonsterId = -1; for (uint counter1 = 0; counter1 < 5; ++counter1) { if (_teamMonsterIdArray[counter1] == -1) { - var4 = counter1; + teamMonsterId = counter1; break; } } - if (var4 != -1) { + if (teamMonsterId != -1) { // sub1BE9A - loop var2 - Start for (int var2 = 1; var2 < 3; ++var2) { - if (var4 >= 5) + if (teamMonsterId >= 5) break; - for (uint counter1 = 0; counter1 < 64; ++counter1) { - if (_mapMonsters[counter1]._guess_fullPlaceId == 0xFF) + for (uint ctrMapMonsterId = 0; ctrMapMonsterId < 64; ++ctrMapMonsterId) { + if (_mapMonsters[ctrMapMonsterId]._guess_fullPlaceId == 0xFF) continue; - if (((_mapMonsters[counter1]._possessivePronounSHL6 & 0x3F) == 0x3F && !isCharacterATeamMember(_mapMonsters[counter1]._npcId)) || (_mapMonsters[counter1]._possessivePronounSHL6 & 0x3F) <= 0x3D) { - if (checkIfMonsterOnSameLargeMapPlace(counter1)) { - bool var6 = false; - for (uint counter2 = 0; counter2 < 9; ++counter2) { - if (_mapMonsters[counter1]._pictureRef[counter2] > 0) { - var6 = true; + if (((_mapMonsters[ctrMapMonsterId]._possessivePronounSHL6 & 0x3F) == 0x3F && !isCharacterATeamMember(_mapMonsters[ctrMapMonsterId]._npcId)) || (_mapMonsters[ctrMapMonsterId]._possessivePronounSHL6 & 0x3F) <= 0x3D) { + if (checkIfMonsterOnSameLargeMapPlace(ctrMapMonsterId)) { + bool monsterActiveFound = false; + for (uint ctrSubId = 0; ctrSubId < 9; ++ctrSubId) { + if (_mapMonsters[ctrMapMonsterId]._pictureRef[ctrSubId] > 0) { + monsterActiveFound = true; break; } } - if (!var6) + if (!monsterActiveFound) continue; - if (computeMonsterGroupDistance(counter1) > var2) + if (computeMonsterGroupDistance(ctrMapMonsterId) > var2) continue; - if (sub1BC74(counter1, var4)) + if (sub1BC74(ctrMapMonsterId, teamMonsterId)) continue; - _teamMonsterIdArray[var4] = counter1; + _teamMonsterIdArray[teamMonsterId] = ctrMapMonsterId; // The original at this point was doing a loop on counter1, which is not a good idea as // it was resetting the counter1 to 9 whatever its value before the loop. - // Furthermore, it was accessing _teamMonsterEffects[counter1]._effect[counter1] which doesn't make - // sense... // I therefore decided to use another counter as it looks like an original misbehavior/bug. - for (uint counter2 = 0; counter2 < 9; ++counter2) { - _teamMonsterEffects[counter1]._effect[counter2] = 0; + for (uint ctrEffectId = 0; ctrEffectId < 9; ++ctrEffectId) { + _teamMonsterEffects[teamMonsterId]._effect[ctrEffectId] = 0; } - if (++var4 >= 5) + if (++teamMonsterId >= 5) break; } } @@ -2372,14 +2371,14 @@ void EfhEngine::sub1BE9A(int16 monsterId) { // sub1BE9A - loop var2 - End } - if (var4 == -1 || var4 > 4) + if (teamMonsterId == -1 || teamMonsterId > 4) return; // sub1BE9A - last loop counter1_monsterId - Start - for (int16 counter1 = var4; counter1 < 5; ++counter1) { - _teamMonsterIdArray[counter1] = -1; - for (uint counter2 = 0; counter2 < 9; ++counter2) { - _teamMonsterEffects[counter1]._effect[counter2] = (int16)0x8000; + for (int16 ctrTeamMonsterId = teamMonsterId; ctrTeamMonsterId < 5; ++ctrTeamMonsterId) { + _teamMonsterIdArray[ctrTeamMonsterId] = -1; + for (uint ctrEffectId = 0; ctrEffectId < 9; ++ctrEffectId) { + _teamMonsterEffects[ctrTeamMonsterId]._effect[ctrEffectId] = (int16)0x8000; } } // sub1BE9A - last loop counter1_monsterId - End diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 02b020b4c06a..a03df2a9b19a 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -464,7 +464,7 @@ class EfhEngine : public Engine { int16 handleStatusMenu(int16 gameMode, int16 charId); void unequipItem(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine); void sub191FF(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine); - int16 sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine, int16 argA); + int16 sub19E2E(int16 charId, int16 objectId, int16 teamMonsterId, int16 menuId, int16 curMenuLine, int16 argA); // Savegames void synchronize(Common::Serializer &s); diff --git a/engines/efh/menu.cpp b/engines/efh/menu.cpp index b6ea94c1cbb8..6950fed3b5f3 100644 --- a/engines/efh/menu.cpp +++ b/engines/efh/menu.cpp @@ -899,8 +899,8 @@ void EfhEngine::sub191FF(int16 charId, int16 objectId, int16 windowId, int16 men } } -int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine, int16 argA) { - debug("sub19E2E %d %d %d %d %d %d", charId, objectId, windowId, menuId, curMenuLine, argA); +int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 teamMonsterId, int16 menuId, int16 curMenuLine, int16 argA) { + debug("sub19E2E %d %d %d %d %d %d", charId, objectId, teamMonsterId, menuId, curMenuLine, argA); Common::String buffer1 = ""; @@ -911,37 +911,37 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me switch (_items[itemId]._specialEffect - 1) { case 0: // "Demonic Powers", "MindDomination", "Guilt Trip", "Sleep Grenade", "SleepGrenader" if (argA == 2) { - displayString_3("The item emits a low droning hum...", false, charId, windowId, menuId, curMenuLine); + displayString_3("The item emits a low droning hum...", false, charId, teamMonsterId, menuId, curMenuLine); } else { int16 victims = 0; _messageToBePrinted += " The item emits a low droning hum..."; if (getRandom(100) < 50) { - for (uint counter = 0; counter < 9; ++counter) { - if (isMonsterActive(windowId, counter)) { + for (uint ctrEffectId = 0; ctrEffectId < 9; ++ctrEffectId) { + if (isMonsterActive(teamMonsterId, ctrEffectId)) { ++victims; - _teamMonsterEffects[windowId]._effect[counter] = 1; - _teamMonsterEffects[windowId]._duration[counter] = getRandom(8); + _teamMonsterEffects[teamMonsterId]._effect[ctrEffectId] = 1; + _teamMonsterEffects[teamMonsterId]._duration[ctrEffectId] = getRandom(8); } } } else { int16 NumberOfTargets = getRandom(9); - for (uint counter = 0; counter < 9; ++counter) { + for (uint ctrEffectId = 0; ctrEffectId < 9; ++ctrEffectId) { if (NumberOfTargets == 0) break; - if (isMonsterActive(windowId, counter)) { + if (isMonsterActive(teamMonsterId, ctrEffectId)) { ++victims; --NumberOfTargets; - _teamMonsterEffects[windowId]._effect[counter] = 1; - _teamMonsterEffects[windowId]._duration[counter] = getRandom(8); + _teamMonsterEffects[teamMonsterId]._effect[ctrEffectId] = 1; + _teamMonsterEffects[teamMonsterId]._duration[ctrEffectId] = getRandom(8); } } } // The original was duplicating this code in each branch of the previous random check. if (victims > 1) { - buffer1 = Common::String::format("%d %ss fall asleep!", victims, kEncounters[_mapMonsters[_teamMonsterIdArray[windowId]]._monsterRef]._name); + buffer1 = Common::String::format("%d %ss fall asleep!", victims, kEncounters[_mapMonsters[_teamMonsterIdArray[teamMonsterId]]._monsterRef]._name); } else { - buffer1 = Common::String::format("%d %s falls asleep!", victims, kEncounters[_mapMonsters[_teamMonsterIdArray[windowId]]._monsterRef]._name); + buffer1 = Common::String::format("%d %s falls asleep!", victims, kEncounters[_mapMonsters[_teamMonsterIdArray[teamMonsterId]]._monsterRef]._name); } _messageToBePrinted += buffer1; } @@ -950,38 +950,38 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me break; case 1: // "Chilling Touch", "Guilt", "Petrify Rod", "Elmer's Gun" if (argA == 2) { - displayString_3("The item grows very cold for a moment...", false, charId, windowId, menuId, curMenuLine); + displayString_3("The item grows very cold for a moment...", false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += " The item emits a blue beam..."; int16 victim = 0; if (getRandom(100) < 50) { - for (uint varA8 = 0; varA8 < 9; ++varA8) { - if (isMonsterActive(windowId, varA8)) { + for (uint ctrEffectId = 0; ctrEffectId < 9; ++ctrEffectId) { + if (isMonsterActive(teamMonsterId, ctrEffectId)) { ++victim; - _teamMonsterEffects[windowId]._effect[varA8] = 2; - _teamMonsterEffects[windowId]._duration[varA8] = getRandom(8); + _teamMonsterEffects[teamMonsterId]._effect[ctrEffectId] = 2; + _teamMonsterEffects[teamMonsterId]._duration[ctrEffectId] = getRandom(8); } } } else { int16 varAC = getRandom(9); - for (uint varA8 = 0; varA8 < 9; ++varA8) { + for (uint ctrEffectId = 0; ctrEffectId < 9; ++ctrEffectId) { if (varAC == 0) break; - if (isMonsterActive(windowId, varA8)) { + if (isMonsterActive(teamMonsterId, ctrEffectId)) { ++victim; --varAC; - _teamMonsterEffects[windowId]._effect[varA8] = 2; - _teamMonsterEffects[windowId]._duration[varA8] = getRandom(8); + _teamMonsterEffects[teamMonsterId]._effect[ctrEffectId] = 2; + _teamMonsterEffects[teamMonsterId]._duration[ctrEffectId] = getRandom(8); } } } // : This part is only present in the original in the case < 50, but for me // it's missing in the other case as there's an effect (frozen enemies) but no feedback to the player if (victim > 1) { - buffer1 = Common::String::format("%d %ss are frozen in place!", victim, kEncounters[_mapMonsters[_teamMonsterIdArray[windowId]]._monsterRef]._name); + buffer1 = Common::String::format("%d %ss are frozen in place!", victim, kEncounters[_mapMonsters[_teamMonsterIdArray[teamMonsterId]]._monsterRef]._name); } else { - buffer1 = Common::String::format("%d %s is frozen in place!", victim, kEncounters[_mapMonsters[_teamMonsterIdArray[windowId]]._monsterRef]._name); + buffer1 = Common::String::format("%d %s is frozen in place!", victim, kEncounters[_mapMonsters[_teamMonsterIdArray[teamMonsterId]]._monsterRef]._name); } _messageToBePrinted += buffer1; // @@ -991,7 +991,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me break; case 2: if (argA == 2) { - displayString_3("A serene feeling passes through the air...", false, charId, windowId, menuId, curMenuLine); + displayString_3("A serene feeling passes through the air...", false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += " The combat pauses...as there is a moment of forgiveness..."; _unk2C8AA = 0; @@ -1001,20 +1001,20 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me break; case 4: // "Unholy Sinwave", "Holy Water" if (argA == 2) { - displayString_3("A dark sense fills your soul...then fades!", false, charId, windowId, menuId, curMenuLine); + displayString_3("A dark sense fills your soul...then fades!", false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += " A dark gray fiery whirlwind surrounds the poor victim...the power fades and death abounds!"; if (getRandom(100) < 50) { for (uint counter = 0; counter < 9; ++counter) { if (getRandom(100) < 50) { - _mapMonsters[_teamMonsterIdArray[windowId]]._pictureRef[counter] = 0; + _mapMonsters[_teamMonsterIdArray[teamMonsterId]]._pictureRef[counter] = 0; } } } else { for (uint counter = 0; counter < 9; ++counter) { - if (isMonsterActive(windowId, counter)) { + if (isMonsterActive(teamMonsterId, counter)) { if (getRandom(100) < 50) { - _mapMonsters[_teamMonsterIdArray[windowId]]._pictureRef[counter] = 0; + _mapMonsters[_teamMonsterIdArray[teamMonsterId]]._pictureRef[counter] = 0; } break; } @@ -1025,18 +1025,18 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me break; case 5: // "Lucifer'sTouch", "Book of Death", "Holy Cross" if (argA == 2) { - displayString_3("A dark sense fills your soul...then fades!", false, charId, windowId, menuId, curMenuLine); + displayString_3("A dark sense fills your soul...then fades!", false, charId, teamMonsterId, menuId, curMenuLine); } else { if (getRandom(100) < 50) { _messageToBePrinted += " A dark fiery whirlwind surrounds the poor victim...the power fades and all targeted die!"; for (uint counter = 0; counter < 9; ++counter) { - _mapMonsters[_teamMonsterIdArray[windowId]]._pictureRef[counter] = 0; + _mapMonsters[_teamMonsterIdArray[teamMonsterId]]._pictureRef[counter] = 0; } } else { _messageToBePrinted += " A dark fiery whirlwind surrounds the poor victim...the power fades and one victim dies!"; for (uint counter = 0; counter < 9; ++counter) { - if (isMonsterActive(windowId, counter)) { - _mapMonsters[_teamMonsterIdArray[windowId]]._pictureRef[counter] = 0; + if (isMonsterActive(teamMonsterId, counter)) { + _mapMonsters[_teamMonsterIdArray[teamMonsterId]]._pictureRef[counter] = 0; } } } @@ -1046,26 +1046,26 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me break; case 12: // "Terror Gaze", "Servitude Rod", "Despair Ankh", "ConfusionPrism", "Pipe of Peace", "Red Cape", "Peace Symbol", "Hell Badge" if (argA == 2) { - displayString_3("There is no apparent affect!", false, charId, windowId, menuId, curMenuLine); + displayString_3("There is no apparent affect!", false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += " The magic sparkles brilliant hues in the air!"; - setMapMonsterField8(windowId, _items[itemId].field17_attackTypeDefense, true); + setMapMonsterField8(teamMonsterId, _items[itemId].field17_attackTypeDefense, true); } varA6 = true; break; case 14: { // "Feathered Cap" int16 varAA; if (argA == 2) { - displayString_3("Who will use the item?", false, charId, windowId, menuId, curMenuLine); + displayString_3("Who will use the item?", false, charId, teamMonsterId, menuId, curMenuLine); varAA = selectOtherCharFromTeam(); } else { - varAA = windowId; + varAA = teamMonsterId; } if (varAA != 0x1B) { buffer1 = " The magic makes the user as quick and agile as a bird!"; if (argA == 2) { - displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + displayString_3(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; } @@ -1079,16 +1079,16 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me case 15: { // "Regal Crown" int16 teamCharId; if (argA == 2) { - displayString_3("Who will use the item?", false, charId, windowId, menuId, curMenuLine); + displayString_3("Who will use the item?", false, charId, teamMonsterId, menuId, curMenuLine); teamCharId = selectOtherCharFromTeam(); } else { - teamCharId = windowId; + teamCharId = teamMonsterId; } if (teamCharId != 0x1B) { buffer1 = " The magic makes the user invisible!"; if (argA == 2) { - displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + displayString_3(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; } @@ -1109,7 +1109,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me totalPartyKill(); buffer1 = "The entire party vanishes in a flash... only to appear in stone !"; if (argA == 2) { - displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + displayString_3(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; retVal = true; @@ -1118,7 +1118,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me if (tileFactId == 0 || tileFactId == 0x48) { buffer1 = "The entire party vanishes in a flash...but re-appears, as if nothing happened!"; if (argA == 2) { - displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + displayString_3(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; retVal = true; @@ -1126,7 +1126,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me } else { buffer1 = "The entire party vanishes in a flash...only to appear elsewhere!"; if (argA == 2) { - displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + displayString_3(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; retVal = true; @@ -1144,7 +1144,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me totalPartyKill(); buffer1 = "The entire party vanishes in a flash... only to appear in stone !"; if (argA == 2) { - displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + displayString_3(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; retVal = true; @@ -1153,7 +1153,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me if (tileFactId == 0 || tileFactId == 0x48) { buffer1 = "The entire party vanishes in a flash...but re-appears, as if nothing happened!"; if (argA == 2) { - displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + displayString_3(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; retVal = true; @@ -1161,7 +1161,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me } else { buffer1 = "The entire party vanishes in a flash...only to appear elsewhere!"; if (argA == 2) { - displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + displayString_3(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; retVal = true; @@ -1173,9 +1173,9 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me } break; case 18: if (argA == 2) { - displayString_3("The item makes a loud noise!", false, charId, windowId, menuId, curMenuLine); + displayString_3("The item makes a loud noise!", false, charId, teamMonsterId, menuId, curMenuLine); } else { - int16 teamCharId = windowId; + int16 teamCharId = teamMonsterId; if (teamCharId != 0x1B) { if (_teamCharStatus[teamCharId]._status == 2) { // frozen _messageToBePrinted += " The item makes a loud noise, awakening the character!"; @@ -1192,7 +1192,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me case 19: // "Junk" buffer1 = " * The item breaks!"; if (argA == 2) { - displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + displayString_3(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; } @@ -1228,7 +1228,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me } buffer1 += "'"; if (argA == 2) { - displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + displayString_3(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; retVal = true; @@ -1239,10 +1239,10 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me case 24: { int16 teamCharId; if (argA == 2) { - displayString_3("Who will use this item?", false, charId, windowId, menuId, curMenuLine); + displayString_3("Who will use this item?", false, charId, teamMonsterId, menuId, curMenuLine); teamCharId = selectOtherCharFromTeam(); } else - teamCharId = windowId; + teamCharId = teamMonsterId; if (teamCharId != 0x1B) { uint8 varAE = _items[itemId].field17_attackTypeDefense; @@ -1257,7 +1257,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me buffer1 = Common::String::format("%s increased 1 point!", kSkillArray[varAE]); if (argA == 2) { - displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + displayString_3(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; retVal = true; @@ -1269,10 +1269,10 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me case 25: { int16 teamCharId; if (argA == 2) { - displayString_3("Who will use this item?", false, charId, windowId, menuId, curMenuLine); + displayString_3("Who will use this item?", false, charId, teamMonsterId, menuId, curMenuLine); teamCharId = selectOtherCharFromTeam(); } else - teamCharId = windowId; + teamCharId = teamMonsterId; if (teamCharId != 0x1B) { uint8 varAE = _items[itemId].field17_attackTypeDefense; @@ -1287,7 +1287,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me buffer1 = Common::String::format("%s lowered 1 point!", kSkillArray[varAE]); if (argA == 2) { - displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + displayString_3(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; retVal = true; @@ -1299,7 +1299,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me case 26: // "Black Sphere" buffer1 = "The entire party collapses, dead!!!"; if (argA == 2) { - displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + displayString_3(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; retVal = true; @@ -1310,17 +1310,17 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me case 27: { // "Magic Pyramid", "Razor Blade" int16 teamCharId; if (argA == 2) { - displayString_3("Who will use the item?", false, charId, windowId, menuId, curMenuLine); + displayString_3("Who will use the item?", false, charId, teamMonsterId, menuId, curMenuLine); teamCharId = selectOtherCharFromTeam(); } else { - teamCharId = windowId; + teamCharId = teamMonsterId; } if (teamCharId != 0x1B) { _npcBuf[_teamCharId[teamCharId]]._hitPoints = 0; buffer1 = Common::String::format("%s collapses, dead!!!", _npcBuf[_teamCharId[teamCharId]]._name); if (argA == 2) { - displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + displayString_3(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; retVal = true; @@ -1331,9 +1331,9 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me } break; case 28: // "Bugle" if (argA == 2) { - displayString_3("The item makes a loud noise!", false, charId, windowId, menuId, curMenuLine); + displayString_3("The item makes a loud noise!", false, charId, teamMonsterId, menuId, curMenuLine); } else { - int16 teamCharId = windowId; + int16 teamCharId = teamMonsterId; if (teamCharId != 0x1B) { if (_teamCharStatus[teamCharId]._status == 0) { _messageToBePrinted += " The item makes a loud noise, awakening the character!"; @@ -1350,10 +1350,10 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me case 29: { // "Healing Spray", "Healing Elixir", "Curing Potion", "Magic Potion" int16 teamCharId; if (argA == 2) { - displayString_3("Who will use the item?", false, charId, windowId, menuId, curMenuLine); + displayString_3("Who will use the item?", false, charId, teamMonsterId, menuId, curMenuLine); teamCharId = selectOtherCharFromTeam(); } else { - teamCharId = windowId; + teamCharId = teamMonsterId; } if (teamCharId != 0x1B) { @@ -1369,7 +1369,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me } if (argA == 2) { - displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + displayString_3(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; retVal = true; @@ -1380,10 +1380,10 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me case 30: { int16 teamCharId; if (argA == 2) { - displayString_3("Who will use the item?", false, charId, windowId, menuId, curMenuLine); + displayString_3("Who will use the item?", false, charId, teamMonsterId, menuId, curMenuLine); teamCharId = selectOtherCharFromTeam(); } else { - teamCharId = windowId; + teamCharId = teamMonsterId; } if (teamCharId != 0x1B) { @@ -1399,7 +1399,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me } if (argA == 2) { - displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + displayString_3(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; retVal = true; @@ -1430,7 +1430,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me buffer1 = " * The item breaks!"; if (argA == 2) { getLastCharAfterAnimCount(_guessAnimationAmount); - displayString_3(buffer1, false, charId, windowId, menuId, curMenuLine); + displayString_3(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; } @@ -1443,7 +1443,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 windowId, int16 me if (argA == 2) { getLastCharAfterAnimCount(_guessAnimationAmount); - sub18E80(charId, windowId, menuId, curMenuLine); + sub18E80(charId, teamMonsterId, menuId, curMenuLine); } } From 88ad3db32d9e67ef84e69759413b7a403c2b4076 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Fri, 30 Dec 2022 00:18:25 +0100 Subject: [PATCH 203/412] EFH: Review giveItemTo(), renaming + fix a bug in handleStatusMenu() --- engines/efh/efh.cpp | 4 ++-- engines/efh/menu.cpp | 29 +++++++++++++++-------------- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 4a268d24d373..7626903f103d 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -920,7 +920,7 @@ void EfhEngine::handleWinSequence() { } bool EfhEngine::giveItemTo(int16 charId, int16 objectId, int16 altCharId) { - debug("giveItemTo %d %d %d", charId, objectId, altCharId); + debugC(3, kDebugEngine, "giveItemTo %d %d %d", charId, objectId, altCharId); for (uint newObjectId = 0; newObjectId < 10; ++newObjectId) { if (_npcBuf[charId]._inventory[newObjectId]._ref != 0x7FFF) @@ -933,7 +933,7 @@ bool EfhEngine::giveItemTo(int16 charId, int16 objectId, int16 altCharId) { } else { _npcBuf[charId]._inventory[newObjectId]._ref = _npcBuf[altCharId]._inventory[newObjectId]._ref; _npcBuf[charId]._inventory[newObjectId]._stat2 = _npcBuf[altCharId]._inventory[newObjectId]._stat2; - _npcBuf[charId]._inventory[newObjectId]._stat1 = _npcBuf[altCharId]._inventory[newObjectId]._stat1 & 0x7F; + _npcBuf[charId]._inventory[newObjectId]._stat1 = _npcBuf[altCharId]._inventory[newObjectId]._stat1 & 0x7F; // not equipped as the upper bit isn't set (0x80) } return true; diff --git a/engines/efh/menu.cpp b/engines/efh/menu.cpp index 6950fed3b5f3..f0bb55f25dfb 100644 --- a/engines/efh/menu.cpp +++ b/engines/efh/menu.cpp @@ -734,40 +734,41 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { sub18E80(charId, windowId, menuId, curMenuLine); if (validationFl) { - bool var6; - int16 var8; + bool givenFl; + int16 destCharId; do { if (_teamCharId[2] != -1) { - var8 = displayString_3("Who will you give the item to?", false, charId, windowId, menuId, curMenuLine); + displayString_3("Who will you give the item to?", false, charId, windowId, menuId, curMenuLine); + destCharId = selectOtherCharFromTeam(); var2 = false; } else if (_teamCharId[1]) { - var8 = 0x1A; + destCharId = 0x1A; var2 = false; } else { var2 = true; if (_teamCharId[0] == charId) - var8 = 1; + destCharId = 1; else - var8 = 0; + destCharId = 0; } - if (var8 != 0x1A && var8 != 0x1B) { - var6 = giveItemTo(_teamCharId[var8], objectId, charId); - if (!var6) { + if (destCharId != 0x1A && destCharId != 0x1B) { + givenFl = giveItemTo(_teamCharId[destCharId], objectId, charId); + if (!givenFl) { displayString_3("That character cannot carry anymore!", false, charId, windowId, menuId, curMenuLine); getLastCharAfterAnimCount(_guessAnimationAmount); } } else { - if (var8 == 0x1A) { + if (destCharId == 0x1A) { displayString_3("No one to trade with!", false, charId, windowId, menuId, curMenuLine); getLastCharAfterAnimCount(_guessAnimationAmount); - var8 = 0x1B; + destCharId = 0x1B; } - var6 = false; + givenFl = false; } - } while (!var6 && !var2 && var8 != 0x1B); + } while (!givenFl && !var2 && destCharId != 0x1B); - if (var6) { + if (givenFl) { removeObject(charId, objectId); if (gameMode == 2) { restoreAnimImageSetId(); From 4a9ac53f03c226dbd47b465118ff0b8451aa4705 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Fri, 30 Dec 2022 10:45:06 +0100 Subject: [PATCH 204/412] EFH: Validate some more functions, more renaming --- engines/efh/efh.cpp | 54 ++++++++++++++++----------------- engines/efh/efh.h | 12 ++++---- engines/efh/fight.cpp | 68 +++++++++++++++++++++--------------------- engines/efh/menu.cpp | 8 ++--- engines/efh/script.cpp | 6 ++-- 5 files changed, 72 insertions(+), 76 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 7626903f103d..29d444725cc8 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -447,7 +447,7 @@ void EfhEngine::initMapMonsters() { continue; for (uint counter = 0; counter < 9; ++counter) - _mapMonsters[monsterId]._pictureRef[counter] = 0; + _mapMonsters[monsterId]._hitPoints[counter] = 0; uint8 groupSize = _mapMonsters[monsterId]._groupSize; if (groupSize == 0) @@ -462,12 +462,12 @@ void EfhEngine::initMapMonsters() { if (rand100 <= 25) { uint16 delta = getRandom(pictureRef / 2); - _mapMonsters[monsterId]._pictureRef[counter] = pictureRef - delta; + _mapMonsters[monsterId]._hitPoints[counter] = pictureRef - delta; } else if (rand100 <= 75) { - _mapMonsters[monsterId]._pictureRef[counter] = pictureRef; + _mapMonsters[monsterId]._hitPoints[counter] = pictureRef; } else { uint16 delta = getRandom(pictureRef / 2); - _mapMonsters[monsterId]._pictureRef[counter] = pictureRef + delta; + _mapMonsters[monsterId]._hitPoints[counter] = pictureRef + delta; } } } @@ -503,7 +503,7 @@ void EfhEngine::loadMapArrays(int idx) { _mapMonsters[i]._field9_textId = mapMonstersPtr[29 * i + 9]; _mapMonsters[i]._groupSize = mapMonstersPtr[29 * i + 10]; for (int j = 0; j < 9; ++j) - _mapMonsters[i]._pictureRef[j] = READ_LE_INT16(&mapMonstersPtr[29 * i + 11 + j * 2]); + _mapMonsters[i]._hitPoints[j] = READ_LE_INT16(&mapMonstersPtr[29 * i + 11 + j * 2]); } uint8 *mapPtr = &_mapArr[idx][2758]; @@ -667,7 +667,7 @@ void EfhEngine::drawMap(bool largeMapFl, int16 mapPosX, int16 mapPosY, int16 map continue; for (uint counterY = 0; counterY < 9 && !var4; ++counterY) { - if (_mapMonsters[var16]._pictureRef[counterY] > 0) + if (_mapMonsters[var16]._hitPoints[counterY] > 0) var4 = true; } @@ -677,7 +677,7 @@ void EfhEngine::drawMap(bool largeMapFl, int16 mapPosX, int16 mapPosY, int16 map int16 var6 = 148 + kEncounters[_mapMonsters[var16]._monsterRef]._animId; int16 var1 = _mapMonsters[var16]._possessivePronounSHL6 & 0x3F; - if (var1 == 0x3F && isCharacterATeamMember(_mapMonsters[var16]._npcId)) + if (var1 == 0x3F && isNpcATeamMember(_mapMonsters[var16]._npcId)) continue; int16 drawPosX = 128 + (posX - minX) * 16; @@ -826,8 +826,8 @@ void EfhEngine::refreshTeamSize() { } } -bool EfhEngine::isCharacterATeamMember(int16 id) { - debugC(6, kDebugEngine,"isCharacterATeamMember %d", id); +bool EfhEngine::isNpcATeamMember(int16 id) { + debugC(6, kDebugEngine,"isNpcATeamMember %d", id); for (int counter = 0; counter < _teamSize; ++counter) { if (_teamCharId[counter] == id) @@ -1753,7 +1753,7 @@ bool EfhEngine::checkPictureRefAvailability(int16 monsterId) { return false; for (uint counter = 0; counter < 9; ++counter) { - if (_mapMonsters[monsterId]._pictureRef[counter] > 0) + if (_mapMonsters[monsterId]._hitPoints[counter] > 0) return true; } @@ -1767,19 +1767,15 @@ void EfhEngine::displayMonsterAnim(int16 monsterId) { displayAnimFrames(animId, true); } -int16 EfhEngine::countPictureRef(int16 id, bool teamMemberFl) { - debug("countPictureRef %d %s", id, teamMemberFl ? "True" : "False"); +// The original is using an additional bool parameter which was only passed as 'False'. +// It has been removed as well as the associated code +int16 EfhEngine::countAliveMonsters(int16 id) { + debugC(6, kDebugEngine, "countAliveMonsters %d", id); int16 count = 0; - int16 monsterId; - - if (teamMemberFl) - monsterId = _teamMonsterIdArray[id]; - else - monsterId = id; for (uint counter = 0; counter < 9; ++counter) { - if (_mapMonsters[monsterId]._pictureRef[counter] > 0) + if (_mapMonsters[id]._hitPoints[counter] > 0) ++count; } @@ -1787,7 +1783,7 @@ int16 EfhEngine::countPictureRef(int16 id, bool teamMemberFl) { } bool EfhEngine::checkMonsterGroupDistance1OrLess(int16 monsterId) { - debug("checkMonsterGroupDistance1OrLess %d", monsterId); + debugC(6,kDebugEngine, "checkMonsterGroupDistance1OrLess %d", monsterId); if (computeMonsterGroupDistance(monsterId) > 1) return false; @@ -1802,7 +1798,7 @@ bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { if (_mapMonsters[monsterId]._guess_fullPlaceId == 0xFF) return false; - if (countPictureRef(monsterId, false) < 1) + if (countAliveMonsters(monsterId) < 1) return false; if (!checkIfMonsterOnSameLargeMapPlace(monsterId)) @@ -1821,7 +1817,7 @@ bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { return true; } - if (isCharacterATeamMember(_mapMonsters[monsterId]._npcId)) + if (isNpcATeamMember(_mapMonsters[monsterId]._npcId)) return false; int16 npcId = _mapMonsters[monsterId]._npcId; @@ -2296,7 +2292,7 @@ void EfhEngine::sub1BE9A(int16 monsterId) { continue; for (uint counter2 = 0; counter2 < 9; ++counter2) { - _mapMonsters[_teamMonsterIdArray[counter1]]._pictureRef[counter2] = 0; + _mapMonsters[_teamMonsterIdArray[counter1]]._hitPoints[counter2] = 0; _teamMonsterEffects[counter1]._effect[counter2] = 0; _teamMonsterEffects[counter1]._duration[counter2] = 0; } @@ -2334,11 +2330,11 @@ void EfhEngine::sub1BE9A(int16 monsterId) { if (_mapMonsters[ctrMapMonsterId]._guess_fullPlaceId == 0xFF) continue; - if (((_mapMonsters[ctrMapMonsterId]._possessivePronounSHL6 & 0x3F) == 0x3F && !isCharacterATeamMember(_mapMonsters[ctrMapMonsterId]._npcId)) || (_mapMonsters[ctrMapMonsterId]._possessivePronounSHL6 & 0x3F) <= 0x3D) { + if (((_mapMonsters[ctrMapMonsterId]._possessivePronounSHL6 & 0x3F) == 0x3F && !isNpcATeamMember(_mapMonsters[ctrMapMonsterId]._npcId)) || (_mapMonsters[ctrMapMonsterId]._possessivePronounSHL6 & 0x3F) <= 0x3D) { if (checkIfMonsterOnSameLargeMapPlace(ctrMapMonsterId)) { bool monsterActiveFound = false; for (uint ctrSubId = 0; ctrSubId < 9; ++ctrSubId) { - if (_mapMonsters[ctrMapMonsterId]._pictureRef[ctrSubId] > 0) { + if (_mapMonsters[ctrMapMonsterId]._hitPoints[ctrSubId] > 0) { monsterActiveFound = true; break; } @@ -2350,7 +2346,7 @@ void EfhEngine::sub1BE9A(int16 monsterId) { if (computeMonsterGroupDistance(ctrMapMonsterId) > var2) continue; - if (sub1BC74(ctrMapMonsterId, teamMonsterId)) + if (isMonsterAlreadyFighting(ctrMapMonsterId, teamMonsterId)) continue; _teamMonsterIdArray[teamMonsterId] = ctrMapMonsterId; @@ -2522,7 +2518,7 @@ void EfhEngine::setMapMonsterField8(int16 id, uint8 movementType, bool groupFl) bool EfhEngine::isMonsterActive(int16 groupId, int16 id) { debugC(5, kDebugEngine, "isMonsterActive %d %d", groupId, id); - if (_mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[id] > 0 && _teamMonsterEffects[groupId]._effect[id] == 0) + if (_mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[id] > 0 && _teamMonsterEffects[groupId]._effect[id] == 0) return true; return false; } @@ -2573,7 +2569,7 @@ bool EfhEngine::checkMonsterCollision() { continue; if ((_mapMonsters[monsterId]._possessivePronounSHL6 & 0x3F) > 0x3D - && !(((_mapMonsters[monsterId]._possessivePronounSHL6 & 0x3F) == 0x3F) && !isCharacterATeamMember(_mapMonsters[monsterId]._npcId))) + && !(((_mapMonsters[monsterId]._possessivePronounSHL6 & 0x3F) == 0x3F) && !isNpcATeamMember(_mapMonsters[monsterId]._npcId))) continue; if (_mapMonsters[monsterId]._posX != _mapPosX || _mapMonsters[monsterId]._posY != _mapPosY) @@ -2587,7 +2583,7 @@ bool EfhEngine::checkMonsterCollision() { int16 var6A = 0; for (uint var6C = 0; var6C < 9; ++var6C) { - if (_mapMonsters[monsterId]._pictureRef[var6C]) + if (_mapMonsters[monsterId]._hitPoints[var6C]) ++var6A; } diff --git a/engines/efh/efh.h b/engines/efh/efh.h index a03df2a9b19a..c24cc3c3c2f0 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -214,7 +214,7 @@ struct MapMonster { uint8 _moveInfo; // abbb cccc a: special move flag, bbb: Pct modifier for random move, cccc movement type uint8 _field9_textId; uint8 _groupSize; - int16 _pictureRef[9]; + int16 _hitPoints[9]; }; struct Stru32686 { @@ -308,7 +308,7 @@ class EfhEngine : public Engine { void totalPartyKill(); void removeCharacterFromTeam(int16 teamMemberId); void refreshTeamSize(); - bool isCharacterATeamMember(int16 id); + bool isNpcATeamMember(int16 id); void handleWinSequence(); bool giveItemTo(int16 charId, int16 objectId, int16 altCharId); int16 chooseCharacterToReplace(); @@ -345,7 +345,7 @@ class EfhEngine : public Engine { void handleMapMonsterMoves(); bool checkPictureRefAvailability(int16 monsterId); void displayMonsterAnim(int16 monsterId); - int16 countPictureRef(int16 id, bool teamMemberFl); + int16 countAliveMonsters(int16 id); bool checkMonsterGroupDistance1OrLess(int16 monsterId); bool sub21820(int16 monsterId, int16 arg2, int16 itemId); void sub221D2(int16 monsterId); @@ -378,9 +378,9 @@ class EfhEngine : public Engine { void handleFight_lastAction_H(int16 teamCharId); void handleFight_lastAction_U(int16 teamCharId); bool isTPK(); - bool sub1BC74(int16 monsterId, int16 teamMonsterId); - void sub1BCA7(int16 monsterTeamId); - void reset_stru32686(); + bool isMonsterAlreadyFighting(int16 monsterId, int16 teamMonsterId); + void createOpponentList(int16 monsterTeamId); + void resetTeamMonsterEffects(); void sub1BE89(int16 monsterId); void resetTeamMonsterIdArray(); bool isTeamMemberStatusNormal(int16 id); diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index 98a94f637380..a7504082dc8b 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -23,11 +23,11 @@ namespace Efh { -void EfhEngine::sub1BCA7(int16 monsterTeamId) { - debug("sub1BCA7 %d", monsterTeamId); +void EfhEngine::createOpponentList(int16 monsterTeamId) { + debugC(3, kDebugEngine, "createOpponentList %d", monsterTeamId); int16 counter = 0; - if (monsterTeamId != -1 && countPictureRef(monsterTeamId, false) > 0) { + if (monsterTeamId != -1 && countAliveMonsters(monsterTeamId) > 0) { counter = 1; _teamMonsterIdArray[0] = monsterTeamId; } @@ -40,22 +40,22 @@ void EfhEngine::sub1BCA7(int16 monsterTeamId) { if (_mapMonsters[monsterId]._guess_fullPlaceId == 0xFF) continue; - if (((_mapMonsters[monsterId]._possessivePronounSHL6 & 0x3F) != 0x3F || isCharacterATeamMember(_mapMonsters[monsterId]._npcId)) && (_mapMonsters[monsterId]._possessivePronounSHL6 & 0x3F) > 0x3D) + if (((_mapMonsters[monsterId]._possessivePronounSHL6 & 0x3F) != 0x3F || isNpcATeamMember(_mapMonsters[monsterId]._npcId)) && (_mapMonsters[monsterId]._possessivePronounSHL6 & 0x3F) > 0x3D) continue; if (!checkIfMonsterOnSameLargeMapPlace(monsterId)) continue; bool found = false; - for (uint counter3 = 0; counter3 < 9; ++counter3) { - if (_mapMonsters[monsterId]._pictureRef[counter3] > 0) { + for (uint subId = 0; subId < 9; ++subId) { + if (_mapMonsters[monsterId]._hitPoints[subId] > 0) { found = true; break; } } if (found) { - if (computeMonsterGroupDistance(monsterId) <= counter2 && !sub1BC74(monsterId, counter)) { + if (computeMonsterGroupDistance(monsterId) <= counter2 && !isMonsterAlreadyFighting(monsterId, counter)) { _teamMonsterIdArray[counter] = monsterId; if (++counter >= 5) break; @@ -73,8 +73,8 @@ void EfhEngine::sub1BCA7(int16 monsterTeamId) { void EfhEngine::sub1BE89(int16 monsterId) { debug("sub1BE89 %d", monsterId); - sub1BCA7(monsterId); - reset_stru32686(); + createOpponentList(monsterId); + resetTeamMonsterEffects(); } bool EfhEngine::handleFight(int16 monsterId) { @@ -337,7 +337,7 @@ bool EfhEngine::handleFight(int16 monsterId) { } // handleFight - Loop on var7E - End } - } else if (_mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._pictureRef[var86] > 0 && _teamMonsterEffects[monsterGroupIdOrMonsterId]._effect[var86]) { + } else if (_mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._hitPoints[var86] > 0 && _teamMonsterEffects[monsterGroupIdOrMonsterId]._effect[var86]) { --_teamMonsterEffects[monsterGroupIdOrMonsterId]._duration[var86]; if (_teamMonsterEffects[monsterGroupIdOrMonsterId]._duration[var86] <= 0) { _enemyNamePt2 = kEncounters[_mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._monsterRef]._name; @@ -470,7 +470,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { varInt = _teamMonsterIdArray[groupId]; int16 var5E = kEncounters[_mapMonsters[varInt]._monsterRef]._nameArticle; int16 charScore = getCharacterScore(_teamCharId[teamCharId], unk_monsterField5_itemId); - int16 var80 = _mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E]; + int16 hitPointsBefore = _mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[var7E]; int16 var62 = 0; int16 originalDamage = 0; int16 damagePointsAbsorbed = 0; @@ -503,7 +503,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { var62 = 0; if (var62 > 0) { - _mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] -= originalDamage; + _mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[var7E] -= originalDamage; if (var62 > 1) { _attackBuffer = Common::String::format("%d times ", var62); } else { @@ -535,7 +535,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s, but does no damage!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[var70], _nameBuffer.c_str()); } else if (hitPoints == 1) { _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s for 1 point", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[var70], _nameBuffer.c_str()); - if (_mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] <= 0) { + if (_mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[var7E] <= 0) { getDeathTypeDescription(groupId, teamCharId + 1000); getXPAndSearchCorpse(_teamCharId[teamCharId], _enemyNamePt1, _enemyNamePt2, _teamMonsterIdArray[groupId]); } else { @@ -543,7 +543,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { } } else { _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s for %d points", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[var70], _nameBuffer.c_str(), hitPoints); - if (_mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] <= 0) { + if (_mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[var7E] <= 0) { getDeathTypeDescription(groupId, teamCharId + 1000); getXPAndSearchCorpse(_teamCharId[teamCharId], _enemyNamePt1, _enemyNamePt2, _teamMonsterIdArray[groupId]); } else { @@ -553,19 +553,19 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { // Action A - Check damages - End // Action A - Add reaction text - Start - if (var62 != 0 && originalDamage > 0 && getRandom(100) <= 35 && _mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] > 0) { - if (_mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] - 5 <= originalDamage) { + if (var62 != 0 && originalDamage > 0 && getRandom(100) <= 35 && _mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[var7E] > 0) { + if (_mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[var7E] - 5 <= originalDamage) { addReactionText(0); - } else if (_mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] < var80 / 8) { + } else if (_mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[var7E] < hitPointsBefore / 8) { addReactionText(1); - } else if (_mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] < var80 / 4) { + } else if (_mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[var7E] < hitPointsBefore / 4) { addReactionText(2); - } else if (_mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] < var80 / 2) { + } else if (_mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[var7E] < hitPointsBefore / 2) { addReactionText(3); - } else if (_mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] < var80 / 3) { + } else if (_mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[var7E] < hitPointsBefore / 3) { // CHECKME: Doesn't make any sense to check /3 after /2... I don't get it addReactionText(4); - } else if (var80 / 8 >= originalDamage) { + } else if (hitPointsBefore / 8 >= originalDamage) { addReactionText(5); } else if (originalDamage == 0 && getRandom(100) < 35) { addReactionText(6); @@ -574,7 +574,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { // Action A - Add reaction text - End // Action A - Add armor absorb text - Start - if (var76 && var62 && _mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] > 0) { + if (var76 && var62 && _mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[var7E] > 0) { if (damagePointsAbsorbed <= 1) _messageToBePrinted += Common::String::format(" %s%s's armor absorbs 1 point!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); else @@ -602,13 +602,13 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { // Action A - Check item durability - End // Action A - Check effect - Start - if (_items[unk_monsterField5_itemId]._specialEffect == 1 && _mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] > 0) { + if (_items[unk_monsterField5_itemId]._specialEffect == 1 && _mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[var7E] > 0) { if (getRandom(100) < 35) { _teamMonsterEffects[groupId]._effect[var7E] = 1; _teamMonsterEffects[groupId]._duration[var7E] = getRandom(10); _messageToBePrinted += Common::String::format(" %s%s falls asleep!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); } - } else if (_items[unk_monsterField5_itemId]._specialEffect == 2 && _mapMonsters[_teamMonsterIdArray[groupId]]._pictureRef[var7E] > 0) { + } else if (_items[unk_monsterField5_itemId]._specialEffect == 2 && _mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[var7E] > 0) { _teamMonsterEffects[groupId]._effect[var7E] = 2; _teamMonsterEffects[groupId]._duration[var7E] = getRandom(10); _messageToBePrinted += Common::String::format(" %s%s is frozen!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); @@ -692,8 +692,8 @@ bool EfhEngine::isTPK() { return zeroedChar == _teamSize; } -bool EfhEngine::sub1BC74(int16 monsterId, int16 teamMonsterId) { - debug("sub1BC74 %d %d", monsterId, teamMonsterId); +bool EfhEngine::isMonsterAlreadyFighting(int16 monsterId, int16 teamMonsterId) { + debug("isMonsterAlreadyFighting %d %d", monsterId, teamMonsterId); for (int counter = 0; counter < teamMonsterId; ++counter) { if (_teamMonsterIdArray[counter] == monsterId) @@ -702,12 +702,12 @@ bool EfhEngine::sub1BC74(int16 monsterId, int16 teamMonsterId) { return false; } -void EfhEngine::reset_stru32686() { - debug("reset_stru32686"); - for (uint counter1 = 0; counter1 < 5; ++counter1) { - for (uint counter2 = 0; counter2 < 9; ++counter2) { - _teamMonsterEffects[counter1]._effect[counter2] = 0; - _teamMonsterEffects[counter1]._duration[counter2] = 0; +void EfhEngine::resetTeamMonsterEffects() { + debugC(6, kDebugEngine, "resetTeamMonsterEffects"); + for (uint ctrMonsterId = 0; ctrMonsterId < 5; ++ctrMonsterId) { + for (uint ctrEffectId = 0; ctrEffectId < 9; ++ctrEffectId) { + _teamMonsterEffects[ctrMonsterId]._effect[ctrEffectId] = 0; + _teamMonsterEffects[ctrMonsterId]._duration[ctrEffectId] = 0; } } } @@ -1398,11 +1398,11 @@ int16 EfhEngine::sub1DEC8(int16 groupNumber) { if (!isMonsterActive(groupNumber, counter)) continue; - if (_mapMonsters[monsterId]._pictureRef[var4] > _mapMonsters[monsterId]._pictureRef[counter]) + if (_mapMonsters[monsterId]._hitPoints[var4] > _mapMonsters[monsterId]._hitPoints[counter]) var4 = counter; } - if (_mapMonsters[monsterId]._pictureRef[var4] <= 0) + if (_mapMonsters[monsterId]._hitPoints[var4] <= 0) return -1; return var4; diff --git a/engines/efh/menu.cpp b/engines/efh/menu.cpp index f0bb55f25dfb..43f4610d71b9 100644 --- a/engines/efh/menu.cpp +++ b/engines/efh/menu.cpp @@ -1008,14 +1008,14 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 teamMonsterId, int if (getRandom(100) < 50) { for (uint counter = 0; counter < 9; ++counter) { if (getRandom(100) < 50) { - _mapMonsters[_teamMonsterIdArray[teamMonsterId]]._pictureRef[counter] = 0; + _mapMonsters[_teamMonsterIdArray[teamMonsterId]]._hitPoints[counter] = 0; } } } else { for (uint counter = 0; counter < 9; ++counter) { if (isMonsterActive(teamMonsterId, counter)) { if (getRandom(100) < 50) { - _mapMonsters[_teamMonsterIdArray[teamMonsterId]]._pictureRef[counter] = 0; + _mapMonsters[_teamMonsterIdArray[teamMonsterId]]._hitPoints[counter] = 0; } break; } @@ -1031,13 +1031,13 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 teamMonsterId, int if (getRandom(100) < 50) { _messageToBePrinted += " A dark fiery whirlwind surrounds the poor victim...the power fades and all targeted die!"; for (uint counter = 0; counter < 9; ++counter) { - _mapMonsters[_teamMonsterIdArray[teamMonsterId]]._pictureRef[counter] = 0; + _mapMonsters[_teamMonsterIdArray[teamMonsterId]]._hitPoints[counter] = 0; } } else { _messageToBePrinted += " A dark fiery whirlwind surrounds the poor victim...the power fades and one victim dies!"; for (uint counter = 0; counter < 9; ++counter) { if (isMonsterActive(teamMonsterId, counter)) { - _mapMonsters[_teamMonsterIdArray[teamMonsterId]]._pictureRef[counter] = 0; + _mapMonsters[_teamMonsterIdArray[teamMonsterId]]._hitPoints[counter] = 0; } } } diff --git a/engines/efh/script.cpp b/engines/efh/script.cpp index 354c9bcf6391..aa901340a648 100644 --- a/engines/efh/script.cpp +++ b/engines/efh/script.cpp @@ -293,7 +293,7 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos case 0x0F: buffer = script_readNumberArray(buffer, 3, scriptNumberArray); if (flag) { - if (isCharacterATeamMember(scriptNumberArray[0])) + if (isNpcATeamMember(scriptNumberArray[0])) retVal = scriptNumberArray[1]; else retVal = scriptNumberArray[2]; @@ -332,7 +332,7 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos buffer = script_readNumberArray(buffer, 1, scriptNumberArray); if (flag) { int16 scriptNpcId = scriptNumberArray[0]; - if (!isCharacterATeamMember(scriptNpcId)) + if (!isNpcATeamMember(scriptNpcId)) var_EE = scriptNpcId; retVal = -1; } @@ -351,7 +351,7 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos if (flag) { int16 scriptNpcId = scriptNumberArray[0]; // TODO: This "if" is useless, it's doing just the same loop and if statement. Consider removing it. - if (isCharacterATeamMember(scriptNpcId)) { + if (isNpcATeamMember(scriptNpcId)) { for (uint counter = 0; counter < 3; ++counter) { if (_teamCharId[counter] == scriptNpcId) { removeCharacterFromTeam(counter); From a28c93becf1a9a805467fa1aadd49306e900ca00 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Fri, 30 Dec 2022 22:41:18 +0100 Subject: [PATCH 205/412] EFH: Fix display of low status window --- engines/efh/efh.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 29d444725cc8..30c089d86858 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -726,7 +726,7 @@ void EfhEngine::displayLowStatusScreen(bool flag) { displayCenteredString("DEF", 104, 128, 152); displayCenteredString("HP", 144, 176, 152); displayCenteredString("Max HP", 192, 224, 152); - displayCenteredString("* DEAD *", 225, 302, 152); + displayCenteredString("Weapon", 225, 302, 152); setTextColorRed(); for (int i = 0; i < 3; ++i) { From 2042def6a0c897abe0682acefd49a168853144fd Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sat, 31 Dec 2022 17:32:16 +0100 Subject: [PATCH 206/412] EFH: Validate some more functions, more renaming --- engines/efh/efh.cpp | 122 +++++++++++++++++++------------------- engines/efh/efh.h | 12 ++-- engines/efh/files.cpp | 2 +- engines/efh/init.cpp | 4 +- engines/efh/savegames.cpp | 2 +- 5 files changed, 72 insertions(+), 70 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 30c089d86858..7ef03b234a6d 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -483,7 +483,7 @@ void EfhEngine::loadMapArrays(int idx) { _mapUnknown[i]._posX = _mapUnknownPtr[9 * i + 1]; _mapUnknown[i]._posY = _mapUnknownPtr[9 * i + 2]; _mapUnknown[i]._field3 = _mapUnknownPtr[9 * i + 3]; - _mapUnknown[i]._field4 = _mapUnknownPtr[9 * i + 4]; + _mapUnknown[i]._field4_NpcId = _mapUnknownPtr[9 * i + 4]; _mapUnknown[i]._field5_textId = READ_LE_UINT16(&_mapUnknownPtr[9 * i + 5]); _mapUnknown[i]._field7_textId = READ_LE_UINT16(&_mapUnknownPtr[9 * i + 7]); } @@ -802,7 +802,7 @@ void EfhEngine::removeCharacterFromTeam(int16 teamMemberId) { _npcBuf[charId].field12_textId = _npcBuf[charId].fieldB_textId; _npcBuf[charId].field14_textId = _npcBuf[charId].fieldE_textId; _npcBuf[charId].field_10 = _npcBuf[charId].field_C; - _npcBuf[charId].field_11 = _npcBuf[charId].field_D; + _npcBuf[charId].field11_NpcId = _npcBuf[charId].field_D; _teamCharId[teamMemberId] = -1; _teamCharStatus[teamMemberId]._status = 0; @@ -1358,7 +1358,7 @@ int8 EfhEngine::checkMonsterMoveCollisionAndTileTexture(int16 monsterId) { if (counter == monsterId) continue; - if (!checkPictureRefAvailability(counter)) + if (!checkMapMonsterAvailability(counter)) continue; if (_mapMonsters[monsterId]._guess_fullPlaceId == _mapMonsters[counter]._guess_fullPlaceId @@ -1587,7 +1587,7 @@ void EfhEngine::handleMapMonsterMoves() { int16 maxDisplayedMapY = CLIP(minDisplayedMapY + 17, 0, mapSize); for (uint monsterId = 0; monsterId < 64; ++monsterId) { - if (!checkPictureRefAvailability(monsterId)) + if (!checkMapMonsterAvailability(monsterId)) continue; if (!checkTeamWeaponRange(monsterId)) @@ -1746,8 +1746,8 @@ void EfhEngine::handleMapMonsterMoves() { handleFight(attackMonsterId); } -bool EfhEngine::checkPictureRefAvailability(int16 monsterId) { - debugC(6, kDebugEngine, "checkPictureRefAvailability %d", monsterId); +bool EfhEngine::checkMapMonsterAvailability(int16 monsterId) { + debugC(6, kDebugEngine, "checkMapMonsterAvailability %d", monsterId); if (_mapMonsters[monsterId]._guess_fullPlaceId == 0xFF) return false; @@ -1791,10 +1791,9 @@ bool EfhEngine::checkMonsterGroupDistance1OrLess(int16 monsterId) { return true; } -bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { - debug("sub21820 %d %d %d", monsterId, arg2, itemId); +bool EfhEngine::handleTalk(int16 monsterId, int16 arg2, int16 itemId) { + debug("handleTalk %d %d %d", monsterId, arg2, itemId); - uint8 var51 = _mapMonsters[monsterId]._possessivePronounSHL6 & 0x3F; if (_mapMonsters[monsterId]._guess_fullPlaceId == 0xFF) return false; @@ -1807,7 +1806,7 @@ bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { if (!checkMonsterGroupDistance1OrLess(monsterId)) return false; - if (var51 != 0x3F) { + if ((_mapMonsters[monsterId]._possessivePronounSHL6 & 0x3F) != 0x3F) { if (_mapMonsters[monsterId]._field9_textId == 0xFF || arg2 != 5) { return false; } @@ -1823,7 +1822,7 @@ bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { int16 npcId = _mapMonsters[monsterId]._npcId; switch (_npcBuf[npcId].field_10 - 0xEE) { case 0: - if (arg2 == 4 && _npcBuf[npcId].field_11 == itemId) { + if (arg2 == 4 && _npcBuf[npcId].field11_NpcId == itemId) { displayMonsterAnim(monsterId); displayImp1Text(_npcBuf[npcId].field14_textId); displayAnimFrames(0xFE, true); @@ -1831,7 +1830,7 @@ bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { } break; case 1: - if (arg2 == 2 && _npcBuf[npcId].field_11 == itemId) { + if (arg2 == 2 && _npcBuf[npcId].field11_NpcId == itemId) { displayMonsterAnim(monsterId); displayImp1Text(_npcBuf[npcId].field14_textId); displayAnimFrames(0xFE, true); @@ -1839,7 +1838,7 @@ bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { } break; case 2: - if (arg2 == 1 && _npcBuf[npcId].field_11 == itemId) { + if (arg2 == 1 && _npcBuf[npcId].field11_NpcId == itemId) { displayMonsterAnim(monsterId); displayImp1Text(_npcBuf[npcId].field14_textId); displayAnimFrames(0xFE, true); @@ -1847,7 +1846,7 @@ bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { } break; case 3: - if (_history[_npcBuf[npcId].field_11] != 0) { + if (_history[_npcBuf[npcId].field11_NpcId] != 0) { displayMonsterAnim(monsterId); displayImp1Text(_npcBuf[npcId].field14_textId); displayAnimFrames(0xFE, true); @@ -1857,7 +1856,7 @@ bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { case 4: for (int counter = 0; counter < _teamSize; ++counter) { for (uint charId = 0; charId < 10; ++charId) { - if (_npcBuf[_teamCharId[counter]]._inventory[charId]._ref == _npcBuf[npcId].field_11) { + if (_npcBuf[_teamCharId[counter]]._inventory[charId]._ref == _npcBuf[npcId].field11_NpcId) { removeObject(_teamCharId[counter], charId); displayMonsterAnim(monsterId); displayImp1Text(_npcBuf[npcId].field14_textId); @@ -1868,7 +1867,7 @@ bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { } break; case 5: - if (arg2 == 2 && _npcBuf[npcId].field_11 == itemId) { + if (arg2 == 2 && _npcBuf[npcId].field11_NpcId == itemId) { displayMonsterAnim(monsterId); displayImp1Text(_npcBuf[npcId].field14_textId); displayAnimFrames(0xFE, true); @@ -1878,7 +1877,7 @@ bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { case 6: for (int counter = 0; counter < _teamSize; ++counter) { for (uint charId = 0; charId < 10; ++charId) { - if (_npcBuf[_teamCharId[counter]]._inventory[charId]._ref == _npcBuf[npcId].field_11) { + if (_npcBuf[_teamCharId[counter]]._inventory[charId]._ref == _npcBuf[npcId].field11_NpcId) { displayMonsterAnim(monsterId); displayImp1Text(_npcBuf[npcId].field14_textId); displayAnimFrames(0xFE, true); @@ -1889,7 +1888,7 @@ bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { break; case 7: for (int counter = 0; counter < _teamSize; ++counter) { - if (_npcBuf[npcId].field_11 == _teamCharId[counter]) { + if (_npcBuf[npcId].field11_NpcId == _teamCharId[counter]) { removeCharacterFromTeam(counter); displayMonsterAnim(monsterId); displayImp1Text(_npcBuf[npcId].field14_textId); @@ -1900,7 +1899,7 @@ bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { break; case 8: for (int counter = 0; counter < _teamSize; ++counter) { - if (_npcBuf[npcId].field_11 == _teamCharId[counter]) { + if (_npcBuf[npcId].field11_NpcId == _teamCharId[counter]) { displayMonsterAnim(monsterId); _enemyNamePt2 = _npcBuf[npcId]._name; _characterNamePt2 = _npcBuf[_teamCharId[counter]]._name; @@ -1927,7 +1926,7 @@ bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { break; case 9: for (int counter = 0; counter < _teamSize; ++counter) { - if (_npcBuf[npcId].field_11 == _teamCharId[counter]) { + if (_npcBuf[npcId].field11_NpcId == _teamCharId[counter]) { displayMonsterAnim(monsterId); displayImp1Text(_npcBuf[npcId].field14_textId); displayAnimFrames(0xFE, true); @@ -1954,12 +1953,12 @@ bool EfhEngine::sub21820(int16 monsterId, int16 arg2, int16 itemId) { return true; } -void EfhEngine::sub221D2(int16 monsterId) { - debug("sub221D2 %d", monsterId); +void EfhEngine::startTalkMenu(int16 monsterId) { + debugC(6, kDebugEngine, "startTalkMenu %d", monsterId); if (monsterId != -1) { _tempTextPtr = nullptr; - sub21820(monsterId, 5, -1); + handleTalk(monsterId, 5, -1); } } @@ -2098,7 +2097,7 @@ bool EfhEngine::sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemI for (int counter = 0; counter < _teamSize; ++counter) { if (_teamCharId[counter] == -1) continue; - if (_teamCharId[counter] == _mapUnknown[var8]._field4) { + if (_teamCharId[counter] == _mapUnknown[var8]._field4_NpcId) { displayImp1Text(_mapUnknown[var8]._field5_textId); return true; } @@ -2109,7 +2108,7 @@ bool EfhEngine::sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemI continue; for (uint var2 = 0; var2 < 10; ++var2) { - if (_npcBuf[_teamCharId[counter]]._inventory[var2]._ref == _mapUnknown[var8]._field4) { + if (_npcBuf[_teamCharId[counter]]._inventory[var2]._ref == _mapUnknown[var8]._field4_NpcId) { displayImp1Text(_mapUnknown[var8]._field5_textId); return true; } @@ -2125,7 +2124,7 @@ bool EfhEngine::sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemI for (uint var2 = 0; var2 < 39; ++var2) { // CHECKME : the whole loop doesn't make much sense as it's using var6 instead of var2, plus _activeScore is an array of 15 bytes, not 0x77... // Also, 39 correspond to the size of activeScore + passiveScore + infoScore + the 2 remaining bytes of the struct - if (_npcBuf[_teamCharId[counter]]._activeScore[var6] >= _mapUnknown[var8]._field4) { + if (_npcBuf[_teamCharId[counter]]._activeScore[var6] >= _mapUnknown[var8]._field4_NpcId) { displayImp1Text(_mapUnknown[var8]._field5_textId); return true; } @@ -2134,7 +2133,7 @@ bool EfhEngine::sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemI } } else { if ((_mapUnknown[var8]._field3 == 0xFA && arg8 == 1) || (_mapUnknown[var8]._field3 == 0xFC && arg8 == 2) || (_mapUnknown[var8]._field3 == 0xFB && arg8 == 3)) { - if (_mapUnknown[var8]._field4 == itemId) { + if (_mapUnknown[var8]._field4_NpcId == itemId) { displayImp1Text(_mapUnknown[var8]._field5_textId); return true; } @@ -2142,7 +2141,7 @@ bool EfhEngine::sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemI int16 var6 = _mapUnknown[var8]._field3; if (var6 >= 0x7B && var6 <= 0xEF) { var6 -= 0x78; - if (var6 >= 0 && var6 <= 0x8B && var6 == itemId && _mapUnknown[var8]._field4 <= _npcBuf[charId]._activeScore[itemId]) { + if (var6 >= 0 && var6 <= 0x8B && var6 == itemId && _mapUnknown[var8]._field4_NpcId <= _npcBuf[charId]._activeScore[itemId]) { displayImp1Text(_mapUnknown[var8]._field5_textId); return true; } @@ -2151,7 +2150,7 @@ bool EfhEngine::sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemI } for (uint counter = 0; counter < 64; ++counter) { - if (!sub21820(counter, arg8, itemId)) + if (!handleTalk(counter, arg8, itemId)) return true; } @@ -2557,19 +2556,18 @@ int16 EfhEngine::selectOtherCharFromTeam() { } bool EfhEngine::checkMonsterCollision() { - debug("checkMonsterCollision"); - - int16 var68 = 0; + debugC(3, kDebugEngine, "checkMonsterCollision"); for (uint monsterId = 0; monsterId < 64; ++monsterId) { - if (!checkPictureRefAvailability(monsterId)) + if (!checkMapMonsterAvailability(monsterId)) continue; - if (!(_largeMapFlag && _mapMonsters[monsterId]._guess_fullPlaceId == 0xFE) && !(!_largeMapFlag && _mapMonsters[monsterId]._guess_fullPlaceId == _fullPlaceId)) + if (!(_largeMapFlag && _mapMonsters[monsterId]._guess_fullPlaceId == 0xFE) + && !(!_largeMapFlag && _mapMonsters[monsterId]._guess_fullPlaceId == _fullPlaceId)) continue; if ((_mapMonsters[monsterId]._possessivePronounSHL6 & 0x3F) > 0x3D - && !(((_mapMonsters[monsterId]._possessivePronounSHL6 & 0x3F) == 0x3F) && !isNpcATeamMember(_mapMonsters[monsterId]._npcId))) + && ((_mapMonsters[monsterId]._possessivePronounSHL6 & 0x3F) != 0x3F || isNpcATeamMember(_mapMonsters[monsterId]._npcId))) continue; if (_mapMonsters[monsterId]._posX != _mapPosX || _mapMonsters[monsterId]._posY != _mapPosY) @@ -2581,30 +2579,34 @@ bool EfhEngine::checkMonsterCollision() { _oldImageSetSubFilesIdx = _imageSetSubFilesIdx; _redrawNeededFl = true; - int16 var6A = 0; - for (uint var6C = 0; var6C < 9; ++var6C) { - if (_mapMonsters[monsterId]._hitPoints[var6C]) - ++var6A; + int16 mobsterCount = 0; + for (uint mobsterCounter = 0; mobsterCounter < 9; ++mobsterCounter) { + if (_mapMonsters[monsterId]._hitPoints[mobsterCounter]) + ++mobsterCount; } - Common::String buffer = ""; + bool endLoop = false; + Common::String buffer; do { - for (uint var6C = 0; var6C < 2; ++var6C) { - int16 var1 = _mapMonsters[monsterId]._possessivePronounSHL6 & 0x3F; + for (uint displayCounter = 0; displayCounter < 2; ++displayCounter) { Common::String dest; - if (var1 <= 0x3D) { - dest = kEncounters[_mapMonsters[monsterId]._monsterRef]._name; - if (var6A > 1) - dest += "s"; - - buffer = Common::String::format("with %d ", var6A) + dest; - } else if (var1 == 0x3E) { + switch (_mapMonsters[monsterId]._possessivePronounSHL6 & 0x3F) { + case 0x3E: buffer = "(NOT DEFINED)"; dest = "(NOT DEFINED)"; - } else if (var1 == 0x3F) { // Useless check, it's the last possible value + break; + case 0x3F: // Special character name dest = _npcBuf[_mapMonsters[monsterId]._npcId]._name; buffer = Common::String("with ") + dest; + break; + default: + dest = kEncounters[_mapMonsters[monsterId]._monsterRef]._name; + if (mobsterCount > 1) + dest += "s"; + + buffer = Common::String::format("with %d ", mobsterCount) + dest; + break; } clearBottomTextZone(0); @@ -2633,7 +2635,7 @@ bool EfhEngine::checkMonsterCollision() { displayStringAtTextPos("L"); setTextColorRed(); displayStringAtTextPos("eave"); - if (var6C == 0) + if (displayCounter == 0) displayFctFullScreen(); } @@ -2641,28 +2643,28 @@ bool EfhEngine::checkMonsterCollision() { switch (input) { case Common::KEYCODE_a: // Attack - var6A = handleFight(monsterId); - var68 = true; + handleFight(monsterId); + endLoop = true; break; case Common::KEYCODE_ESCAPE: case Common::KEYCODE_l: // Leave - var68 = true; + endLoop = true; break; case Common::KEYCODE_s: // Status - var6A = handleStatusMenu(1, _teamCharId[0]); - var68 = true; + handleStatusMenu(1, _teamCharId[0]); + endLoop = true; _tempTextPtr = nullptr; drawGameScreenAndTempText(true); break; case Common::KEYCODE_t: // Talk - sub221D2(monsterId); - var68 = true; + startTalkMenu(monsterId); + endLoop = true; break; default: break; } - } while (!var68); - return true; + } while (!endLoop); + return false; } int8 check = checkTileStatus(_mapPosX, _mapPosY, true); diff --git a/engines/efh/efh.h b/engines/efh/efh.h index c24cc3c3c2f0..911f3e815091 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -92,7 +92,7 @@ struct UnkMapStruct { uint8 _posX; uint8 _posY; uint8 _field3; - uint8 _field4; + uint8 _field4_NpcId; uint16 _field5_textId; uint16 _field7_textId; @@ -138,7 +138,7 @@ struct NPCStruct { uint8 fieldE_textId; uint8 field_F; uint8 field_10; - uint8 field_11; + uint8 field11_NpcId; uint16 field12_textId; uint16 field14_textId; uint32 _xp; @@ -203,7 +203,7 @@ struct CharStatus { }; struct MapMonster { - uint8 _possessivePronounSHL6; + uint8 _possessivePronounSHL6; // aabb bbbb aa:Possessive Pronoun, bb bbbb: unknown uint8 _npcId; uint8 _guess_fullPlaceId; // unsigned? Magic values are 0xFF and 0xFE uint8 _posX; @@ -343,12 +343,12 @@ class EfhEngine : public Engine { bool checkIfMonsterOnSameLargeMapPlace(int16 monsterId); bool checkMonsterWeaponRange(int16 monsterId); void handleMapMonsterMoves(); - bool checkPictureRefAvailability(int16 monsterId); + bool checkMapMonsterAvailability(int16 monsterId); void displayMonsterAnim(int16 monsterId); int16 countAliveMonsters(int16 id); bool checkMonsterGroupDistance1OrLess(int16 monsterId); - bool sub21820(int16 monsterId, int16 arg2, int16 itemId); - void sub221D2(int16 monsterId); + bool handleTalk(int16 monsterId, int16 arg2, int16 itemId); + void startTalkMenu(int16 monsterId); void displayImp1Text(int16 textId); bool sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemId, int16 arg8, int16 imageSetId); int8 checkTileStatus(int16 mapPosX, int16 mapPosY, bool arg4); diff --git a/engines/efh/files.cpp b/engines/efh/files.cpp index ccae0802e5d2..b346cb46c5ce 100644 --- a/engines/efh/files.cpp +++ b/engines/efh/files.cpp @@ -270,7 +270,7 @@ void EfhEngine::loadNPCS() { _npcBuf[i].fieldE_textId = f.readByte(); _npcBuf[i].field_F = f.readByte(); _npcBuf[i].field_10 = f.readByte(); - _npcBuf[i].field_11 = f.readByte(); + _npcBuf[i].field11_NpcId = f.readByte(); _npcBuf[i].field12_textId = f.readUint16LE(); _npcBuf[i].field14_textId = f.readUint16LE(); _npcBuf[i]._xp = f.readUint32LE(); diff --git a/engines/efh/init.cpp b/engines/efh/init.cpp index 1cc26d9713ac..f99328bf78e5 100644 --- a/engines/efh/init.cpp +++ b/engines/efh/init.cpp @@ -45,7 +45,7 @@ void InvObject::init() { } void UnkMapStruct::init() { - _placeId = _posX = _posY = _field3 = _field4 = 0; + _placeId = _posX = _posY = _field3 = _field4_NpcId = 0; _field5_textId = _field7_textId = 0; } @@ -90,7 +90,7 @@ void NPCStruct::init() { fieldE_textId = 0; field_F = 0; field_10 = 0; - field_11 = 0; + field11_NpcId = 0; field12_textId = 0; field14_textId = 0; _xp = 0; diff --git a/engines/efh/savegames.cpp b/engines/efh/savegames.cpp index 776a96b4ff80..8b9239d6bc3e 100644 --- a/engines/efh/savegames.cpp +++ b/engines/efh/savegames.cpp @@ -173,7 +173,7 @@ void EfhEngine::synchronize(Common::Serializer &s) { s.syncAsByte(_npcBuf[i].fieldE_textId); s.syncAsByte(_npcBuf[i].field_F); s.syncAsByte(_npcBuf[i].field_10); - s.syncAsByte(_npcBuf[i].field_11); + s.syncAsByte(_npcBuf[i].field11_NpcId); s.syncAsSint16LE(_npcBuf[i].field12_textId); s.syncAsSint16LE(_npcBuf[i].field14_textId); s.syncAsSint32LE(_npcBuf[i]._xp); From fea76a97247c3e3688ca71d04521d4224bed8763 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sat, 31 Dec 2022 18:27:56 +0100 Subject: [PATCH 207/412] EFH: Review two more functions, small refactoring and some renaming --- engines/efh/efh.cpp | 23 ++++++++++++----------- engines/efh/efh.h | 2 ++ engines/efh/fight.cpp | 12 ++++++------ engines/efh/init.cpp | 1 + 4 files changed, 21 insertions(+), 17 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 7ef03b234a6d..0db5323d082d 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -1257,27 +1257,28 @@ void EfhEngine::goSouthWest() { } void EfhEngine::handleNewRoundEffects() { - debug("handleNewRoundEffects"); - - static int16 regenCounter = 0; + debugC(6, kDebugEngine, "handleNewRoundEffects"); for (int counter = 0; counter < _teamSize; ++counter) { - if (_teamCharStatus[counter]._status == 0) // normal + CharStatus *curStatus = &_teamCharStatus[counter]; + if (curStatus->_status == 0) // normal continue; - if (--_teamCharStatus[counter]._duration <= 0) { - _teamCharStatus[counter]._status = 0; - _teamCharStatus[counter]._duration = 0; + + if (--curStatus->_duration <= 0) { + curStatus->_status = 0; + curStatus->_duration = 0; } } - if (++regenCounter <= 8) + if (++_regenCounter <= 8) return; for (int counter = 0; counter < _teamSize; ++counter) { - if (++_npcBuf[_teamCharId[counter]]._hitPoints > _npcBuf[_teamCharId[counter]]._maxHP) - _npcBuf[_teamCharId[counter]]._hitPoints = _npcBuf[_teamCharId[counter]]._maxHP; + NPCStruct *curNpc = &_npcBuf[_teamCharId[counter]]; + if (curNpc->_hitPoints < curNpc->_maxHP) + ++curNpc->_hitPoints = curNpc->_maxHP; } - regenCounter = 0; + _regenCounter = 0; } void EfhEngine::resetGame() { diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 911f3e815091..41e434224263 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -604,6 +604,8 @@ class EfhEngine : public Engine { int16 _menuStatItemArr[15]; Stru32686 _teamMonsterEffects[5]; InitiativeStruct _initiatives[8]; + + int16 _regenCounter; }; diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index a7504082dc8b..23eb055cc28e 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -1159,16 +1159,16 @@ void EfhEngine::drawCombatScreen(int16 charId, bool whiteFl, bool forceDrawFl) { } void EfhEngine::getXPAndSearchCorpse(int16 charId, Common::String namePt1, Common::String namePt2, int16 monsterId) { - debug("getXPAndSearchCorpse %d %s%s %d", charId, namePt1.c_str(), namePt2.c_str(), monsterId); + debugC(3, kDebugEngine, "getXPAndSearchCorpse %d %s%s %d", charId, namePt1.c_str(), namePt2.c_str(), monsterId); - int16 xpLevel = getXPLevel(_npcBuf[charId]._xp); + int16 oldXpLevel = getXPLevel(_npcBuf[charId]._xp); _npcBuf[charId]._xp += kEncounters[_mapMonsters[monsterId]._monsterRef]._xpGiven; - if (getXPLevel(_npcBuf[charId]._xp) > xpLevel) { + if (getXPLevel(_npcBuf[charId]._xp) > oldXpLevel) { generateSound(15); - int16 var2 = getRandom(20) + getRandom(_npcBuf[charId]._infoScore[4]); - _npcBuf[charId]._hitPoints += var2; - _npcBuf[charId]._maxHP += var2; + int16 hpGain = getRandom(20) + getRandom(_npcBuf[charId]._infoScore[4]); + _npcBuf[charId]._hitPoints += hpGain; + _npcBuf[charId]._maxHP += hpGain; _npcBuf[charId]._infoScore[0] += getRandom(3) - 1; _npcBuf[charId]._infoScore[1] += getRandom(3) - 1; _npcBuf[charId]._infoScore[2] += getRandom(3) - 1; diff --git a/engines/efh/init.cpp b/engines/efh/init.cpp index f99328bf78e5..4f3609c856db 100644 --- a/engines/efh/init.cpp +++ b/engines/efh/init.cpp @@ -316,6 +316,7 @@ EfhEngine::EfhEngine(OSystem *syst, const ADGameDescription *gd) : Engine(syst), memset(_mapMonsters, 0, ARRAYSIZE(_mapMonsters)); memset(_mapGameMap, 0, ARRAYSIZE(_mapGameMap)); memset(_imageSetSubFilesArray, 0, ARRAYSIZE(_imageSetSubFilesArray)); + _regenCounter = 0; // If requested, load a savegame instead of showing the intro _loadSaveSlot = -1; From 4eb3e39efeafe0ba6c3c6a8cee48ffa4875c2dd4 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sun, 1 Jan 2023 13:43:49 +0100 Subject: [PATCH 208/412] EFH: Fix a (likely) original bug, renaming and partial refactoring of ItemStruct (pronoun) --- engines/efh/efh.cpp | 25 ++++++++++++---------- engines/efh/efh.h | 7 +++--- engines/efh/fight.cpp | 50 +++++++++++++++++++++---------------------- engines/efh/files.cpp | 8 +++---- engines/efh/init.cpp | 11 +++++++--- engines/efh/menu.cpp | 34 ++++++++++++++--------------- 6 files changed, 72 insertions(+), 63 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 0db5323d082d..59ae1b042e4f 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -2418,21 +2418,20 @@ void EfhEngine::sub1D8C2(int16 charId, int16 damage) { debug("sub1D8C2 %d %d", charId, damage); int16 destroyCounter = 0; - int16 var40 = _npcBuf[charId]._possessivePronounSHL6 / 64; + int16 pronoun = _npcBuf[charId].getPronoun(); - if (var40 > 2) { - var40 = 2; + if (pronoun > 2) { + pronoun = 2; } - if (damage > 50) - damage = 50; + int16 curDamage = CLIP(damage, 0, 50); for (uint objectId = 0; objectId < 10; ++objectId) { - if (_npcBuf[charId]._inventory[objectId]._ref == 0x7FFF || (_npcBuf[charId]._inventory[objectId]._stat1 & 0x80) == 0 && _items[_npcBuf[charId]._inventory[objectId]._ref]._defense == 0) + if (_npcBuf[charId]._inventory[objectId]._ref == 0x7FFF || (_npcBuf[charId]._inventory[objectId]._stat1 & 0x80) == 0 || _items[_npcBuf[charId]._inventory[objectId]._ref]._defense == 0) continue; - int16 var44 = damage - _npcBuf[charId]._inventory[objectId]._stat2; - _npcBuf[charId]._inventory[objectId]._stat2 -= damage; + int16 remainingDamage = curDamage - _npcBuf[charId]._inventory[objectId]._stat2; + _npcBuf[charId]._inventory[objectId]._stat2 -= curDamage; if (_npcBuf[charId]._inventory[objectId]._stat2 <= 0) { Common::String buffer2 = _items[_npcBuf[charId]._inventory[objectId]._ref]._name; @@ -2440,15 +2439,19 @@ void EfhEngine::sub1D8C2(int16 charId, int16 damage) { if (destroyCounter == 0) { destroyCounter = 1; - _messageToBePrinted += Common::String::format(", but %s ", kPossessive[var40]) + buffer2; + _messageToBePrinted += Common::String::format(", but %s ", kPossessive[pronoun]) + buffer2; } else { ++destroyCounter; _messageToBePrinted += Common::String(", ") + buffer2; } } - if (var44 > 0) - damage = var44; + if (remainingDamage > 0) + curDamage = remainingDamage; + // The original doesn't contain this Else clause. But logically, if the remainingDamage is less than 0, it doesn't make sense to keep damaging equipment with the previous damage. + // As it looks like an original bug, I just added the code to stop damaging equipped protections. + else + break; } if (destroyCounter == 0) { diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 41e434224263..bef29d439257 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -122,10 +122,10 @@ struct ItemStruct { uint8 _range; uint8 _attackType; uint8 _specialEffect; - uint8 field17_attackTypeDefense; + uint8 _field17_attackTypeDefense; uint8 field_18; - uint8 field_19; - uint8 field_1A; + uint8 _field19_mapPosX_or_maxDeltaPoints; + uint8 _mapPosY; void init(); }; @@ -175,6 +175,7 @@ struct NPCStruct { uint8 field_85; void init(); + uint8 getPronoun(); }; struct FontDescr { diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index 23eb055cc28e..a37a838c3053 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -187,8 +187,8 @@ bool EfhEngine::handleFight(int16 monsterId) { int16 var76 = getRandom(getEquipmentDefense(_teamCharId[var7E], false)); varInt = _teamMonsterIdArray[monsterGroupIdOrMonsterId]; - int16 var70 = kEncounters[_mapMonsters[varInt]._monsterRef]._nameArticle; - int16 var5E = _npcBuf[_teamCharId[var7E]]._possessivePronounSHL6 >> 6; + int16 ennemyPronoun = kEncounters[_mapMonsters[varInt]._monsterRef]._nameArticle; + int16 characterPronoun = _npcBuf[_teamCharId[var7E]].getPronoun(); varInt = _items[unk_monsterField5_itemId].field_13; _word32482[var7E] += (varInt * 5); int16 var62 = 0; @@ -235,12 +235,12 @@ bool EfhEngine::handleFight(int16 monsterId) { int16 var68 = _items[unk_monsterField5_itemId]._attackType + 1; int16 var6A = getRandom(3); - if (var5E == 2) + if (characterPronoun == 2) _characterNamePt1 = "The "; else _characterNamePt1 = ""; - if (var7E == 2) + if (ennemyPronoun == 2) _enemyNamePt1 = "The "; else _enemyNamePt1 = ""; @@ -251,17 +251,17 @@ bool EfhEngine::handleFight(int16 monsterId) { if (checkSpecialItemsOnCurrentPlace(unk_monsterField5_itemId)) { // handleFight - check damages - Start if (var62 == 0) { - _messageToBePrinted = Common::String::format("%s%s %s at %s%s with %s %s, but misses!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1.c_str(), _characterNamePt2.c_str(), kPossessive[var70], _nameBuffer.c_str()); + _messageToBePrinted = Common::String::format("%s%s %s at %s%s with %s %s, but misses!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1.c_str(), _characterNamePt2.c_str(), kPossessive[ennemyPronoun], _nameBuffer.c_str()); } else if (hitPoints <= 0) { - _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s, but does no damage!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[var70], _nameBuffer.c_str()); + _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s, but does no damage!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[ennemyPronoun], _nameBuffer.c_str()); } else if (hitPoints == 1) { - _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s for 1 point", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[var70], _nameBuffer.c_str()); + _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s for 1 point", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[ennemyPronoun], _nameBuffer.c_str()); if (_npcBuf[_teamCharId[var7E]]._hitPoints <= 0) getDeathTypeDescription(var7E + 1000, monsterGroupIdOrMonsterId); else _messageToBePrinted += "!"; } else { - _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s for %d points", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[var70], _nameBuffer.c_str(), hitPoints); + _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s for %d points", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[ennemyPronoun], _nameBuffer.c_str(), hitPoints); if (_npcBuf[_teamCharId[var7E]]._hitPoints <= 0) getDeathTypeDescription(var7E + 1000, monsterGroupIdOrMonsterId); else @@ -330,7 +330,7 @@ bool EfhEngine::handleFight(int16 monsterId) { } // handleFight - Check effect - end } else { - _messageToBePrinted = Common::String::format("%s%s tries to use %s %s, but it doesn't work!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPossessive[var70], _nameBuffer.c_str()); + _messageToBePrinted = Common::String::format("%s%s tries to use %s %s, but it doesn't work!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPossessive[ennemyPronoun], _nameBuffer.c_str()); } genericGenerateSound(_items[unk_monsterField5_itemId]._attackType, var62); sub1C219(_messageToBePrinted, 1, 2, true); @@ -389,7 +389,7 @@ void EfhEngine::handleFight_checkEndEffect(int16 charId) { // At this point : The status is different to 0 (normal) and the effect duration is finally 0 (end of effect) _enemyNamePt2 = _npcBuf[_teamCharId[charId]]._name; - if ((_npcBuf[_teamCharId[charId]]._possessivePronounSHL6 >> 6) == 2) { + if (_npcBuf[_teamCharId[charId]].getPronoun() == 2) { _enemyNamePt1 = "The "; } else { _enemyNamePt1 = ""; @@ -464,8 +464,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { int16 var76 = getRandom(_mapMonsters[_teamMonsterIdArray[groupId]]._field_6); int16 varInt = _teamCharId[teamCharId]; - int16 var51 = _npcBuf[varInt]._possessivePronounSHL6; - var51 >>= 6; + int16 var51 = _npcBuf[varInt].getPronoun(); int16 var70 = var51; varInt = _teamMonsterIdArray[groupId]; int16 var5E = kEncounters[_mapMonsters[varInt]._monsterRef]._nameArticle; @@ -631,14 +630,15 @@ void EfhEngine::handleFight_lastAction_D(int16 teamCharId) { _word32482[teamCharId] -= 40; _enemyNamePt2 = _npcBuf[_teamCharId[teamCharId]]._name; - int16 var70 = _npcBuf[_teamCharId[teamCharId]]._possessivePronounSHL6 >> 6; - if (var70 == 2) + uint8 pronoun = _npcBuf[_teamCharId[teamCharId]].getPronoun(); + + if (pronoun == 2) _enemyNamePt1 = "The "; else _enemyNamePt1 = ""; - _messageToBePrinted = Common::String::format("%s%s prepares to defend %sself!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPersonal[var70]); + _messageToBePrinted = Common::String::format("%s%s prepares to defend %sself!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPersonal[pronoun]); sub1C219(_messageToBePrinted, 1, 2, true); } @@ -650,14 +650,14 @@ void EfhEngine::handleFight_lastAction_H(int16 teamCharId) { _teamPctVisible[teamCharId] -= 50; _enemyNamePt2 = _npcBuf[_teamCharId[teamCharId]]._name; - int16 var70 = _npcBuf[_teamCharId[teamCharId]]._possessivePronounSHL6 >> 6; + int16 pronoun = _npcBuf[_teamCharId[teamCharId]].getPronoun(); - if (var70 == 2) + if (pronoun == 2) _enemyNamePt1 = "The "; else _enemyNamePt1 = ""; - _messageToBePrinted = Common::String::format("%s%s attempts to hide %sself!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPersonal[var70]); + _messageToBePrinted = Common::String::format("%s%s attempts to hide %sself!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPersonal[pronoun]); sub1C219(_messageToBePrinted, 1, 2, true); } @@ -670,13 +670,13 @@ void EfhEngine::handleFight_lastAction_U(int16 teamCharId) { int16 itemId = _npcBuf[_teamCharId[teamCharId]]._inventory[_word31780[teamCharId]]._ref; _enemyNamePt2 = _npcBuf[_teamCharId[teamCharId]]._name; _nameBuffer = _items[itemId]._name; - int16 var70 = _npcBuf[_teamCharId[teamCharId]]._possessivePronounSHL6 >> 6; - if (var70 == 2) + int16 pronoun = _npcBuf[_teamCharId[teamCharId]].getPronoun(); + if (pronoun == 2) _enemyNamePt1 = "The "; else _enemyNamePt1 = ""; - _messageToBePrinted = Common::String::format("%s%s uses %s %s! ", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPossessive[var70], _nameBuffer.c_str()); + _messageToBePrinted = Common::String::format("%s%s uses %s %s! ", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPossessive[pronoun], _nameBuffer.c_str()); sub1C219(_messageToBePrinted, 1, 2, true); } @@ -713,7 +713,7 @@ void EfhEngine::resetTeamMonsterEffects() { } void EfhEngine::resetTeamMonsterIdArray() { - debug("resetTeamMonsterIdArray"); + debugC(6, kDebugEngine, "resetTeamMonsterIdArray"); for (int i = 0; i < 5; ++i) { _teamMonsterIdArray[i] = -1; @@ -1518,7 +1518,7 @@ bool EfhEngine::hasAdequateDefense(int16 monsterId, uint8 attackType) { if (_items[itemId]._specialEffect != 0) return false; - return _items[itemId].field17_attackTypeDefense == attackType; + return _items[itemId]._field17_attackTypeDefense == attackType; } bool EfhEngine::hasAdequateDefense_2(int16 charId, uint8 attackType) { @@ -1526,7 +1526,7 @@ bool EfhEngine::hasAdequateDefense_2(int16 charId, uint8 attackType) { int16 itemId = _npcBuf[charId]._unkItemId; - if (_items[itemId]._specialEffect == 0 && _items[itemId].field17_attackTypeDefense == attackType) + if (_items[itemId]._specialEffect == 0 && _items[itemId]._field17_attackTypeDefense == attackType) return true; for (uint counter = 0; counter < 10; ++counter) { @@ -1534,7 +1534,7 @@ bool EfhEngine::hasAdequateDefense_2(int16 charId, uint8 attackType) { continue; itemId = _npcBuf[charId]._inventory[counter]._ref; - if (_items[itemId]._specialEffect == 0 && _items[itemId].field17_attackTypeDefense == attackType) + if (_items[itemId]._specialEffect == 0 && _items[itemId]._field17_attackTypeDefense == attackType) return true; } return false; diff --git a/engines/efh/files.cpp b/engines/efh/files.cpp index b346cb46c5ce..1e0980ddd470 100644 --- a/engines/efh/files.cpp +++ b/engines/efh/files.cpp @@ -149,12 +149,12 @@ void EfhEngine::readItems() { _items[i]._range = f.readByte(); _items[i]._attackType = f.readByte(); _items[i]._specialEffect = f.readByte(); - _items[i].field17_attackTypeDefense = f.readByte(); + _items[i]._field17_attackTypeDefense = f.readByte(); _items[i].field_18 = f.readByte(); - _items[i].field_19 = f.readByte(); - _items[i].field_1A = f.readByte(); + _items[i]._field19_mapPosX_or_maxDeltaPoints = f.readByte(); + _items[i]._mapPosY = f.readByte(); - debugC(7, kDebugEngine, "%s\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x", _items[i]._name, _items[i]._damage, _items[i]._defense, _items[i]._attacks, _items[i]._uses, _items[i].field_13, _items[i]._range, _items[i]._attackType, _items[i]._specialEffect, _items[i].field17_attackTypeDefense, _items[i].field_18, _items[i].field_19, _items[i].field_1A); + debugC(7, kDebugEngine, "%s\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x", _items[i]._name, _items[i]._damage, _items[i]._defense, _items[i]._attacks, _items[i]._uses, _items[i].field_13, _items[i]._range, _items[i]._attackType, _items[i]._specialEffect, _items[i]._field17_attackTypeDefense, _items[i].field_18, _items[i]._field19_mapPosX_or_maxDeltaPoints, _items[i]._mapPosY); } } diff --git a/engines/efh/init.cpp b/engines/efh/init.cpp index 4f3609c856db..7080f8e796b6 100644 --- a/engines/efh/init.cpp +++ b/engines/efh/init.cpp @@ -75,10 +75,10 @@ void ItemStruct::init() { _range = 0; _attackType = 0; _specialEffect = 0; - field17_attackTypeDefense = 0; + _field17_attackTypeDefense = 0; field_18 = 0; - field_19 = 0; - field_1A = 0; + _field19_mapPosX_or_maxDeltaPoints = 0; + _mapPosY = 0; } void NPCStruct::init() { @@ -136,6 +136,11 @@ void NPCStruct::init() { field_85 = 0; } +uint8 NPCStruct::getPronoun() { + return _possessivePronounSHL6 >> 6; +} + + void Stru32686::init() { for (int i = 0; i < 9; ++i) { _effect[i] = 0; diff --git a/engines/efh/menu.cpp b/engines/efh/menu.cpp index 43f4610d71b9..ffbf12e8d8d5 100644 --- a/engines/efh/menu.cpp +++ b/engines/efh/menu.cpp @@ -1050,7 +1050,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 teamMonsterId, int displayString_3("There is no apparent affect!", false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += " The magic sparkles brilliant hues in the air!"; - setMapMonsterField8(teamMonsterId, _items[itemId].field17_attackTypeDefense, true); + setMapMonsterField8(teamMonsterId, _items[itemId]._field17_attackTypeDefense, true); } varA6 = true; break; @@ -1138,8 +1138,8 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 teamMonsterId, int varA6 = true; } break; case 17: { // "Devil Dust" - _mapPosX = _items[itemId].field_19; - _mapPosY = _items[itemId].field_1A; + _mapPosX = _items[itemId]._field19_mapPosX_or_maxDeltaPoints; + _mapPosY = _items[itemId]._mapPosY; int16 tileFactId = getTileFactId(_mapPosX, _mapPosY); if (_tileFact[tileFactId]._field0 == 0) { totalPartyKill(); @@ -1202,26 +1202,26 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 teamMonsterId, int break; case 23: // "Divining Rod" buffer1 = Common::String::format("The %s says, '", _items[itemId]._name); - if (_items[itemId].field_19 < _mapPosX) { - if (_items[itemId].field_1A < _mapPosY) { + if (_items[itemId]._field19_mapPosX_or_maxDeltaPoints < _mapPosX) { + if (_items[itemId]._mapPosY < _mapPosY) { buffer1 += "North West!"; - } else if (_items[itemId].field_1A > _mapPosY) { + } else if (_items[itemId]._mapPosY > _mapPosY) { buffer1 += "South West!"; } else { buffer1 += "West!"; } - } else if (_items[itemId].field_19 > _mapPosX) { - if (_items[itemId].field_1A < _mapPosY) { + } else if (_items[itemId]._field19_mapPosX_or_maxDeltaPoints > _mapPosX) { + if (_items[itemId]._mapPosY < _mapPosY) { buffer1 += "North East!"; - } else if (_items[itemId].field_1A > _mapPosY) { + } else if (_items[itemId]._mapPosY > _mapPosY) { buffer1 += "South East!"; } else { buffer1 += "East!"; } } else { // equals _mapPosX - if (_items[itemId].field_1A < _mapPosY) { + if (_items[itemId]._mapPosY < _mapPosY) { buffer1 += "North!"; - } else if (_items[itemId].field_1A > _mapPosY) { + } else if (_items[itemId]._mapPosY > _mapPosY) { buffer1 += "South!"; } else { buffer1 += "Here!!!"; @@ -1246,8 +1246,8 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 teamMonsterId, int teamCharId = teamMonsterId; if (teamCharId != 0x1B) { - uint8 varAE = _items[itemId].field17_attackTypeDefense; - uint8 effectPoints = getRandom(_items[itemId].field_19); + uint8 varAE = _items[itemId]._field17_attackTypeDefense; + uint8 effectPoints = getRandom(_items[itemId]._field19_mapPosX_or_maxDeltaPoints); _npcBuf[_teamCharId[teamCharId]]._activeScore[varAE] += effectPoints; if (_npcBuf[_teamCharId[teamCharId]]._activeScore[varAE] > 20) { _npcBuf[_teamCharId[teamCharId]]._activeScore[varAE] = 20; @@ -1276,8 +1276,8 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 teamMonsterId, int teamCharId = teamMonsterId; if (teamCharId != 0x1B) { - uint8 varAE = _items[itemId].field17_attackTypeDefense; - uint8 effectPoints = getRandom(_items[itemId].field_19); + uint8 varAE = _items[itemId]._field17_attackTypeDefense; + uint8 effectPoints = getRandom(_items[itemId]._field19_mapPosX_or_maxDeltaPoints); _npcBuf[_teamCharId[teamCharId]]._activeScore[varAE] -= effectPoints; if (_npcBuf[_teamCharId[teamCharId]]._activeScore[varAE] > 20 || _npcBuf[_teamCharId[teamCharId]]._activeScore[varAE] < 0) { _npcBuf[_teamCharId[teamCharId]]._activeScore[varAE] = 1; @@ -1358,7 +1358,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 teamMonsterId, int } if (teamCharId != 0x1B) { - int16 effectPoints = getRandom(_items[itemId].field17_attackTypeDefense); + int16 effectPoints = getRandom(_items[itemId]._field17_attackTypeDefense); _npcBuf[_teamCharId[teamCharId]]._hitPoints += effectPoints; if (_npcBuf[_teamCharId[teamCharId]]._hitPoints > _npcBuf[_teamCharId[teamCharId]]._maxHP) _npcBuf[_teamCharId[teamCharId]]._hitPoints = _npcBuf[_teamCharId[teamCharId]]._maxHP; @@ -1388,7 +1388,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 teamMonsterId, int } if (teamCharId != 0x1B) { - int16 effectPoints = getRandom(_items[itemId].field17_attackTypeDefense); + int16 effectPoints = getRandom(_items[itemId]._field17_attackTypeDefense); _npcBuf[_teamCharId[teamCharId]]._hitPoints -= effectPoints; if (_npcBuf[_teamCharId[teamCharId]]._hitPoints < 0) _npcBuf[_teamCharId[teamCharId]]._hitPoints = 0; From 9a293d2074da08097f2ce902d9c48cfe9dfe7d36 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sun, 1 Jan 2023 13:56:57 +0100 Subject: [PATCH 209/412] EFH: finish pronoun refactoring, some renaming --- engines/efh/efh.h | 2 ++ engines/efh/fight.cpp | 84 +++++++++++++++++++++---------------------- engines/efh/init.cpp | 3 ++ 3 files changed, 47 insertions(+), 42 deletions(-) diff --git a/engines/efh/efh.h b/engines/efh/efh.h index bef29d439257..6b19eab7d909 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -216,6 +216,8 @@ struct MapMonster { uint8 _field9_textId; uint8 _groupSize; int16 _hitPoints[9]; + + uint8 getPronoun(); }; struct Stru32686 { diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index a37a838c3053..bdc354d04204 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -732,18 +732,18 @@ bool EfhEngine::isTeamMemberStatusNormal(int16 teamMemberId) { void EfhEngine::getDeathTypeDescription(int16 attackerId, int16 victimId) { debug("getDeathTypeDescription %d %d", attackerId, victimId); - int16 possessivePronoun; + int16 pronoun; if (attackerId > 999) { int16 charId = _teamCharId[attackerId - 1000]; - possessivePronoun = _npcBuf[charId]._possessivePronounSHL6 >> 6; + pronoun = _npcBuf[charId].getPronoun(); } else { int16 charId = _teamMonsterIdArray[attackerId]; - possessivePronoun = _mapMonsters[charId]._possessivePronounSHL6 >> 6; + pronoun = _mapMonsters[charId].getPronoun(); } - if (possessivePronoun > 2) - possessivePronoun = 2; + if (pronoun > 2) + pronoun = 2; int16 deathType; if (getRandom(100) < 20) { @@ -774,13 +774,13 @@ void EfhEngine::getDeathTypeDescription(int16 attackerId, int16 victimId) { case 0: switch (rndDescrForDeathType) { case 0: - tmpStr = Common::String::format(", killing %s!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", killing %s!", kPersonal[pronoun]); break; case 1: - tmpStr = Common::String::format(", slaughtering %s!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", slaughtering %s!", kPersonal[pronoun]); break; case 2: - tmpStr = Common::String::format(", annihilating %s!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", annihilating %s!", kPersonal[pronoun]); break; default: break; @@ -789,13 +789,13 @@ void EfhEngine::getDeathTypeDescription(int16 attackerId, int16 victimId) { case 1: switch (rndDescrForDeathType) { case 0: - tmpStr = Common::String::format(", cutting %s in two!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", cutting %s in two!", kPersonal[pronoun]); break; case 1: - tmpStr = Common::String::format(", dicing %s into small cubes!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", dicing %s into small cubes!", kPersonal[pronoun]); break; case 2: - tmpStr = Common::String::format(", butchering %s into lamb chops!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", butchering %s into lamb chops!", kPersonal[pronoun]); break; default: break; @@ -804,13 +804,13 @@ void EfhEngine::getDeathTypeDescription(int16 attackerId, int16 victimId) { case 2: switch (rndDescrForDeathType) { case 0: - tmpStr = Common::String::format(", piercing %s heart!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", piercing %s heart!", kPersonal[pronoun]); break; case 1: - tmpStr = Common::String::format(", leaving %s a spouting mass of blood!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", leaving %s a spouting mass of blood!", kPersonal[pronoun]); break; case 2: - tmpStr = Common::String::format(", popping %s like a zit!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", popping %s like a zit!", kPersonal[pronoun]); break; default: break; @@ -819,13 +819,13 @@ void EfhEngine::getDeathTypeDescription(int16 attackerId, int16 victimId) { case 3: switch (rndDescrForDeathType) { case 0: - tmpStr = Common::String::format(", pulping %s head over a wide area!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", pulping %s head over a wide area!", kPersonal[pronoun]); break; case 1: - tmpStr = Common::String::format(", smashing %s into a meat patty!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", smashing %s into a meat patty!", kPersonal[pronoun]); break; case 2: - tmpStr = Common::String::format(", squashing %s like a ripe tomato!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", squashing %s like a ripe tomato!", kPersonal[pronoun]); break; default: break; @@ -834,10 +834,10 @@ void EfhEngine::getDeathTypeDescription(int16 attackerId, int16 victimId) { case 4: switch (rndDescrForDeathType) { case 0: - tmpStr = Common::String::format(", totally incinerating %s!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", totally incinerating %s!", kPersonal[pronoun]); break; case 1: - tmpStr = Common::String::format(", reducing %s to a pile of ash!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", reducing %s to a pile of ash!", kPersonal[pronoun]); break; case 2: tmpStr = Common::String::format(", leaving a blistered mass of flesh behind!"); @@ -850,13 +850,13 @@ void EfhEngine::getDeathTypeDescription(int16 attackerId, int16 victimId) { switch (rndDescrForDeathType) { case 0: // The original has a typo: popscicle - tmpStr = Common::String::format(", turning %s into a popsicle!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", turning %s into a popsicle!", kPersonal[pronoun]); break; case 1: - tmpStr = Common::String::format(", encasing %s in a block of ice!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", encasing %s in a block of ice!", kPersonal[pronoun]); break; case 2: - tmpStr = Common::String::format(", shattering %s into shards!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", shattering %s into shards!", kPersonal[pronoun]); break; default: break; @@ -868,10 +868,10 @@ void EfhEngine::getDeathTypeDescription(int16 attackerId, int16 victimId) { tmpStr = Common::String::format(", leaving pudding for brains"); break; case 1: - tmpStr = Common::String::format(", bursting %s head like a bubble!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", bursting %s head like a bubble!", kPersonal[pronoun]); break; case 2: - tmpStr = Common::String::format(", turning %s into a mindless vegetable", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", turning %s into a mindless vegetable", kPersonal[pronoun]); break; default: break; @@ -880,13 +880,13 @@ void EfhEngine::getDeathTypeDescription(int16 attackerId, int16 victimId) { case 7: switch (rndDescrForDeathType) { case 0: - tmpStr = Common::String::format(", reducing %s to an oozing pile of flesh!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", reducing %s to an oozing pile of flesh!", kPersonal[pronoun]); break; case 1: - tmpStr = Common::String::format(", melting %s like an ice cube in hot coffee!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", melting %s like an ice cube in hot coffee!", kPersonal[pronoun]); break; case 2: - tmpStr = Common::String::format(", vaporizing %s into a steaming cloud!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", vaporizing %s into a steaming cloud!", kPersonal[pronoun]); break; default: break; @@ -895,13 +895,13 @@ void EfhEngine::getDeathTypeDescription(int16 attackerId, int16 victimId) { case 8: switch (rndDescrForDeathType) { case 0: - tmpStr = Common::String::format(", engulfing %s in black smoke puffs!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", engulfing %s in black smoke puffs!", kPersonal[pronoun]); break; case 1: - tmpStr = Common::String::format(", sucking %s into eternity!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", sucking %s into eternity!", kPersonal[pronoun]); break; case 2: - tmpStr = Common::String::format(", turning %s into a mindless zombie!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", turning %s into a mindless zombie!", kPersonal[pronoun]); break; default: break; @@ -912,13 +912,13 @@ void EfhEngine::getDeathTypeDescription(int16 attackerId, int16 victimId) { case 11: switch (rndDescrForDeathType) { case 0: - tmpStr = Common::String::format(", completely disintegrating %s!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", completely disintegrating %s!", kPersonal[pronoun]); break; case 1: - tmpStr = Common::String::format(", spreading %s into a fine mist!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", spreading %s into a fine mist!", kPersonal[pronoun]); break; case 2: - tmpStr = Common::String::format(", leaving a smoking crater in %s place!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", leaving a smoking crater in %s place!", kPersonal[pronoun]); break; default: break; @@ -929,13 +929,13 @@ void EfhEngine::getDeathTypeDescription(int16 attackerId, int16 victimId) { case 14: switch (rndDescrForDeathType) { case 0: - tmpStr = Common::String::format(", tearing a chunk out of %s back!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", tearing a chunk out of %s back!", kPersonal[pronoun]); break; case 1: - tmpStr = Common::String::format(", blowing %s brains out!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", blowing %s brains out!", kPersonal[pronoun]); break; case 2: - tmpStr = Common::String::format(", exploding %s entire chest!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", exploding %s entire chest!", kPersonal[pronoun]); break; default: break; @@ -944,13 +944,13 @@ void EfhEngine::getDeathTypeDescription(int16 attackerId, int16 victimId) { case 15: switch (rndDescrForDeathType) { case 0: - tmpStr = Common::String::format(", choking %s to death!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", choking %s to death!", kPersonal[pronoun]); break; case 1: - tmpStr = Common::String::format(", melting %s lungs!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", melting %s lungs!", kPersonal[pronoun]); break; case 2: - tmpStr = Common::String::format(", leaving %s gasping for air as %s collapses!", kPersonal[possessivePronoun], kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", leaving %s gasping for air as %s collapses!", kPersonal[pronoun], kPersonal[pronoun]); break; default: break; @@ -959,13 +959,13 @@ void EfhEngine::getDeathTypeDescription(int16 attackerId, int16 victimId) { case 16: switch (rndDescrForDeathType) { case 0: - tmpStr = Common::String::format(", tearing a chunk out of %s back!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", tearing a chunk out of %s back!", kPersonal[pronoun]); break; case 1: - tmpStr = Common::String::format(", piercing %s heart!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", piercing %s heart!", kPersonal[pronoun]); break; case 2: - tmpStr = Common::String::format(", impaling %s brain!", kPersonal[possessivePronoun]); + tmpStr = Common::String::format(", impaling %s brain!", kPersonal[pronoun]); break; default: break; diff --git a/engines/efh/init.cpp b/engines/efh/init.cpp index 7080f8e796b6..e7c3fd48f68e 100644 --- a/engines/efh/init.cpp +++ b/engines/efh/init.cpp @@ -140,6 +140,9 @@ uint8 NPCStruct::getPronoun() { return _possessivePronounSHL6 >> 6; } +uint8 MapMonster::getPronoun() { + return _possessivePronounSHL6 >> 6; +} void Stru32686::init() { for (int i = 0; i < 9; ++i) { From 204f23ba1bc255d77f1c7f5f04f496930acf02e1 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sun, 1 Jan 2023 14:56:41 +0100 Subject: [PATCH 210/412] EFH: refactor the use of InvObject._stat1, fix a bug in hasAdequateDefense_2(), in sub19E2E() and in displayCharacterSummary() --- engines/efh/efh.cpp | 31 ++++++++++++++++++------------- engines/efh/efh.h | 6 ++++-- engines/efh/fight.cpp | 17 ++++++++--------- engines/efh/menu.cpp | 13 +++++++------ 4 files changed, 37 insertions(+), 30 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 59ae1b042e4f..ddd54fda2e23 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -39,6 +39,14 @@ void EfhGraphicsStruct::copy(EfhGraphicsStruct *src) { _area = src->_area; } +bool InvObject::isEquipped() { + return (_stat1 & 0x80) != 0; +} + +int8 InvObject::getUsesLeft() { + return _stat1 & 0x7F; +} + EfhEngine::~EfhEngine() { delete _rnd; delete _graphicsStruct; @@ -530,7 +538,7 @@ int16 EfhEngine::getEquipmentDefense(int16 charId, bool flag) { if (_npcBuf[charId]._inventory[i]._ref == 0x7FFF) continue; - if ((_npcBuf[charId]._inventory[i]._stat1 & 0x80) == 0) + if (!_npcBuf[charId]._inventory[i].isEquipped()) continue; int16 curDef = _npcBuf[charId]._inventory[i]._stat2; @@ -554,7 +562,7 @@ uint16 EfhEngine::sub1C80A(int16 charId, int16 field18, bool flag) { debugC(2, kDebugEngine, "sub1C80A %d %d %s", charId, field18, flag ? "True" : "False"); for (int i = 0; i < 10; ++i) { - if ((_npcBuf[charId]._inventory[i]._stat1 & 0x80) == 0) + if (!_npcBuf[charId]._inventory[i].isEquipped()) continue; int16 itemId = _npcBuf[charId]._inventory[i]._ref; @@ -919,21 +927,21 @@ void EfhEngine::handleWinSequence() { free(winSeqBuf4); } -bool EfhEngine::giveItemTo(int16 charId, int16 objectId, int16 altCharId) { - debugC(3, kDebugEngine, "giveItemTo %d %d %d", charId, objectId, altCharId); +bool EfhEngine::giveItemTo(int16 charId, int16 objectId, int16 fromCharId) { + debugC(3, kDebugEngine, "giveItemTo %d %d %d", charId, objectId, fromCharId); for (uint newObjectId = 0; newObjectId < 10; ++newObjectId) { if (_npcBuf[charId]._inventory[newObjectId]._ref != 0x7FFF) continue; - if (altCharId == 0xFF) { + if (fromCharId == 0xFF) { _npcBuf[charId]._inventory[newObjectId]._ref = objectId; _npcBuf[charId]._inventory[newObjectId]._stat2 = _items[objectId]._defense; _npcBuf[charId]._inventory[newObjectId]._stat1 = _items[objectId]._uses; } else { - _npcBuf[charId]._inventory[newObjectId]._ref = _npcBuf[altCharId]._inventory[newObjectId]._ref; - _npcBuf[charId]._inventory[newObjectId]._stat2 = _npcBuf[altCharId]._inventory[newObjectId]._stat2; - _npcBuf[charId]._inventory[newObjectId]._stat1 = _npcBuf[altCharId]._inventory[newObjectId]._stat1 & 0x7F; // not equipped as the upper bit isn't set (0x80) + _npcBuf[charId]._inventory[newObjectId]._ref = _npcBuf[fromCharId]._inventory[newObjectId]._ref; + _npcBuf[charId]._inventory[newObjectId]._stat2 = _npcBuf[fromCharId]._inventory[newObjectId]._stat2; + _npcBuf[charId]._inventory[newObjectId]._stat1 = _npcBuf[fromCharId]._inventory[newObjectId].getUsesLeft(); // not equipped as the upper bit isn't set (0x80) } return true; @@ -2427,7 +2435,7 @@ void EfhEngine::sub1D8C2(int16 charId, int16 damage) { int16 curDamage = CLIP(damage, 0, 50); for (uint objectId = 0; objectId < 10; ++objectId) { - if (_npcBuf[charId]._inventory[objectId]._ref == 0x7FFF || (_npcBuf[charId]._inventory[objectId]._stat1 & 0x80) == 0 || _items[_npcBuf[charId]._inventory[objectId]._ref]._defense == 0) + if (_npcBuf[charId]._inventory[objectId]._ref == 0x7FFF || !_npcBuf[charId]._inventory[objectId].isEquipped() || _items[_npcBuf[charId]._inventory[objectId]._ref]._defense == 0) continue; int16 remainingDamage = curDamage - _npcBuf[charId]._inventory[objectId]._stat2; @@ -2496,10 +2504,7 @@ bool EfhEngine::isItemCursed(int16 itemId) { bool EfhEngine::hasObjectEquipped(int16 charId, int16 objectId) { debugC(6, kDebugEngine, "hasObjectEquipped %d %d", charId, objectId); - if ((_npcBuf[charId]._inventory[objectId]._stat1 & 0x80) == 0) - return false; - - return true; + return _npcBuf[charId]._inventory[objectId].isEquipped(); } diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 6b19eab7d909..fb0e03ef4ef5 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -81,10 +81,12 @@ class EfhGraphicsStruct { struct InvObject { int16 _ref; - uint8 _stat1; // abbb bbbb - a: equipped b: durability + uint8 _stat1; // abbb bbbb - a: equipped b: uses left uint8 _stat2; void init(); + bool isEquipped(); + int8 getUsesLeft(); }; struct UnkMapStruct { @@ -313,7 +315,7 @@ class EfhEngine : public Engine { void refreshTeamSize(); bool isNpcATeamMember(int16 id); void handleWinSequence(); - bool giveItemTo(int16 charId, int16 objectId, int16 altCharId); + bool giveItemTo(int16 charId, int16 objectId, int16 fromCharId); int16 chooseCharacterToReplace(); int16 handleCharacterJoining(); void drawText(uint8 *impPtr, int16 posX, int16 posY, int16 maxX, int16 maxY, bool flag); diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index bdc354d04204..a505c666df7a 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -464,8 +464,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { int16 var76 = getRandom(_mapMonsters[_teamMonsterIdArray[groupId]]._field_6); int16 varInt = _teamCharId[teamCharId]; - int16 var51 = _npcBuf[varInt].getPronoun(); - int16 var70 = var51; + int16 var70 = _npcBuf[varInt].getPronoun(); varInt = _teamMonsterIdArray[groupId]; int16 var5E = kEncounters[_mapMonsters[varInt]._monsterRef]._nameArticle; int16 charScore = getCharacterScore(_teamCharId[teamCharId], unk_monsterField5_itemId); @@ -587,15 +586,15 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { // Action A - Check item durability - Start varInt = _teamCharId[teamCharId]; var64 = sub1C80A(varInt, 9, false); - if (var64 != 0x7FFF && (_npcBuf[varInt]._inventory[var64]._stat1 & 0x7F) != 0x7F) { - var51 = _npcBuf[varInt]._inventory[var64]._stat1 & 0x7F; - --var51; - if (var51 <= 0) { + if (var64 != 0x7FFF && _npcBuf[varInt]._inventory[var64].getUsesLeft() != 0x7F) { + int16 usesLeft = _npcBuf[varInt]._inventory[var64].getUsesLeft(); + --usesLeft; + if (usesLeft <= 0) { _messageToBePrinted += Common::String::format(" * %s%s's %s breaks!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), _nameBuffer.c_str()); setCharacterObjectToBroken(varInt, var64); var6E = false; } else { - _npcBuf[varInt]._inventory[var64]._stat1 = (_npcBuf[varInt]._inventory[var64]._stat1 & 80) + var51; + _npcBuf[varInt]._inventory[var64]._stat1 = (_npcBuf[varInt]._inventory[var64]._stat1 & 80) + usesLeft; } } // Action A - Check item durability - End @@ -732,7 +731,7 @@ bool EfhEngine::isTeamMemberStatusNormal(int16 teamMemberId) { void EfhEngine::getDeathTypeDescription(int16 attackerId, int16 victimId) { debug("getDeathTypeDescription %d %d", attackerId, victimId); - int16 pronoun; + uint8 pronoun; if (attackerId > 999) { int16 charId = _teamCharId[attackerId - 1000]; @@ -1530,7 +1529,7 @@ bool EfhEngine::hasAdequateDefense_2(int16 charId, uint8 attackType) { return true; for (uint counter = 0; counter < 10; ++counter) { - if (_npcBuf[charId]._inventory[counter]._ref == 0x7FFF || _npcBuf[charId]._inventory[counter]._stat1 == 0x80) + if (_npcBuf[charId]._inventory[counter]._ref == 0x7FFF || !_npcBuf[charId]._inventory[counter].isEquipped()) continue; itemId = _npcBuf[charId]._inventory[counter]._ref; diff --git a/engines/efh/menu.cpp b/engines/efh/menu.cpp index ffbf12e8d8d5..fbf7b697c87e 100644 --- a/engines/efh/menu.cpp +++ b/engines/efh/menu.cpp @@ -320,7 +320,7 @@ void EfhEngine::displayCharacterSummary(int16 curMenuLine, int16 npcId) { int16 textPosY = 81 + counter * 9; int16 itemId = _npcBuf[npcId]._inventory[_menuStatItemArr[counter]]._ref; if (itemId != 0x7FFF) { - if (_npcBuf[npcId]._inventory[_menuStatItemArr[counter]]._stat1 & 0x80) { + if (_npcBuf[npcId]._inventory[_menuStatItemArr[counter]].isEquipped()) { setTextPos(146, textPosY); displayCharAtTextPos('E'); } @@ -353,7 +353,7 @@ void EfhEngine::displayCharacterSummary(int16 curMenuLine, int16 npcId) { // var54 = _items[_npcBuf[npcId]._inventory[_menuStatItemArr[counter]]._ref]._defense; // { } else if (_items[itemId]._uses != 0x7F) { - int16 stat1 = _npcBuf[npcId]._inventory[_menuStatItemArr[counter]]._stat1; + int16 stat1 = _npcBuf[npcId]._inventory[_menuStatItemArr[counter]].getUsesLeft(); if (stat1 != 0x7F) { buffer1 = Common::String::format("%d", stat1); displayStringAtTextPos(buffer1); @@ -1425,9 +1425,10 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 teamMonsterId, int } if (varA6) { - if ((_npcBuf[charId]._inventory[objectId]._stat1 & 0x7F) != 0x7F) { - int8 varA1 = (_npcBuf[charId]._inventory[objectId]._stat1 & 0x7F) - 1; - if (varA1 <= 0) { + int16 usesLeft = _npcBuf[charId]._inventory[objectId].getUsesLeft(); + if (usesLeft != 0x7F) { + --usesLeft; + if (usesLeft <= 0) { buffer1 = " * The item breaks!"; if (argA == 2) { getLastCharAfterAnimCount(_guessAnimationAmount); @@ -1438,7 +1439,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 teamMonsterId, int setCharacterObjectToBroken(charId, objectId); } else { _npcBuf[charId]._inventory[objectId]._stat1 &= 0x80; - _npcBuf[charId]._inventory[objectId]._stat1 |= 0xA1; + _npcBuf[charId]._inventory[objectId]._stat1 |= usesLeft; } } From 946b1740a55b7d8ae414d77cc2caf6f40e4aaca0 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sun, 1 Jan 2023 16:09:32 +0100 Subject: [PATCH 211/412] EFH: Fix a (likely) bug in sub1D8C2() --- engines/efh/efh.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index ddd54fda2e23..6f266abdacc5 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -2439,9 +2439,11 @@ void EfhEngine::sub1D8C2(int16 charId, int16 damage) { continue; int16 remainingDamage = curDamage - _npcBuf[charId]._inventory[objectId]._stat2; - _npcBuf[charId]._inventory[objectId]._stat2 -= curDamage; + // not in the original: this int16 is used to test if the result is negative. Otherwise _stat2 (uint8) turns it into a "large" positive value. + int16 newDurability = _npcBuf[charId]._inventory[objectId]._stat2 - curDamage; + _npcBuf[charId]._inventory[objectId]._stat2 = newDurability; - if (_npcBuf[charId]._inventory[objectId]._stat2 <= 0) { + if (newDurability <= 0) { Common::String buffer2 = _items[_npcBuf[charId]._inventory[objectId]._ref]._name; removeObject(charId, objectId); From 594156ae6451a16648d5e2f6bc43ffa0f75f1f05 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Mon, 2 Jan 2023 09:05:51 +0100 Subject: [PATCH 212/412] EFH: Fix a bug in handleFight, fix handleFight_lastAction_U, rename (between others) useObject() --- engines/efh/efh.cpp | 16 +++++------ engines/efh/efh.h | 10 +++---- engines/efh/fight.cpp | 7 +++-- engines/efh/files.cpp | 2 +- engines/efh/init.cpp | 4 +-- engines/efh/menu.cpp | 57 ++++++++++++++++++++------------------- engines/efh/savegames.cpp | 2 +- 7 files changed, 51 insertions(+), 47 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 6f266abdacc5..1a91cebaa350 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -541,7 +541,7 @@ int16 EfhEngine::getEquipmentDefense(int16 charId, bool flag) { if (!_npcBuf[charId]._inventory[i].isEquipped()) continue; - int16 curDef = _npcBuf[charId]._inventory[i]._stat2; + int16 curDef = _npcBuf[charId]._inventory[i]._curHitPoints; if (curDef == 0xFF) curDef = _items[_npcBuf[charId]._inventory[i]._ref]._defense; @@ -791,7 +791,7 @@ void EfhEngine::removeObject(int16 charId, int16 objectId) { debugC(6, kDebugEngine, "removeObject %d %d", charId, objectId); _npcBuf[charId]._inventory[objectId]._ref = 0x7FFF; _npcBuf[charId]._inventory[objectId]._stat1 = 0; - _npcBuf[charId]._inventory[objectId]._stat2 = 0; + _npcBuf[charId]._inventory[objectId]._curHitPoints = 0; } void EfhEngine::totalPartyKill() { @@ -936,11 +936,11 @@ bool EfhEngine::giveItemTo(int16 charId, int16 objectId, int16 fromCharId) { if (fromCharId == 0xFF) { _npcBuf[charId]._inventory[newObjectId]._ref = objectId; - _npcBuf[charId]._inventory[newObjectId]._stat2 = _items[objectId]._defense; + _npcBuf[charId]._inventory[newObjectId]._curHitPoints = _items[objectId]._defense; _npcBuf[charId]._inventory[newObjectId]._stat1 = _items[objectId]._uses; } else { _npcBuf[charId]._inventory[newObjectId]._ref = _npcBuf[fromCharId]._inventory[newObjectId]._ref; - _npcBuf[charId]._inventory[newObjectId]._stat2 = _npcBuf[fromCharId]._inventory[newObjectId]._stat2; + _npcBuf[charId]._inventory[newObjectId]._curHitPoints = _npcBuf[fromCharId]._inventory[newObjectId]._curHitPoints; _npcBuf[charId]._inventory[newObjectId]._stat1 = _npcBuf[fromCharId]._inventory[newObjectId].getUsesLeft(); // not equipped as the upper bit isn't set (0x80) } @@ -2438,10 +2438,10 @@ void EfhEngine::sub1D8C2(int16 charId, int16 damage) { if (_npcBuf[charId]._inventory[objectId]._ref == 0x7FFF || !_npcBuf[charId]._inventory[objectId].isEquipped() || _items[_npcBuf[charId]._inventory[objectId]._ref]._defense == 0) continue; - int16 remainingDamage = curDamage - _npcBuf[charId]._inventory[objectId]._stat2; - // not in the original: this int16 is used to test if the result is negative. Otherwise _stat2 (uint8) turns it into a "large" positive value. - int16 newDurability = _npcBuf[charId]._inventory[objectId]._stat2 - curDamage; - _npcBuf[charId]._inventory[objectId]._stat2 = newDurability; + int16 remainingDamage = curDamage - _npcBuf[charId]._inventory[objectId]._curHitPoints; + // not in the original: this int16 is used to test if the result is negative. Otherwise _curHitPoints (uint8) turns it into a "large" positive value. + int16 newDurability = _npcBuf[charId]._inventory[objectId]._curHitPoints - curDamage; + _npcBuf[charId]._inventory[objectId]._curHitPoints = newDurability; if (newDurability <= 0) { Common::String buffer2 = _items[_npcBuf[charId]._inventory[objectId]._ref]._name; diff --git a/engines/efh/efh.h b/engines/efh/efh.h index fb0e03ef4ef5..74972893b43c 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -82,7 +82,7 @@ class EfhGraphicsStruct { struct InvObject { int16 _ref; uint8 _stat1; // abbb bbbb - a: equipped b: uses left - uint8 _stat2; + uint8 _curHitPoints; void init(); bool isEquipped(); @@ -222,7 +222,7 @@ struct MapMonster { uint8 getPronoun(); }; -struct Stru32686 { +struct TeamMonsterEffect { int16 _effect[9]; int16 _duration[9]; @@ -381,7 +381,7 @@ class EfhEngine : public Engine { void handleFight_lastAction_A(int16 teamCharId); void handleFight_lastAction_D(int16 teamCharId); void handleFight_lastAction_H(int16 teamCharId); - void handleFight_lastAction_U(int16 teamCharId); + bool handleFight_lastAction_U(int16 teamCharId); bool isTPK(); bool isMonsterAlreadyFighting(int16 monsterId, int16 teamMonsterId); void createOpponentList(int16 monsterTeamId); @@ -469,7 +469,7 @@ class EfhEngine : public Engine { int16 handleStatusMenu(int16 gameMode, int16 charId); void unequipItem(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine); void sub191FF(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine); - int16 sub19E2E(int16 charId, int16 objectId, int16 teamMonsterId, int16 menuId, int16 curMenuLine, int16 argA); + int16 useObject(int16 charId, int16 objectId, int16 teamMonsterId, int16 menuId, int16 curMenuLine, int16 argA); // Savegames void synchronize(Common::Serializer &s); @@ -607,7 +607,7 @@ class EfhEngine : public Engine { int16 _word31780[3]; int16 _menuStatItemArr[15]; - Stru32686 _teamMonsterEffects[5]; + TeamMonsterEffect _teamMonsterEffects[5]; InitiativeStruct _initiatives[8]; int16 _regenCounter; diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index a505c666df7a..e61fa8662a0c 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -151,7 +151,7 @@ bool EfhEngine::handleFight(int16 monsterId) { handleFight_lastAction_H(monsterGroupIdOrMonsterId); break; case 0x55: // 'U'se - handleFight_lastAction_U(monsterGroupIdOrMonsterId); + mainLoopCond = handleFight_lastAction_U(monsterGroupIdOrMonsterId); break; default: break; @@ -660,7 +660,7 @@ void EfhEngine::handleFight_lastAction_H(int16 teamCharId) { sub1C219(_messageToBePrinted, 1, 2, true); } -void EfhEngine::handleFight_lastAction_U(int16 teamCharId) { +bool EfhEngine::handleFight_lastAction_U(int16 teamCharId) { debug("handleFight_lastAction_U %d", teamCharId); // Fight - Action 'U' - Use Item @@ -676,7 +676,10 @@ void EfhEngine::handleFight_lastAction_U(int16 teamCharId) { _enemyNamePt1 = ""; _messageToBePrinted = Common::String::format("%s%s uses %s %s! ", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPossessive[pronoun], _nameBuffer.c_str()); + bool retVal = useObject(_teamCharId[teamCharId], _word31780[teamCharId], _teamNextAttack[teamCharId], teamCharId, 0, 3); sub1C219(_messageToBePrinted, 1, 2, true); + + return retVal; } bool EfhEngine::isTPK() { diff --git a/engines/efh/files.cpp b/engines/efh/files.cpp index 1e0980ddd470..54f0446fa9eb 100644 --- a/engines/efh/files.cpp +++ b/engines/efh/files.cpp @@ -288,7 +288,7 @@ void EfhEngine::loadNPCS() { for (int idx = 0; idx < 10; ++idx) { _npcBuf[i]._inventory[idx]._ref = f.readSint16LE(); _npcBuf[i]._inventory[idx]._stat1 = f.readByte(); - _npcBuf[i]._inventory[idx]._stat2 = f.readByte(); + _npcBuf[i]._inventory[idx]._curHitPoints = f.readByte(); } _npcBuf[i]._possessivePronounSHL6 = f.readByte(); _npcBuf[i]._speed = f.readByte(); diff --git a/engines/efh/init.cpp b/engines/efh/init.cpp index e7c3fd48f68e..e5839e9e68b5 100644 --- a/engines/efh/init.cpp +++ b/engines/efh/init.cpp @@ -41,7 +41,7 @@ EfhGraphicsStruct::EfhGraphicsStruct(int8 **lineBuf, int16 x, int16 y, int16 wid void InvObject::init() { _ref = 0; _stat1 = 0; - _stat2 = 0; + _curHitPoints = 0; } void UnkMapStruct::init() { @@ -144,7 +144,7 @@ uint8 MapMonster::getPronoun() { return _possessivePronounSHL6 >> 6; } -void Stru32686::init() { +void TeamMonsterEffect::init() { for (int i = 0; i < 9; ++i) { _effect[i] = 0; _duration[i] = 0; diff --git a/engines/efh/menu.cpp b/engines/efh/menu.cpp index fbf7b697c87e..b1efb776a2a4 100644 --- a/engines/efh/menu.cpp +++ b/engines/efh/menu.cpp @@ -341,9 +341,9 @@ void EfhEngine::displayCharacterSummary(int16 curMenuLine, int16 npcId) { setTextPos(262, textPosY); if (_items[itemId]._defense > 0) { - int16 stat2 = _npcBuf[npcId]._inventory[_menuStatItemArr[counter]]._stat2; - if (stat2 != 0xFF) { - buffer1 = Common::String::format("%d", 1 + stat2 / 8); + int16 curHitPoints = _npcBuf[npcId]._inventory[_menuStatItemArr[counter]]._curHitPoints; + if (curHitPoints != 0xFF) { + buffer1 = Common::String::format("%d", 1 + curHitPoints / 8); displayStringAtTextPos(buffer1); setTextPos(286, textPosY); displayStringAtTextPos("Def"); @@ -694,7 +694,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { return -1; } - sub19E2E(charId, objectId, windowId, menuId, curMenuLine, 2); + useObject(charId, objectId, windowId, menuId, curMenuLine, 2); break; case 2: objectId = _menuStatItemArr[selectedLine]; @@ -900,12 +900,12 @@ void EfhEngine::sub191FF(int16 charId, int16 objectId, int16 windowId, int16 men } } -int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 teamMonsterId, int16 menuId, int16 curMenuLine, int16 argA) { - debug("sub19E2E %d %d %d %d %d %d", charId, objectId, teamMonsterId, menuId, curMenuLine, argA); +int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, int16 menuId, int16 curMenuLine, int16 argA) { + debug("useObject %d %d %d %d %d %d", charId, objectId, teamMonsterId, menuId, curMenuLine, argA); Common::String buffer1 = ""; - bool varA6 = false; + bool objectUsedFl = false; bool retVal = false; int16 itemId = _npcBuf[charId]._inventory[objectId]._ref; @@ -947,7 +947,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 teamMonsterId, int _messageToBePrinted += buffer1; } - varA6 = true; + objectUsedFl = true; break; case 1: // "Chilling Touch", "Guilt", "Petrify Rod", "Elmer's Gun" if (argA == 2) { @@ -988,7 +988,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 teamMonsterId, int // } - varA6 = true; + objectUsedFl = true; break; case 2: if (argA == 2) { @@ -998,7 +998,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 teamMonsterId, int _unk2C8AA = 0; } - varA6 = true; + objectUsedFl = true; break; case 4: // "Unholy Sinwave", "Holy Water" if (argA == 2) { @@ -1022,7 +1022,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 teamMonsterId, int } } } - varA6 = true; + objectUsedFl = true; break; case 5: // "Lucifer'sTouch", "Book of Death", "Holy Cross" if (argA == 2) { @@ -1043,7 +1043,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 teamMonsterId, int } } - varA6 = true; + objectUsedFl = true; break; case 12: // "Terror Gaze", "Servitude Rod", "Despair Ankh", "ConfusionPrism", "Pipe of Peace", "Red Cape", "Peace Symbol", "Hell Badge" if (argA == 2) { @@ -1052,7 +1052,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 teamMonsterId, int _messageToBePrinted += " The magic sparkles brilliant hues in the air!"; setMapMonsterField8(teamMonsterId, _items[itemId]._field17_attackTypeDefense, true); } - varA6 = true; + objectUsedFl = true; break; case 14: { // "Feathered Cap" int16 varAA; @@ -1075,7 +1075,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 teamMonsterId, int _word32482[varAA] = 0; } - varA6 = true; + objectUsedFl = true; } break; case 15: { // "Regal Crown" int16 teamCharId; @@ -1099,7 +1099,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 teamMonsterId, int _teamPctVisible[teamCharId] = 0; } - varA6 = true; + objectUsedFl = true; } break; case 16: { // Fairy Dust _mapPosX = getRandom(_largeMapFlag ? 63 : 23); @@ -1135,7 +1135,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 teamMonsterId, int } } - varA6 = true; + objectUsedFl = true; } break; case 17: { // "Devil Dust" _mapPosX = _items[itemId]._field19_mapPosX_or_maxDeltaPoints; @@ -1170,7 +1170,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 teamMonsterId, int } } - varA6 = true; + objectUsedFl = true; } break; case 18: if (argA == 2) { @@ -1188,7 +1188,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 teamMonsterId, int } } - varA6 = true; + objectUsedFl = true; break; case 19: // "Junk" buffer1 = " * The item breaks!"; @@ -1198,7 +1198,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 teamMonsterId, int _messageToBePrinted += buffer1; } setCharacterObjectToBroken(charId, objectId); - varA6 = true; + objectUsedFl = true; break; case 23: // "Divining Rod" buffer1 = Common::String::format("The %s says, '", _items[itemId]._name); @@ -1235,7 +1235,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 teamMonsterId, int retVal = true; } - varA6 = true; + objectUsedFl = true; break; case 24: { int16 teamCharId; @@ -1265,7 +1265,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 teamMonsterId, int } } - varA6 = true; + objectUsedFl = true; } break; case 25: { int16 teamCharId; @@ -1295,7 +1295,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 teamMonsterId, int } } - varA6 = true; + objectUsedFl = true; } break; case 26: // "Black Sphere" buffer1 = "The entire party collapses, dead!!!"; @@ -1306,7 +1306,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 teamMonsterId, int retVal = true; } totalPartyKill(); - varA6 = true; + objectUsedFl = true; break; case 27: { // "Magic Pyramid", "Razor Blade" int16 teamCharId; @@ -1328,7 +1328,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 teamMonsterId, int } } - varA6 = true; + objectUsedFl = true; } break; case 28: // "Bugle" if (argA == 2) { @@ -1346,7 +1346,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 teamMonsterId, int } } - varA6 = true; + objectUsedFl = true; break; case 29: { // "Healing Spray", "Healing Elixir", "Curing Potion", "Magic Potion" int16 teamCharId; @@ -1376,7 +1376,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 teamMonsterId, int retVal = true; } - varA6 = true; + objectUsedFl = true; } break; case 30: { int16 teamCharId; @@ -1406,7 +1406,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 teamMonsterId, int retVal = true; } - varA6 = true; + objectUsedFl = true; } break; case 3: @@ -1424,7 +1424,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 teamMonsterId, int break; } - if (varA6) { + if (objectUsedFl) { int16 usesLeft = _npcBuf[charId]._inventory[objectId].getUsesLeft(); if (usesLeft != 0x7F) { --usesLeft; @@ -1438,6 +1438,7 @@ int16 EfhEngine::sub19E2E(int16 charId, int16 objectId, int16 teamMonsterId, int } setCharacterObjectToBroken(charId, objectId); } else { + // Keep the Equipped bit and set the new number of uses _npcBuf[charId]._inventory[objectId]._stat1 &= 0x80; _npcBuf[charId]._inventory[objectId]._stat1 |= usesLeft; } diff --git a/engines/efh/savegames.cpp b/engines/efh/savegames.cpp index 8b9239d6bc3e..00b9ea278f5b 100644 --- a/engines/efh/savegames.cpp +++ b/engines/efh/savegames.cpp @@ -191,7 +191,7 @@ void EfhEngine::synchronize(Common::Serializer &s) { for (int idx = 0; idx < 10; ++idx) { s.syncAsSint16LE(_npcBuf[i]._inventory[idx]._ref); s.syncAsByte(_npcBuf[i]._inventory[idx]._stat1); - s.syncAsByte(_npcBuf[i]._inventory[idx]._stat2); + s.syncAsByte(_npcBuf[i]._inventory[idx]._curHitPoints); } s.syncAsByte(_npcBuf[i]._possessivePronounSHL6); s.syncAsByte(_npcBuf[i]._speed); From 69e5fb04cb3ee612cbcee9233a5e0813155badac Mon Sep 17 00:00:00 2001 From: Strangerke Date: Mon, 2 Jan 2023 14:00:20 +0100 Subject: [PATCH 213/412] EFH: Validate 2 functions, renaming --- engines/efh/efh.cpp | 2 +- engines/efh/efh.h | 2 +- engines/efh/fight.cpp | 24 ++++++++++++------------ engines/efh/menu.cpp | 10 +++++----- engines/efh/script.cpp | 4 ++-- 5 files changed, 21 insertions(+), 21 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 1a91cebaa350..3df4c7c9ad03 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -2056,7 +2056,7 @@ void EfhEngine::displayImp1Text(int16 textId) { displayFctFullScreen(); } - nextTextId = sub1C219(_messageToBePrinted, 1, 1, true); + nextTextId = displayBoxWithText(_messageToBePrinted, 1, 1, true); if (nextTextId != 0xFF) curTextId = nextTextId; diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 74972893b43c..ce4b283c7673 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -454,7 +454,7 @@ class EfhEngine : public Engine { void displayColoredMenuBox(int16 minX, int16 minY, int16 maxX, int16 maxY, int16 color); // Menu - int16 sub1C219(Common::String str, int16 menuType, int16 displayOption, bool displayTeamWindowFl); + int16 displayBoxWithText(Common::String str, int16 menuType, int16 displayOption, bool displayTeamWindowFl); bool handleDeathMenu(); void displayCombatMenu(int16 charId); void displayMenuItemString(int16 menuBoxId, int16 thisBoxId, int16 minX, int16 maxX, int16 minY, const char *str); diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index e61fa8662a0c..8dcae3e79e3b 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -129,7 +129,7 @@ bool EfhEngine::handleFight(int16 monsterId) { } computeInitiatives(); - sub1C219("", 2, 1, false); + displayBoxWithText("", 2, 1, false); for (uint counter = 0; counter < 8; ++counter) { int16 monsterGroupIdOrMonsterId = _initiatives[counter]._id; @@ -333,7 +333,7 @@ bool EfhEngine::handleFight(int16 monsterId) { _messageToBePrinted = Common::String::format("%s%s tries to use %s %s, but it doesn't work!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPossessive[ennemyPronoun], _nameBuffer.c_str()); } genericGenerateSound(_items[unk_monsterField5_itemId]._attackType, var62); - sub1C219(_messageToBePrinted, 1, 2, true); + displayBoxWithText(_messageToBePrinted, 1, 2, true); } // handleFight - Loop on var7E - End } @@ -359,7 +359,7 @@ bool EfhEngine::handleFight(int16 monsterId) { break; } _teamMonsterEffects[monsterGroupIdOrMonsterId]._effect[var86] = 0; - sub1C219(_messageToBePrinted, 1, 2, true); + displayBoxWithText(_messageToBePrinted, 1, 2, true); } } } @@ -412,7 +412,7 @@ void EfhEngine::handleFight_checkEndEffect(int16 charId) { _teamCharStatus[charId]._status = 0; // Finally, display the message - sub1C219(_messageToBePrinted, 1, 2, true); + displayBoxWithText(_messageToBePrinted, 1, 2, true); } void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { @@ -617,7 +617,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { } genericGenerateSound(_items[unk_monsterField5_itemId]._attackType, var62); - sub1C219(_messageToBePrinted, 1, 2, true); + displayBoxWithText(_messageToBePrinted, 1, 2, true); } } } @@ -638,11 +638,11 @@ void EfhEngine::handleFight_lastAction_D(int16 teamCharId) { _enemyNamePt1 = ""; _messageToBePrinted = Common::String::format("%s%s prepares to defend %sself!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPersonal[pronoun]); - sub1C219(_messageToBePrinted, 1, 2, true); + displayBoxWithText(_messageToBePrinted, 1, 2, true); } void EfhEngine::handleFight_lastAction_H(int16 teamCharId) { - debug("handleFight_lastAction_H %d", teamCharId); + debugC(3, kDebugEngine, "handleFight_lastAction_H %d", teamCharId); // In the original, this function is part of handleFight. // It has been split for readability purposes. @@ -657,7 +657,7 @@ void EfhEngine::handleFight_lastAction_H(int16 teamCharId) { _enemyNamePt1 = ""; _messageToBePrinted = Common::String::format("%s%s attempts to hide %sself!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPersonal[pronoun]); - sub1C219(_messageToBePrinted, 1, 2, true); + displayBoxWithText(_messageToBePrinted, 1, 2, true); } bool EfhEngine::handleFight_lastAction_U(int16 teamCharId) { @@ -677,7 +677,7 @@ bool EfhEngine::handleFight_lastAction_U(int16 teamCharId) { _messageToBePrinted = Common::String::format("%s%s uses %s %s! ", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPossessive[pronoun], _nameBuffer.c_str()); bool retVal = useObject(_teamCharId[teamCharId], _word31780[teamCharId], _teamNextAttack[teamCharId], teamCharId, 0, 3); - sub1C219(_messageToBePrinted, 1, 2, true); + displayBoxWithText(_messageToBePrinted, 1, 2, true); return retVal; } @@ -1009,7 +1009,7 @@ int16 EfhEngine::sub1C956(int16 charId, int16 unkFied18Val, bool arg4) { for (uint counter = 0; counter < 2; ++counter) { drawCombatScreen(charId, true, false); if (_teamMonsterIdArray[1] != -1) - sub1C219("Select Monster Group:", 3, 0, false); + displayBoxWithText("Select Monster Group:", 3, 0, false); if (counter == 0) displayFctFullScreen(); @@ -1105,7 +1105,7 @@ bool EfhEngine::sub1CB27() { case 28: case 29: case 30: - sub1C219("Select Character:", 3, 1, false); + displayBoxWithText("Select Character:", 3, 1, false); _teamNextAttack[counter1] = selectOtherCharFromTeam(); break; @@ -1149,7 +1149,7 @@ void EfhEngine::drawCombatScreen(int16 charId, bool whiteFl, bool forceDrawFl) { displayCenteredString("Combat", 128, 303, 9); drawColoredRect(200, 112, 278, 132, 0); displayCenteredString("'T' for Terrain", 128, 303, 117); - sub1C219("", 1, 0, false); + displayBoxWithText("", 1, 0, false); sub1C4CA(whiteFl); displayCombatMenu(charId); displayLowStatusScreen(false); diff --git a/engines/efh/menu.cpp b/engines/efh/menu.cpp index b1efb776a2a4..25fa0b0cbb00 100644 --- a/engines/efh/menu.cpp +++ b/engines/efh/menu.cpp @@ -23,10 +23,10 @@ namespace Efh { -int16 EfhEngine::sub1C219(Common::String str, int16 menuType, int16 displayOption, bool displayTeamWindowFl) { - debug("sub1C219 %s %d %d %s", str.c_str(), menuType, displayOption, displayTeamWindowFl ? "True" : "False"); +int16 EfhEngine::displayBoxWithText(Common::String str, int16 menuType, int16 displayOption, bool displayTeamWindowFl) { + debugC(3, kDebugEngine, "displayBoxWithText %s %d %d %s", str.c_str(), menuType, displayOption, displayTeamWindowFl ? "True" : "False"); - int16 varA = 0xFF; + int16 retVal = 0xFF; int16 minX, maxX, minY, maxY; switch (menuType) { @@ -63,7 +63,7 @@ int16 EfhEngine::sub1C219(Common::String str, int16 menuType, int16 displayOptio drawColoredRect(minX, minY, maxX, maxY, 0); if (!str.empty()) - varA = script_parse(str, minX, minY, maxX, maxY, true); + retVal = script_parse(str, minX, minY, maxX, maxY, true); if (displayTeamWindowFl) displayLowStatusScreen(false); @@ -88,7 +88,7 @@ int16 EfhEngine::sub1C219(Common::String str, int16 menuType, int16 displayOptio drawColoredRect(minX, minY, maxX, maxY, 0); } - return varA; + return retVal; } bool EfhEngine::handleDeathMenu() { diff --git a/engines/efh/script.cpp b/engines/efh/script.cpp index aa901340a648..2f650d87ff97 100644 --- a/engines/efh/script.cpp +++ b/engines/efh/script.cpp @@ -385,7 +385,7 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos drawMapWindow(); displayFctFullScreen(); drawMapWindow(); - scriptRandomItemId = sub1C219("Nothing...", 1, 2, true); + scriptRandomItemId = displayBoxWithText("Nothing...", 1, 2, true); displayFctFullScreen(); } else { _enemyNamePt2 = _npcBuf[_teamCharId[counter]]._name; @@ -394,7 +394,7 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos drawMapWindow(); displayFctFullScreen(); drawMapWindow(); - scriptRandomItemId = sub1C219(curLine, 1, 2, true); + scriptRandomItemId = displayBoxWithText(curLine, 1, 2, true); displayFctFullScreen(); } From 231a5bca12c718426787068b96fd1664e926c48f Mon Sep 17 00:00:00 2001 From: Strangerke Date: Tue, 3 Jan 2023 07:56:56 +0100 Subject: [PATCH 214/412] EFH: Fix bug in tryToggleEquipped, renaming and validation of some more functions --- engines/efh/efh.cpp | 17 +++++++------- engines/efh/efh.h | 10 ++++---- engines/efh/fight.cpp | 50 +++++++++++++++++++++------------------- engines/efh/files.cpp | 4 ++-- engines/efh/init.cpp | 2 +- engines/efh/menu.cpp | 53 +++++++++++++++++++++---------------------- 6 files changed, 70 insertions(+), 66 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 3df4c7c9ad03..641e5592f95c 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -558,22 +558,23 @@ int16 EfhEngine::getEquipmentDefense(int16 charId, bool flag) { return altDef; } -uint16 EfhEngine::sub1C80A(int16 charId, int16 field18, bool flag) { - debugC(2, kDebugEngine, "sub1C80A %d %d %s", charId, field18, flag ? "True" : "False"); +uint16 EfhEngine::getEquippedExclusiveType(int16 charId, int16 exclusiveType, bool flag) { + debugC(2, kDebugEngine, "getEquippedExclusiveType %d %d %s", charId, exclusiveType, flag ? "True" : "False"); for (int i = 0; i < 10; ++i) { if (!_npcBuf[charId]._inventory[i].isEquipped()) continue; - int16 itemId = _npcBuf[charId]._inventory[i]._ref; + int16 curItemId = _npcBuf[charId]._inventory[i]._ref; - if (_items[itemId].field_18 != field18) + if (_items[curItemId]._exclusiveType != exclusiveType) continue; + // If flag is set, returns the ItemId, otherwise return the inventory slot number if (!flag) return i; - return itemId; + return curItemId; } return 0x7FFF; @@ -759,11 +760,11 @@ void EfhEngine::displayLowStatusScreen(bool flag) { switch (_teamCharStatus[i]._status) { case 0: { - uint16 var4 = sub1C80A(charId, 9, true); - if (var4 == 0x7FFF) + uint16 exclusiveItemId = getEquippedExclusiveType(charId, 9, true); + if (exclusiveItemId == 0x7FFF) _nameBuffer = "(NONE)"; else - _nameBuffer = _items[var4]._name; + _nameBuffer = _items[exclusiveItemId]._name; } break; case 1: diff --git a/engines/efh/efh.h b/engines/efh/efh.h index ce4b283c7673..b8bf9a66ebed 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -125,7 +125,7 @@ struct ItemStruct { uint8 _attackType; uint8 _specialEffect; uint8 _field17_attackTypeDefense; - uint8 field_18; + uint8 _exclusiveType; uint8 _field19_mapPosX_or_maxDeltaPoints; uint8 _mapPosY; @@ -292,7 +292,7 @@ class EfhEngine : public Engine { void loadMapArrays(int idx); void saveAnimImageSetId(); int16 getEquipmentDefense(int16 charId, bool flag); - uint16 sub1C80A(int16 charId, int16 field18, bool flag); + uint16 getEquippedExclusiveType(int16 charId, int16 exclusiveType, bool flag); void displayLowStatusScreen(bool flag); void loadImageSetToTileBank(int16 tileBankId, int16 imageSetId); void restoreAnimImageSetId(); @@ -463,12 +463,12 @@ class EfhEngine : public Engine { void displayCharacterSummary(int16 curMenuLine, int16 npcId); void displayCharacterInformationOrSkills(int16 curMenuLine, int16 npcId); void displayStatusMenuActions(int16 menuId, int16 curMenuLine, int16 npcId); - void prepareStatusMenu(int16 windowId, int16 menuId, int16 curMenuLine, int16 charId, bool unusedFl, bool refreshFl); - void sub18E80(int16 charId, int16 windowId, int16 menuId, int16 curMenuLine); + void prepareStatusMenu(int16 windowId, int16 menuId, int16 curMenuLine, int16 charId, bool refreshFl); + void displayWindowAndStatusMenu(int16 charId, int16 windowId, int16 menuId, int16 curMenuLine); int16 displayString_3(Common::String str, bool animFl, int16 charId, int16 windowId, int16 menuId, int16 curMenuLine); int16 handleStatusMenu(int16 gameMode, int16 charId); void unequipItem(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine); - void sub191FF(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine); + void tryToggleEquipped(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine); int16 useObject(int16 charId, int16 objectId, int16 teamMonsterId, int16 menuId, int16 curMenuLine, int16 argA); // Savegames diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index 8dcae3e79e3b..88cc1edca0fc 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -421,9 +421,9 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { // In the original, this function is part of handleFight. // It has been split for readability purposes. - int16 unk_monsterField5_itemId = sub1C80A(_teamCharId[teamCharId], 9, true); - if (unk_monsterField5_itemId == 0x7FFF) - unk_monsterField5_itemId = 0x3F; + int16 teamCharItemId = getEquippedExclusiveType(_teamCharId[teamCharId], 9, true); + if (teamCharItemId == 0x7FFF) + teamCharItemId = 0x3F; int16 monsterGroupNumber = _teamNextAttack[teamCharId]; if (monsterGroupNumber == 0x64) monsterGroupNumber = 0; @@ -431,14 +431,14 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { if (monsterGroupNumber == -1) return; int16 var58; - if (_items[unk_monsterField5_itemId]._range == 4) + if (_items[teamCharItemId]._range == 4) var58 = 5; else var58 = monsterGroupNumber + 1; int16 var54; int16 teamMemberId; - if (_items[unk_monsterField5_itemId]._range < 3) { + if (_items[teamCharItemId]._range < 3) { teamMemberId = sub1DEC8(monsterGroupNumber); var54 = teamMemberId + 1; } else { @@ -467,19 +467,19 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { int16 var70 = _npcBuf[varInt].getPronoun(); varInt = _teamMonsterIdArray[groupId]; int16 var5E = kEncounters[_mapMonsters[varInt]._monsterRef]._nameArticle; - int16 charScore = getCharacterScore(_teamCharId[teamCharId], unk_monsterField5_itemId); + int16 charScore = getCharacterScore(_teamCharId[teamCharId], teamCharItemId); int16 hitPointsBefore = _mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[var7E]; int16 var62 = 0; int16 originalDamage = 0; int16 damagePointsAbsorbed = 0; - int16 var64 = _items[unk_monsterField5_itemId]._attacks * _npcBuf[_teamCharId[teamCharId]]._speed; + int16 var64 = _items[teamCharItemId]._attacks * _npcBuf[_teamCharId[teamCharId]]._speed; // Action A - Loop var84 - Start for (int var84 = 0; var84 < var64; ++var84) { if (getRandom(100) < charScore) { ++var62; - if (!hasAdequateDefense(_teamMonsterIdArray[groupId], _items[unk_monsterField5_itemId]._attackType)) { - int16 var7C = getRandom(_items[unk_monsterField5_itemId]._damage); + if (!hasAdequateDefense(_teamMonsterIdArray[groupId], _items[teamCharItemId]._attackType)) { + int16 var7C = getRandom(_items[teamCharItemId]._damage); varInt = var7C - var76; if (varInt > 0) { originalDamage += varInt; @@ -497,7 +497,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { int16 hitPoints = originalDamage + damagePointsAbsorbed; - if (!checkSpecialItemsOnCurrentPlace(unk_monsterField5_itemId)) + if (!checkSpecialItemsOnCurrentPlace(teamCharItemId)) var62 = 0; if (var62 > 0) { @@ -508,7 +508,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { _attackBuffer = ""; } } - int16 var68 = _items[unk_monsterField5_itemId]._attackType + 1; + int16 var68 = _items[teamCharItemId]._attackType + 1; int16 var6A = getRandom(3) - 1; if (var5E == 2) { _characterNamePt1 = "The "; @@ -524,8 +524,8 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { _characterNamePt2 = kEncounters[_mapMonsters[_teamMonsterIdArray[groupId]]._monsterRef]._name; _enemyNamePt2 = _npcBuf[_teamCharId[teamCharId]]._name; - _nameBuffer = _items[unk_monsterField5_itemId]._name; - if (checkSpecialItemsOnCurrentPlace(unk_monsterField5_itemId)) { + _nameBuffer = _items[teamCharItemId]._name; + if (checkSpecialItemsOnCurrentPlace(teamCharItemId)) { // Action A - Check damages - Start if (var62 == 0) { _messageToBePrinted = Common::String::format("%s%s %s at %s%s with %s %s, but misses!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1.c_str(), _characterNamePt2.c_str(), kPossessive[var70], _nameBuffer.c_str()); @@ -585,7 +585,9 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { // Action A - Check item durability - Start varInt = _teamCharId[teamCharId]; - var64 = sub1C80A(varInt, 9, false); + + // get equipped inventory slot with exclusiveType == 9 + var64 = getEquippedExclusiveType(varInt, 9, false); if (var64 != 0x7FFF && _npcBuf[varInt]._inventory[var64].getUsesLeft() != 0x7F) { int16 usesLeft = _npcBuf[varInt]._inventory[var64].getUsesLeft(); --usesLeft; @@ -600,13 +602,13 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { // Action A - Check item durability - End // Action A - Check effect - Start - if (_items[unk_monsterField5_itemId]._specialEffect == 1 && _mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[var7E] > 0) { + if (_items[teamCharItemId]._specialEffect == 1 && _mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[var7E] > 0) { if (getRandom(100) < 35) { _teamMonsterEffects[groupId]._effect[var7E] = 1; _teamMonsterEffects[groupId]._duration[var7E] = getRandom(10); _messageToBePrinted += Common::String::format(" %s%s falls asleep!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); } - } else if (_items[unk_monsterField5_itemId]._specialEffect == 2 && _mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[var7E] > 0) { + } else if (_items[teamCharItemId]._specialEffect == 2 && _mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[var7E] > 0) { _teamMonsterEffects[groupId]._effect[var7E] = 2; _teamMonsterEffects[groupId]._duration[var7E] = getRandom(10); _messageToBePrinted += Common::String::format(" %s%s is frozen!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); @@ -616,7 +618,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { _messageToBePrinted = Common::String::format("%s%s tries to use %s %s, but it doesn't work!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPossessive[var70], _nameBuffer.c_str()); } - genericGenerateSound(_items[unk_monsterField5_itemId]._attackType, var62); + genericGenerateSound(_items[teamCharItemId]._attackType, var62); displayBoxWithText(_messageToBePrinted, 1, 2, true); } } @@ -756,11 +758,11 @@ void EfhEngine::getDeathTypeDescription(int16 attackerId, int16 victimId) { if (charId == -1) deathType = 0; else { - int16 var6 = sub1C80A(charId, 9, true); - if (var6 == 0x7FFF) + int16 exclusiveItemId = getEquippedExclusiveType(charId, 9, true); + if (exclusiveItemId == 0x7FFF) deathType = 0; else - deathType = _items[var6]._attackType + 1; + deathType = _items[exclusiveItemId]._attackType + 1; } } else if (_teamMonsterIdArray[victimId] == -1) deathType = 0; @@ -985,17 +987,19 @@ int16 EfhEngine::sub1C956(int16 charId, int16 unkFied18Val, bool arg4) { int16 varE = -1; - int16 var6 = sub1C80A(charId, unkFied18Val, true); + int16 curItemId = getEquippedExclusiveType(charId, unkFied18Val, true); int16 range = 0; - if (var6 != 0x7FFF) - range = _items[var6]._range; + if (curItemId != 0x7FFF) + range = _items[curItemId]._range; switch (range) { case 3: case 2: ++range; + // no break on purpose case 1: ++range; + // no break on purpose case 0: ++range; break; diff --git a/engines/efh/files.cpp b/engines/efh/files.cpp index 54f0446fa9eb..aa5ed2e9f1ce 100644 --- a/engines/efh/files.cpp +++ b/engines/efh/files.cpp @@ -150,11 +150,11 @@ void EfhEngine::readItems() { _items[i]._attackType = f.readByte(); _items[i]._specialEffect = f.readByte(); _items[i]._field17_attackTypeDefense = f.readByte(); - _items[i].field_18 = f.readByte(); + _items[i]._exclusiveType = f.readByte(); _items[i]._field19_mapPosX_or_maxDeltaPoints = f.readByte(); _items[i]._mapPosY = f.readByte(); - debugC(7, kDebugEngine, "%s\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x", _items[i]._name, _items[i]._damage, _items[i]._defense, _items[i]._attacks, _items[i]._uses, _items[i].field_13, _items[i]._range, _items[i]._attackType, _items[i]._specialEffect, _items[i]._field17_attackTypeDefense, _items[i].field_18, _items[i]._field19_mapPosX_or_maxDeltaPoints, _items[i]._mapPosY); + debugC(7, kDebugEngine, "%s\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x", _items[i]._name, _items[i]._damage, _items[i]._defense, _items[i]._attacks, _items[i]._uses, _items[i].field_13, _items[i]._range, _items[i]._attackType, _items[i]._specialEffect, _items[i]._field17_attackTypeDefense, _items[i]._exclusiveType, _items[i]._field19_mapPosX_or_maxDeltaPoints, _items[i]._mapPosY); } } diff --git a/engines/efh/init.cpp b/engines/efh/init.cpp index e5839e9e68b5..e5a9af06e93f 100644 --- a/engines/efh/init.cpp +++ b/engines/efh/init.cpp @@ -76,7 +76,7 @@ void ItemStruct::init() { _attackType = 0; _specialEffect = 0; _field17_attackTypeDefense = 0; - field_18 = 0; + _exclusiveType = 0; _field19_mapPosX_or_maxDeltaPoints = 0; _mapPosY = 0; } diff --git a/engines/efh/menu.cpp b/engines/efh/menu.cpp index 25fa0b0cbb00..cc52561ca43e 100644 --- a/engines/efh/menu.cpp +++ b/engines/efh/menu.cpp @@ -455,7 +455,7 @@ void EfhEngine::displayStatusMenuActions(int16 menuId, int16 curMenuLine, int16 } } -void EfhEngine::prepareStatusMenu(int16 windowId, int16 menuId, int16 curMenuLine, int16 charId, bool unusedFl, bool refreshFl) { +void EfhEngine::prepareStatusMenu(int16 windowId, int16 menuId, int16 curMenuLine, int16 charId, bool refreshFl) { debugC(6, kDebugEngine, "prepareStatusMenu %d %d %d %d %s", windowId, menuId, curMenuLine, charId, refreshFl ? "True" : "False"); displayStatusMenu(windowId); @@ -467,12 +467,12 @@ void EfhEngine::prepareStatusMenu(int16 windowId, int16 menuId, int16 curMenuLin displayFctFullScreen(); } -void EfhEngine::sub18E80(int16 charId, int16 windowId, int16 menuId, int16 curMenuLine) { - debug("sub18E80 %d %d %d %d", charId, windowId, menuId, curMenuLine); +void EfhEngine::displayWindowAndStatusMenu(int16 charId, int16 windowId, int16 menuId, int16 curMenuLine) { + debug("displayWindowAndStatusMenu %d %d %d %d", charId, windowId, menuId, curMenuLine); for (int counter = 0; counter < 2; ++counter) { displayWindow(_menuBuf, 0, 0, _hiResImageBuf); - prepareStatusMenu(windowId, menuId, curMenuLine, charId, true, false); + prepareStatusMenu(windowId, menuId, curMenuLine, charId, false); if (counter == 0) displayFctFullScreen(); @@ -485,7 +485,7 @@ int16 EfhEngine::displayString_3(Common::String str, bool animFl, int16 charId, int16 retVal = 0; for (uint counter = 0; counter < 2; ++counter) { - prepareStatusMenu(windowId, menuId, curMenuLine, charId, true, false); + prepareStatusMenu(windowId, menuId, curMenuLine, charId, false); displayWindow(_windowWithBorderBuf, 19, 113, _hiResImageBuf); if (counter == 0) { @@ -498,7 +498,7 @@ int16 EfhEngine::displayString_3(Common::String str, bool animFl, int16 charId, if (animFl) { getLastCharAfterAnimCount(_guessAnimationAmount); - sub18E80(charId, windowId, menuId, curMenuLine); + displayWindowAndStatusMenu(charId, windowId, menuId, curMenuLine); } return retVal; @@ -519,11 +519,11 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { _statusMenuActive = true; _menuDepth = 0; - sub18E80(charId, windowId, menuId, curMenuLine); + displayWindowAndStatusMenu(charId, windowId, menuId, curMenuLine); for (;;) { if (windowId != -1) - prepareStatusMenu(windowId, menuId, curMenuLine, charId, true, true); + prepareStatusMenu(windowId, menuId, curMenuLine, charId, true); else windowId = 0; @@ -603,7 +603,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { _menuDepth = 0; curMenuLine = -1; menuId = 9; - prepareStatusMenu(windowId, menuId, curMenuLine, charId, true, true); + prepareStatusMenu(windowId, menuId, curMenuLine, charId, true); } else { selectedLine = curMenuLine; var10 = true; @@ -614,7 +614,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { _menuDepth = 0; curMenuLine = -1; menuId = 9; - prepareStatusMenu(windowId, menuId, curMenuLine, charId, true, true); + prepareStatusMenu(windowId, menuId, curMenuLine, charId, true); break; case Common::KEYCODE_2: case Common::KEYCODE_6: @@ -658,10 +658,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { break; } - if (curMenuLine == -1) - prepareStatusMenu(windowId, menuId, curMenuLine, charId, false, true); - else - prepareStatusMenu(windowId, menuId, curMenuLine, charId, true, true); + prepareStatusMenu(windowId, menuId, curMenuLine, charId, true); } while (!var10); @@ -673,7 +670,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { case 0: objectId = _menuStatItemArr[selectedLine]; itemId = _npcBuf[charId]._inventory[objectId]._ref; // CHECKME: Useless? - sub191FF(charId, objectId, windowId, menuId, curMenuLine); + tryToggleEquipped(charId, objectId, windowId, menuId, curMenuLine); if (gameMode == 2) { restoreAnimImageSetId(); _statusMenuActive = false; @@ -705,7 +702,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { displayString_3("Item is Equipped! Give anyway?", false, charId, windowId, menuId, curMenuLine); if (!getValidationFromUser()) validationFl = false; - sub18E80(charId, windowId, menuId, curMenuLine); + displayWindowAndStatusMenu(charId, windowId, menuId, curMenuLine); if (validationFl) { if (gameMode == 2) { @@ -731,7 +728,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { displayString_3("Item is Equipped! Trade anyway?", false, charId, windowId, menuId, curMenuLine); if (!getValidationFromUser()) validationFl = false; - sub18E80(charId, windowId, menuId, curMenuLine); + displayWindowAndStatusMenu(charId, windowId, menuId, curMenuLine); if (validationFl) { bool givenFl; @@ -777,7 +774,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { } } - sub18E80(charId, windowId, menuId, curMenuLine); + displayWindowAndStatusMenu(charId, windowId, menuId, curMenuLine); } } break; @@ -790,7 +787,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { displayString_3("Item Is Equipped! Drop Anyway?", false, charId, windowId, menuId, curMenuLine); if (!getValidationFromUser()) validationFl = false; - sub18E80(charId, windowId, menuId, curMenuLine); + displayWindowAndStatusMenu(charId, windowId, menuId, curMenuLine); if (validationFl) { removeObject(charId, objectId); @@ -879,24 +876,26 @@ void EfhEngine::unequipItem(int16 charId, int16 objectId, int16 windowId, int16 } } -void EfhEngine::sub191FF(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine) { - debug("sub191FF %d %d %d %d %d", charId, objectId, windowId, menuId, curMenuLine); +void EfhEngine::tryToggleEquipped(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine) { + debugC(3, kDebugEngine, "tryToggleEquipped %d %d %d %d %d", charId, objectId, windowId, menuId, curMenuLine); int16 itemId = _npcBuf[charId]._inventory[objectId]._ref; if (hasObjectEquipped(charId, objectId)) { unequipItem(charId, objectId, windowId, menuId, curMenuLine); } else { - int16 var2 = _items[itemId].field_18; - if (var2 != 4) { + int16 curType = _items[itemId]._exclusiveType; + if (curType != 4) { for (uint counter = 0; counter < 10; ++counter) { - if (var2 == _items[_npcBuf[charId]._inventory[counter]._ref].field_18) + if (curType == _items[_npcBuf[charId]._inventory[counter]._ref]._exclusiveType) unequipItem(charId, objectId, windowId, menuId, curMenuLine); } } - // Set item as Equipped - _npcBuf[charId]._inventory[objectId]._stat1 |= 0x80; + if (curType != 0) { + // Set item as Equipped + _npcBuf[charId]._inventory[objectId]._stat1 |= 0x80; + } } } @@ -1446,7 +1445,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in if (argA == 2) { getLastCharAfterAnimCount(_guessAnimationAmount); - sub18E80(charId, teamMonsterId, menuId, curMenuLine); + displayWindowAndStatusMenu(charId, teamMonsterId, menuId, curMenuLine); } } From 7122fd549bb54ab57fe311d1be5b8ee9e0fc60b0 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Tue, 3 Jan 2023 23:23:46 +0100 Subject: [PATCH 215/412] EFH: More renaming --- engines/efh/efh.cpp | 34 +++++----- engines/efh/efh.h | 8 +-- engines/efh/fight.cpp | 144 +++++++++++++++++++++--------------------- engines/efh/menu.cpp | 2 +- 4 files changed, 93 insertions(+), 95 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 641e5592f95c..bc8264880c95 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -451,7 +451,7 @@ void EfhEngine::initMapMonsters() { debugC(3, kDebugEngine, "initMapMonsters"); for (uint monsterId = 0; monsterId < 64; ++monsterId) { - if (_mapMonsters[monsterId]._guess_fullPlaceId == 0xFF) + if (_mapMonsters[monsterId]._fullPlaceId == 0xFF) continue; for (uint counter = 0; counter < 9; ++counter) @@ -501,11 +501,11 @@ void EfhEngine::loadMapArrays(int idx) { for (int i = 0; i < 64; ++i) { _mapMonsters[i]._possessivePronounSHL6 = mapMonstersPtr[29 * i]; _mapMonsters[i]._npcId = mapMonstersPtr[29 * i + 1]; - _mapMonsters[i]._guess_fullPlaceId = mapMonstersPtr[29 * i + 2]; + _mapMonsters[i]._fullPlaceId = mapMonstersPtr[29 * i + 2]; _mapMonsters[i]._posX = mapMonstersPtr[29 * i + 3]; _mapMonsters[i]._posY = mapMonstersPtr[29 * i + 4]; - _mapMonsters[i]._itemId_Weapon = mapMonstersPtr[29 * i + 5]; - _mapMonsters[i]._field_6 = mapMonstersPtr[29 * i + 6]; + _mapMonsters[i]._weaponItemId = mapMonstersPtr[29 * i + 5]; + _mapMonsters[i]._maxDamageAbsorption = mapMonstersPtr[29 * i + 6]; _mapMonsters[i]._monsterRef = mapMonstersPtr[29 * i + 7]; _mapMonsters[i]._moveInfo = mapMonstersPtr[29 * i + 8]; _mapMonsters[i]._field9_textId = mapMonstersPtr[29 * i + 9]; @@ -667,7 +667,7 @@ void EfhEngine::drawMap(bool largeMapFl, int16 mapPosX, int16 mapPosY, int16 map if (drawMonstersFl) { for (uint var16 = 0; var16 < 64; ++var16) { - if ((_largeMapFlag && _mapMonsters[var16]._guess_fullPlaceId == 0xFE) || (!_largeMapFlag && _mapMonsters[var16]._guess_fullPlaceId == _fullPlaceId)){ + if ((_largeMapFlag && _mapMonsters[var16]._fullPlaceId == 0xFE) || (!_largeMapFlag && _mapMonsters[var16]._fullPlaceId == _fullPlaceId)){ bool var4 = false; int16 posX = _mapMonsters[var16]._posX; int16 posY = _mapMonsters[var16]._posY; @@ -1371,7 +1371,7 @@ int8 EfhEngine::checkMonsterMoveCollisionAndTileTexture(int16 monsterId) { if (!checkMapMonsterAvailability(counter)) continue; - if (_mapMonsters[monsterId]._guess_fullPlaceId == _mapMonsters[counter]._guess_fullPlaceId + if (_mapMonsters[monsterId]._fullPlaceId == _mapMonsters[counter]._fullPlaceId && _mapMonsters[monsterId]._posX == _mapMonsters[counter]._posX && _mapMonsters[monsterId]._posY == _mapMonsters[counter]._posY) return 0; @@ -1560,7 +1560,7 @@ bool EfhEngine::checkTeamWeaponRange(int16 monsterId) { return true; for (uint counter = 0; counter < 5; ++counter) { - if (_teamMonsterIdArray[counter] == monsterId && checkMonsterMovementType(monsterId, false) && checkWeaponRange(monsterId, _mapMonsters[monsterId]._itemId_Weapon)) + if (_teamMonsterIdArray[counter] == monsterId && checkMonsterMovementType(monsterId, false) && checkWeaponRange(monsterId, _mapMonsters[monsterId]._weaponItemId)) return false; } @@ -1570,10 +1570,10 @@ bool EfhEngine::checkTeamWeaponRange(int16 monsterId) { bool EfhEngine::checkIfMonsterOnSameLargeMapPlace(int16 monsterId) { debugC(6, kDebugEngine, "checkIfMonsterOnSameLargeMapPlace %d", monsterId); - if (_largeMapFlag && _mapMonsters[monsterId]._guess_fullPlaceId == 0xFE) + if (_largeMapFlag && _mapMonsters[monsterId]._fullPlaceId == 0xFE) return true; - if (!_largeMapFlag && _mapMonsters[monsterId]._guess_fullPlaceId == _fullPlaceId) + if (!_largeMapFlag && _mapMonsters[monsterId]._fullPlaceId == _fullPlaceId) return true; return false; @@ -1582,7 +1582,7 @@ bool EfhEngine::checkIfMonsterOnSameLargeMapPlace(int16 monsterId) { bool EfhEngine::checkMonsterWeaponRange(int16 monsterId) { debugC(6, kDebugEngine, "checkMonsterWeaponRange %d", monsterId); - return checkWeaponRange(monsterId, _mapMonsters[monsterId]._itemId_Weapon); + return checkWeaponRange(monsterId, _mapMonsters[monsterId]._weaponItemId); } void EfhEngine::handleMapMonsterMoves() { @@ -1759,7 +1759,7 @@ void EfhEngine::handleMapMonsterMoves() { bool EfhEngine::checkMapMonsterAvailability(int16 monsterId) { debugC(6, kDebugEngine, "checkMapMonsterAvailability %d", monsterId); - if (_mapMonsters[monsterId]._guess_fullPlaceId == 0xFF) + if (_mapMonsters[monsterId]._fullPlaceId == 0xFF) return false; for (uint counter = 0; counter < 9; ++counter) { @@ -1804,7 +1804,7 @@ bool EfhEngine::checkMonsterGroupDistance1OrLess(int16 monsterId) { bool EfhEngine::handleTalk(int16 monsterId, int16 arg2, int16 itemId) { debug("handleTalk %d %d %d", monsterId, arg2, itemId); - if (_mapMonsters[monsterId]._guess_fullPlaceId == 0xFF) + if (_mapMonsters[monsterId]._fullPlaceId == 0xFF) return false; if (countAliveMonsters(monsterId) < 1) @@ -2336,7 +2336,7 @@ void EfhEngine::sub1BE9A(int16 monsterId) { break; for (uint ctrMapMonsterId = 0; ctrMapMonsterId < 64; ++ctrMapMonsterId) { - if (_mapMonsters[ctrMapMonsterId]._guess_fullPlaceId == 0xFF) + if (_mapMonsters[ctrMapMonsterId]._fullPlaceId == 0xFF) continue; if (((_mapMonsters[ctrMapMonsterId]._possessivePronounSHL6 & 0x3F) == 0x3F && !isNpcATeamMember(_mapMonsters[ctrMapMonsterId]._npcId)) || (_mapMonsters[ctrMapMonsterId]._possessivePronounSHL6 & 0x3F) <= 0x3D) { @@ -2511,8 +2511,8 @@ bool EfhEngine::hasObjectEquipped(int16 charId, int16 objectId) { } -void EfhEngine::setMapMonsterField8(int16 id, uint8 movementType, bool groupFl) { - debugC(2, kDebugEngine, "setMapMonsterField8 %d 0x%X %s", id, movementType, groupFl ? "True" : "False"); +void EfhEngine::setMapMonsterMovementType(int16 id, uint8 movementType, bool groupFl) { + debugC(2, kDebugEngine, "setMapMonsterMovementType %d 0x%X %s", id, movementType, groupFl ? "True" : "False"); int16 monsterId; if (groupFl) { // groupFl is always True @@ -2574,8 +2574,8 @@ bool EfhEngine::checkMonsterCollision() { if (!checkMapMonsterAvailability(monsterId)) continue; - if (!(_largeMapFlag && _mapMonsters[monsterId]._guess_fullPlaceId == 0xFE) - && !(!_largeMapFlag && _mapMonsters[monsterId]._guess_fullPlaceId == _fullPlaceId)) + if (!(_largeMapFlag && _mapMonsters[monsterId]._fullPlaceId == 0xFE) + && !(!_largeMapFlag && _mapMonsters[monsterId]._fullPlaceId == _fullPlaceId)) continue; if ((_mapMonsters[monsterId]._possessivePronounSHL6 & 0x3F) > 0x3D diff --git a/engines/efh/efh.h b/engines/efh/efh.h index b8bf9a66ebed..a3030fe23587 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -208,11 +208,11 @@ struct CharStatus { struct MapMonster { uint8 _possessivePronounSHL6; // aabb bbbb aa:Possessive Pronoun, bb bbbb: unknown uint8 _npcId; - uint8 _guess_fullPlaceId; // unsigned? Magic values are 0xFF and 0xFE + uint8 _fullPlaceId; // unsigned? Magic values are 0xFF and 0xFE uint8 _posX; uint8 _posY; - uint8 _itemId_Weapon; - uint8 _field_6; + uint8 _weaponItemId; + uint8 _maxDamageAbsorption; uint8 _monsterRef; uint8 _moveInfo; // abbb cccc a: special move flag, bbb: Pct modifier for random move, cccc movement type uint8 _field9_textId; @@ -368,7 +368,7 @@ class EfhEngine : public Engine { int16 getXPLevel(int32 xp); bool isItemCursed(int16 itemId); bool hasObjectEquipped(int16 charId, int16 objectId); - void setMapMonsterField8(int16 id, uint8 movementType, bool groupFl); + void setMapMonsterMovementType(int16 id, uint8 movementType, bool groupFl); bool isMonsterActive(int16 groupId, int16 id); int16 getTileFactId(int16 mapPosX, int16 mapPosY); void setCharacterObjectToBroken(int16 charId, int16 objectId); diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index 88cc1edca0fc..14dbd0eff20d 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -37,7 +37,7 @@ void EfhEngine::createOpponentList(int16 monsterTeamId) { break; for (uint monsterId = 0; monsterId < 64; ++monsterId) { - if (_mapMonsters[monsterId]._guess_fullPlaceId == 0xFF) + if (_mapMonsters[monsterId]._fullPlaceId == 0xFF) continue; if (((_mapMonsters[monsterId]._possessivePronounSHL6 & 0x3F) != 0x3F || isNpcATeamMember(_mapMonsters[monsterId]._npcId)) && (_mapMonsters[monsterId]._possessivePronounSHL6 & 0x3F) > 0x3D) @@ -161,15 +161,15 @@ bool EfhEngine::handleFight(int16 monsterId) { // handleFight - Loop on var86 - Start for (uint var86 = 0; var86 < 9; ++var86) { if (isMonsterActive(monsterGroupIdOrMonsterId, var86)) { - int16 unk_monsterField5_itemId = _mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._itemId_Weapon; - if (unk_monsterField5_itemId == 0xFF) - unk_monsterField5_itemId = 0x3F; + int16 monsterWeaponItemId = _mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._weaponItemId; + if (monsterWeaponItemId == 0xFF) + monsterWeaponItemId = 0x3F; int16 teamMemberId = -1; int16 var54; - if (_items[unk_monsterField5_itemId]._range < 3) { + if (_items[monsterWeaponItemId]._range < 3) { for (uint var84 = 0; var84 < 10; ++var84) { teamMemberId = getRandom(_teamSize) - 1; - if (checkWeaponRange(_teamMonsterIdArray[monsterGroupIdOrMonsterId], unk_monsterField5_itemId) && isTeamMemberStatusNormal(teamMemberId) && getRandom(100) < _teamPctVisible[teamMemberId]) { + if (checkWeaponRange(_teamMonsterIdArray[monsterGroupIdOrMonsterId], monsterWeaponItemId) && isTeamMemberStatusNormal(teamMemberId) && getRandom(100) < _teamPctVisible[teamMemberId]) { break; } teamMemberId = -1; @@ -189,13 +189,13 @@ bool EfhEngine::handleFight(int16 monsterId) { varInt = _teamMonsterIdArray[monsterGroupIdOrMonsterId]; int16 ennemyPronoun = kEncounters[_mapMonsters[varInt]._monsterRef]._nameArticle; int16 characterPronoun = _npcBuf[_teamCharId[var7E]].getPronoun(); - varInt = _items[unk_monsterField5_itemId].field_13; + varInt = _items[monsterWeaponItemId].field_13; _word32482[var7E] += (varInt * 5); int16 var62 = 0; int16 hitPoints = 0; int16 originalDamage = 0; int16 damagePointsAbsorbed = 0; - int16 var64 = _mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._npcId * _items[unk_monsterField5_itemId]._attacks; + int16 var64 = _mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._npcId * _items[monsterWeaponItemId]._attacks; for (int var84 = 0; var84 < var64; ++var84) { // handleFight - Loop var84 on var64 (objectId) - Start if (getRandom(100) > _word32482[var7E]) @@ -203,10 +203,10 @@ bool EfhEngine::handleFight(int16 monsterId) { ++var62; - if (hasAdequateDefense_2(_teamCharId[var7E], _items[unk_monsterField5_itemId]._attackType)) + if (hasAdequateDefense_2(_teamCharId[var7E], _items[monsterWeaponItemId]._attackType)) continue; - int16 var7C = getRandom(_items[unk_monsterField5_itemId]._damage); + int16 var7C = getRandom(_items[monsterWeaponItemId]._damage); varInt = var7C - var76; if (varInt > 0) { @@ -222,7 +222,7 @@ bool EfhEngine::handleFight(int16 monsterId) { originalDamage = 0; hitPoints = originalDamage + damagePointsAbsorbed; - if (!checkSpecialItemsOnCurrentPlace(unk_monsterField5_itemId)) + if (!checkSpecialItemsOnCurrentPlace(monsterWeaponItemId)) var62 = 0; if (var62 > 0) { @@ -233,7 +233,7 @@ bool EfhEngine::handleFight(int16 monsterId) { _attackBuffer = ""; } - int16 var68 = _items[unk_monsterField5_itemId]._attackType + 1; + int16 var68 = _items[monsterWeaponItemId]._attackType + 1; int16 var6A = getRandom(3); if (characterPronoun == 2) _characterNamePt1 = "The "; @@ -247,8 +247,8 @@ bool EfhEngine::handleFight(int16 monsterId) { _enemyNamePt2 = kEncounters[_mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._monsterRef]._name; _characterNamePt2 = _npcBuf[_teamCharId[var7E]]._name; - _nameBuffer = _items[unk_monsterField5_itemId]._name; - if (checkSpecialItemsOnCurrentPlace(unk_monsterField5_itemId)) { + _nameBuffer = _items[monsterWeaponItemId]._name; + if (checkSpecialItemsOnCurrentPlace(monsterWeaponItemId)) { // handleFight - check damages - Start if (var62 == 0) { _messageToBePrinted = Common::String::format("%s%s %s at %s%s with %s %s, but misses!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1.c_str(), _characterNamePt2.c_str(), kPossessive[ennemyPronoun], _nameBuffer.c_str()); @@ -303,7 +303,7 @@ bool EfhEngine::handleFight(int16 monsterId) { // handleFight - Check armor - end // handleFight - Check effect - start - switch (_items[unk_monsterField5_itemId]._specialEffect) { + switch (_items[monsterWeaponItemId]._specialEffect) { case 1: if (getRandom(100) < 20) { _teamCharStatus[var7E]._status = 1; @@ -332,7 +332,7 @@ bool EfhEngine::handleFight(int16 monsterId) { } else { _messageToBePrinted = Common::String::format("%s%s tries to use %s %s, but it doesn't work!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPossessive[ennemyPronoun], _nameBuffer.c_str()); } - genericGenerateSound(_items[unk_monsterField5_itemId]._attackType, var62); + genericGenerateSound(_items[monsterWeaponItemId]._attackType, var62); displayBoxWithText(_messageToBePrinted, 1, 2, true); } // handleFight - Loop on var7E - End @@ -452,35 +452,34 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { if (_teamMonsterIdArray[groupId] == -1) continue; - for (int16 var7E = teamMemberId; var7E < var54; ++var7E) { - if (isMonsterActive(groupId, var7E) && var6E) { - int16 var5C; + for (int16 mobsterCounter = teamMemberId; mobsterCounter < var54; ++mobsterCounter) { + if (isMonsterActive(groupId, mobsterCounter) && var6E) { + bool noticedFl; if (checkMonsterMovementType(groupId, true)) { - setMapMonsterField8(groupId, 9, true); + setMapMonsterMovementType(groupId, 9, true); _unk2C8AA += 500; - var5C = -1; + noticedFl = true; } else - var5C = 0; + noticedFl = false; - int16 var76 = getRandom(_mapMonsters[_teamMonsterIdArray[groupId]]._field_6); - int16 varInt = _teamCharId[teamCharId]; - int16 var70 = _npcBuf[varInt].getPronoun(); - varInt = _teamMonsterIdArray[groupId]; - int16 var5E = kEncounters[_mapMonsters[varInt]._monsterRef]._nameArticle; + int16 var76 = getRandom(_mapMonsters[_teamMonsterIdArray[groupId]]._maxDamageAbsorption); + int16 ennemyPronoun = _npcBuf[_teamCharId[teamCharId]].getPronoun(); + int16 monsterId = _teamMonsterIdArray[groupId]; + int16 characterPronoun = kEncounters[_mapMonsters[monsterId]._monsterRef]._nameArticle; int16 charScore = getCharacterScore(_teamCharId[teamCharId], teamCharItemId); - int16 hitPointsBefore = _mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[var7E]; - int16 var62 = 0; + int16 hitPointsBefore = _mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[mobsterCounter]; + int16 hitCount = 0; int16 originalDamage = 0; int16 damagePointsAbsorbed = 0; - int16 var64 = _items[teamCharItemId]._attacks * _npcBuf[_teamCharId[teamCharId]]._speed; + int16 attackSpeed = _items[teamCharItemId]._attacks * _npcBuf[_teamCharId[teamCharId]]._speed; // Action A - Loop var84 - Start - for (int var84 = 0; var84 < var64; ++var84) { + for (int var84 = 0; var84 < attackSpeed; ++var84) { if (getRandom(100) < charScore) { - ++var62; + ++hitCount; if (!hasAdequateDefense(_teamMonsterIdArray[groupId], _items[teamCharItemId]._attackType)) { int16 var7C = getRandom(_items[teamCharItemId]._damage); - varInt = var7C - var76; + int16 varInt = var7C - var76; if (varInt > 0) { originalDamage += varInt; damagePointsAbsorbed += var76; @@ -498,25 +497,24 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { int16 hitPoints = originalDamage + damagePointsAbsorbed; if (!checkSpecialItemsOnCurrentPlace(teamCharItemId)) - var62 = 0; + hitCount = 0; - if (var62 > 0) { - _mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[var7E] -= originalDamage; - if (var62 > 1) { - _attackBuffer = Common::String::format("%d times ", var62); + if (hitCount > 0) { + _mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[mobsterCounter] -= originalDamage; + if (hitCount > 1) { + _attackBuffer = Common::String::format("%d times ", hitCount); } else { _attackBuffer = ""; } } - int16 var68 = _items[teamCharItemId]._attackType + 1; - int16 var6A = getRandom(3) - 1; - if (var5E == 2) { + int16 verbId = (3 * _items[teamCharItemId]._attackType + 1) + getRandom(3) - 1; + if (characterPronoun == 2) { _characterNamePt1 = "The "; } else { _characterNamePt1 = ""; } - if (var70 == 2) { + if (ennemyPronoun == 2) { _enemyNamePt1 = "The "; } else { _enemyNamePt1 = ""; @@ -527,21 +525,21 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { _nameBuffer = _items[teamCharItemId]._name; if (checkSpecialItemsOnCurrentPlace(teamCharItemId)) { // Action A - Check damages - Start - if (var62 == 0) { - _messageToBePrinted = Common::String::format("%s%s %s at %s%s with %s %s, but misses!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1.c_str(), _characterNamePt2.c_str(), kPossessive[var70], _nameBuffer.c_str()); + if (hitCount == 0) { + _messageToBePrinted = Common::String::format("%s%s %s at %s%s with %s %s, but misses!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[verbId], _characterNamePt1.c_str(), _characterNamePt2.c_str(), kPossessive[ennemyPronoun], _nameBuffer.c_str()); } else if (hitPoints <= 0) { - _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s, but does no damage!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[var70], _nameBuffer.c_str()); + _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s, but does no damage!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[verbId], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[ennemyPronoun], _nameBuffer.c_str()); } else if (hitPoints == 1) { - _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s for 1 point", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[var70], _nameBuffer.c_str()); - if (_mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[var7E] <= 0) { + _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s for 1 point", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[verbId], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[ennemyPronoun], _nameBuffer.c_str()); + if (_mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[mobsterCounter] <= 0) { getDeathTypeDescription(groupId, teamCharId + 1000); getXPAndSearchCorpse(_teamCharId[teamCharId], _enemyNamePt1, _enemyNamePt2, _teamMonsterIdArray[groupId]); } else { _messageToBePrinted += "!"; } } else { - _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s for %d points", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[(var68 * 3) + var6A], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[var70], _nameBuffer.c_str(), hitPoints); - if (_mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[var7E] <= 0) { + _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s for %d points", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[verbId], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[ennemyPronoun], _nameBuffer.c_str(), hitPoints); + if (_mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[mobsterCounter] <= 0) { getDeathTypeDescription(groupId, teamCharId + 1000); getXPAndSearchCorpse(_teamCharId[teamCharId], _enemyNamePt1, _enemyNamePt2, _teamMonsterIdArray[groupId]); } else { @@ -551,16 +549,16 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { // Action A - Check damages - End // Action A - Add reaction text - Start - if (var62 != 0 && originalDamage > 0 && getRandom(100) <= 35 && _mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[var7E] > 0) { - if (_mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[var7E] - 5 <= originalDamage) { + if (hitCount != 0 && originalDamage > 0 && getRandom(100) <= 35 && _mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[mobsterCounter] > 0) { + if (_mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[mobsterCounter] - 5 <= originalDamage) { addReactionText(0); - } else if (_mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[var7E] < hitPointsBefore / 8) { + } else if (_mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[mobsterCounter] < hitPointsBefore / 8) { addReactionText(1); - } else if (_mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[var7E] < hitPointsBefore / 4) { + } else if (_mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[mobsterCounter] < hitPointsBefore / 4) { addReactionText(2); - } else if (_mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[var7E] < hitPointsBefore / 2) { + } else if (_mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[mobsterCounter] < hitPointsBefore / 2) { addReactionText(3); - } else if (_mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[var7E] < hitPointsBefore / 3) { + } else if (_mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[mobsterCounter] < hitPointsBefore / 3) { // CHECKME: Doesn't make any sense to check /3 after /2... I don't get it addReactionText(4); } else if (hitPointsBefore / 8 >= originalDamage) { @@ -572,7 +570,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { // Action A - Add reaction text - End // Action A - Add armor absorb text - Start - if (var76 && var62 && _mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[var7E] > 0) { + if (var76 && hitCount && _mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[mobsterCounter] > 0) { if (damagePointsAbsorbed <= 1) _messageToBePrinted += Common::String::format(" %s%s's armor absorbs 1 point!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); else @@ -580,45 +578,45 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { } // Action A - Add armor absorb text - End - if (var5C) + if (noticedFl) _messageToBePrinted += Common::String(" Your actions do not go un-noticed..."); // Action A - Check item durability - Start - varInt = _teamCharId[teamCharId]; + int16 npcId = _teamCharId[teamCharId]; // get equipped inventory slot with exclusiveType == 9 - var64 = getEquippedExclusiveType(varInt, 9, false); - if (var64 != 0x7FFF && _npcBuf[varInt]._inventory[var64].getUsesLeft() != 0x7F) { - int16 usesLeft = _npcBuf[varInt]._inventory[var64].getUsesLeft(); + uint16 exclusiveInventoryId = getEquippedExclusiveType(npcId, 9, false); + if (exclusiveInventoryId != 0x7FFF && _npcBuf[npcId]._inventory[exclusiveInventoryId].getUsesLeft() != 0x7F) { + int16 usesLeft = _npcBuf[npcId]._inventory[exclusiveInventoryId].getUsesLeft(); --usesLeft; if (usesLeft <= 0) { _messageToBePrinted += Common::String::format(" * %s%s's %s breaks!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), _nameBuffer.c_str()); - setCharacterObjectToBroken(varInt, var64); + setCharacterObjectToBroken(npcId, exclusiveInventoryId); var6E = false; } else { - _npcBuf[varInt]._inventory[var64]._stat1 = (_npcBuf[varInt]._inventory[var64]._stat1 & 80) + usesLeft; + _npcBuf[npcId]._inventory[exclusiveInventoryId]._stat1 = (_npcBuf[npcId]._inventory[exclusiveInventoryId]._stat1 & 80) + usesLeft; } } // Action A - Check item durability - End // Action A - Check effect - Start - if (_items[teamCharItemId]._specialEffect == 1 && _mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[var7E] > 0) { + if (_items[teamCharItemId]._specialEffect == 1 && _mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[mobsterCounter] > 0) { if (getRandom(100) < 35) { - _teamMonsterEffects[groupId]._effect[var7E] = 1; - _teamMonsterEffects[groupId]._duration[var7E] = getRandom(10); + _teamMonsterEffects[groupId]._effect[mobsterCounter] = 1; + _teamMonsterEffects[groupId]._duration[mobsterCounter] = getRandom(10); _messageToBePrinted += Common::String::format(" %s%s falls asleep!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); } - } else if (_items[teamCharItemId]._specialEffect == 2 && _mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[var7E] > 0) { - _teamMonsterEffects[groupId]._effect[var7E] = 2; - _teamMonsterEffects[groupId]._duration[var7E] = getRandom(10); + } else if (_items[teamCharItemId]._specialEffect == 2 && _mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[mobsterCounter] > 0) { + _teamMonsterEffects[groupId]._effect[mobsterCounter] = 2; + _teamMonsterEffects[groupId]._duration[mobsterCounter] = getRandom(10); _messageToBePrinted += Common::String::format(" %s%s is frozen!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); } // Action A - Check effect - End } else { - _messageToBePrinted = Common::String::format("%s%s tries to use %s %s, but it doesn't work!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPossessive[var70], _nameBuffer.c_str()); + _messageToBePrinted = Common::String::format("%s%s tries to use %s %s, but it doesn't work!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPossessive[ennemyPronoun], _nameBuffer.c_str()); } - genericGenerateSound(_items[teamCharItemId]._attackType, var62); + genericGenerateSound(_items[teamCharItemId]._attackType, hitCount); displayBoxWithText(_messageToBePrinted, 1, 2, true); } } @@ -767,7 +765,7 @@ void EfhEngine::getDeathTypeDescription(int16 attackerId, int16 victimId) { } else if (_teamMonsterIdArray[victimId] == -1) deathType = 0; else { - int16 itemId = _mapMonsters[_teamMonsterIdArray[victimId]]._itemId_Weapon; + int16 itemId = _mapMonsters[_teamMonsterIdArray[victimId]]._weaponItemId; deathType = _items[itemId]._attackType; } } @@ -1519,7 +1517,7 @@ bool EfhEngine::checkSpecialItemsOnCurrentPlace(int16 itemId) { bool EfhEngine::hasAdequateDefense(int16 monsterId, uint8 attackType) { debug("hasAdequateDefense %d %d", monsterId, attackType); - int16 itemId = _mapMonsters[monsterId]._itemId_Weapon; + int16 itemId = _mapMonsters[monsterId]._weaponItemId; if (_items[itemId]._specialEffect != 0) return false; diff --git a/engines/efh/menu.cpp b/engines/efh/menu.cpp index cc52561ca43e..323811b02546 100644 --- a/engines/efh/menu.cpp +++ b/engines/efh/menu.cpp @@ -1049,7 +1049,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in displayString_3("There is no apparent affect!", false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += " The magic sparkles brilliant hues in the air!"; - setMapMonsterField8(teamMonsterId, _items[itemId]._field17_attackTypeDefense, true); + setMapMonsterMovementType(teamMonsterId, _items[itemId]._field17_attackTypeDefense, true); } objectUsedFl = true; break; From 0d8ba6ba74e0dfba202ccfde9e7fc2a1fe4d594a Mon Sep 17 00:00:00 2001 From: Strangerke Date: Tue, 3 Jan 2023 23:26:08 +0100 Subject: [PATCH 216/412] EFH: Rename last field in MapMonster structure --- engines/efh/efh.cpp | 6 +++--- engines/efh/efh.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index bc8264880c95..27fcf188bcd0 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -508,7 +508,7 @@ void EfhEngine::loadMapArrays(int idx) { _mapMonsters[i]._maxDamageAbsorption = mapMonstersPtr[29 * i + 6]; _mapMonsters[i]._monsterRef = mapMonstersPtr[29 * i + 7]; _mapMonsters[i]._moveInfo = mapMonstersPtr[29 * i + 8]; - _mapMonsters[i]._field9_textId = mapMonstersPtr[29 * i + 9]; + _mapMonsters[i]._talkTextId = mapMonstersPtr[29 * i + 9]; _mapMonsters[i]._groupSize = mapMonstersPtr[29 * i + 10]; for (int j = 0; j < 9; ++j) _mapMonsters[i]._hitPoints[j] = READ_LE_INT16(&mapMonstersPtr[29 * i + 11 + j * 2]); @@ -1817,11 +1817,11 @@ bool EfhEngine::handleTalk(int16 monsterId, int16 arg2, int16 itemId) { return false; if ((_mapMonsters[monsterId]._possessivePronounSHL6 & 0x3F) != 0x3F) { - if (_mapMonsters[monsterId]._field9_textId == 0xFF || arg2 != 5) { + if (_mapMonsters[monsterId]._talkTextId == 0xFF || arg2 != 5) { return false; } displayMonsterAnim(monsterId); - displayImp1Text(_mapMonsters[monsterId]._field9_textId); + displayImp1Text(_mapMonsters[monsterId]._talkTextId); displayAnimFrames(0xFE, true); return true; } diff --git a/engines/efh/efh.h b/engines/efh/efh.h index a3030fe23587..77d4deb21ca3 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -215,7 +215,7 @@ struct MapMonster { uint8 _maxDamageAbsorption; uint8 _monsterRef; uint8 _moveInfo; // abbb cccc a: special move flag, bbb: Pct modifier for random move, cccc movement type - uint8 _field9_textId; + uint8 _talkTextId; uint8 _groupSize; int16 _hitPoints[9]; From c28ff1990e4eb8e108e4515c296c0818e117e9e2 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Wed, 4 Jan 2023 08:00:49 +0100 Subject: [PATCH 217/412] EFH: refactor findMapSpecialTileIndex, validate a couple of functions, more renaming --- engines/efh/efh.cpp | 83 ++++++++++++++++++++---------------------- engines/efh/efh.h | 6 +-- engines/efh/files.cpp | 2 +- engines/efh/init.cpp | 4 +- engines/efh/script.cpp | 33 +++++++++-------- 5 files changed, 64 insertions(+), 64 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 27fcf188bcd0..0d64f7b4e4c4 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -484,16 +484,16 @@ void EfhEngine::initMapMonsters() { void EfhEngine::loadMapArrays(int idx) { debugC(6, kDebugEngine, "loadMapArrays %d", idx); - uint8 *_mapUnknownPtr = &_mapArr[idx][2]; + uint8 *mapSpecialTilePtr = &_mapArr[idx][2]; for (int i = 0; i < 100; ++i) { - _mapUnknown[i]._placeId = _mapUnknownPtr[9 * i]; - _mapUnknown[i]._posX = _mapUnknownPtr[9 * i + 1]; - _mapUnknown[i]._posY = _mapUnknownPtr[9 * i + 2]; - _mapUnknown[i]._field3 = _mapUnknownPtr[9 * i + 3]; - _mapUnknown[i]._field4_NpcId = _mapUnknownPtr[9 * i + 4]; - _mapUnknown[i]._field5_textId = READ_LE_UINT16(&_mapUnknownPtr[9 * i + 5]); - _mapUnknown[i]._field7_textId = READ_LE_UINT16(&_mapUnknownPtr[9 * i + 7]); + _mapSpecialTile[i]._placeId = mapSpecialTilePtr[9 * i]; + _mapSpecialTile[i]._posX = mapSpecialTilePtr[9 * i + 1]; + _mapSpecialTile[i]._posY = mapSpecialTilePtr[9 * i + 2]; + _mapSpecialTile[i]._field3 = mapSpecialTilePtr[9 * i + 3]; + _mapSpecialTile[i]._field4_NpcId = mapSpecialTilePtr[9 * i + 4]; + _mapSpecialTile[i]._field5_textId = READ_LE_UINT16(&mapSpecialTilePtr[9 * i + 5]); + _mapSpecialTile[i]._field7_textId = READ_LE_UINT16(&mapSpecialTilePtr[9 * i + 7]); } uint8 *mapMonstersPtr = &_mapArr[idx][902]; @@ -1102,20 +1102,16 @@ void EfhEngine::sub2455E(int16 arg0, int16 arg2, int16 arg4) { } } -int16 EfhEngine::sub151FD(int16 posX, int16 posY) { - debug("sub151FD %d %d", posX, posY); +int16 EfhEngine::findMapSpecialTileIndex(int16 posX, int16 posY) { + debugC(5, kDebugEngine, "findMapSpecialTileIndex %d %d", posX, posY); - if (_largeMapFlag) { - for (uint counter = 0; counter < 100; ++counter) { - if (_mapUnknown[counter]._posX == posX && _mapUnknown[counter]._posY == posY && _mapUnknown[counter]._placeId == 0xFE) - return counter; - } - } else { - for (uint counter = 0; counter < 100; ++counter) { - if (_mapUnknown[counter]._posX == posX && _mapUnknown[counter]._posY == posY && _mapUnknown[counter]._placeId == _fullPlaceId) - return counter; - } + uint16 searchPlaceId = _largeMapFlag ? 0xFE : _fullPlaceId; + + for (uint counter = 0; counter < 100; ++counter) { + if (_mapSpecialTile[counter]._posX == posX && _mapSpecialTile[counter]._posY == posY && _mapSpecialTile[counter]._placeId == searchPlaceId) + return counter; } + return -1; } @@ -2092,41 +2088,41 @@ void EfhEngine::displayImp1Text(int16 textId) { bool EfhEngine::sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemId, int16 arg8, int16 imageSetId) { debug("sub22293 %d-%d %d %d %d %d", mapPosX, mapPosY, charId, itemId, arg8, imageSetId); - int16 var8 = sub151FD(mapPosX, mapPosY); + int16 tileId = findMapSpecialTileIndex(mapPosX, mapPosY); - if (var8 == -1) { + if (tileId == -1) { if (imageSetId != -1 && *_imp2PtrArray[imageSetId] != 0x30) displayMiddleLeftTempText(_imp2PtrArray[imageSetId], true); } else if (arg8 == 0) { - if (_mapUnknown[var8]._field3 == 0xFF) { - displayImp1Text(_mapUnknown[var8]._field5_textId); // word! + if (_mapSpecialTile[tileId]._field3 == 0xFF) { + displayImp1Text(_mapSpecialTile[tileId]._field5_textId); // word! return true; } - if (_mapUnknown[var8]._field3 == 0xFE) { + if (_mapSpecialTile[tileId]._field3 == 0xFE) { for (int counter = 0; counter < _teamSize; ++counter) { if (_teamCharId[counter] == -1) continue; - if (_teamCharId[counter] == _mapUnknown[var8]._field4_NpcId) { - displayImp1Text(_mapUnknown[var8]._field5_textId); + if (_teamCharId[counter] == _mapSpecialTile[tileId]._field4_NpcId) { + displayImp1Text(_mapSpecialTile[tileId]._field5_textId); return true; } } - } else if (_mapUnknown[var8]._field3 == 0xFD) { + } else if (_mapSpecialTile[tileId]._field3 == 0xFD) { for (int counter = 0; counter < _teamSize; ++counter) { if (_teamCharId[counter] == -1) continue; for (uint var2 = 0; var2 < 10; ++var2) { - if (_npcBuf[_teamCharId[counter]]._inventory[var2]._ref == _mapUnknown[var8]._field4_NpcId) { - displayImp1Text(_mapUnknown[var8]._field5_textId); + if (_npcBuf[_teamCharId[counter]]._inventory[var2]._ref == _mapSpecialTile[tileId]._field4_NpcId) { + displayImp1Text(_mapSpecialTile[tileId]._field5_textId); return true; } } } // original makes a useless check on (_mapUnknownPtr[var8 * 9 + 3] > 0x7F) - } else if (_mapUnknown[var8]._field3 <= 0x77) { - int16 var6 = _mapUnknown[var8]._field3; + } else if (_mapSpecialTile[tileId]._field3 <= 0x77) { + int16 var6 = _mapSpecialTile[tileId]._field3; for (int counter = 0; counter < _teamSize; ++counter) { if (_teamCharId[counter] == -1) continue; @@ -2134,25 +2130,25 @@ bool EfhEngine::sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemI for (uint var2 = 0; var2 < 39; ++var2) { // CHECKME : the whole loop doesn't make much sense as it's using var6 instead of var2, plus _activeScore is an array of 15 bytes, not 0x77... // Also, 39 correspond to the size of activeScore + passiveScore + infoScore + the 2 remaining bytes of the struct - if (_npcBuf[_teamCharId[counter]]._activeScore[var6] >= _mapUnknown[var8]._field4_NpcId) { - displayImp1Text(_mapUnknown[var8]._field5_textId); + if (_npcBuf[_teamCharId[counter]]._activeScore[var6] >= _mapSpecialTile[tileId]._field4_NpcId) { + displayImp1Text(_mapSpecialTile[tileId]._field5_textId); return true; } } } } } else { - if ((_mapUnknown[var8]._field3 == 0xFA && arg8 == 1) || (_mapUnknown[var8]._field3 == 0xFC && arg8 == 2) || (_mapUnknown[var8]._field3 == 0xFB && arg8 == 3)) { - if (_mapUnknown[var8]._field4_NpcId == itemId) { - displayImp1Text(_mapUnknown[var8]._field5_textId); + if ((_mapSpecialTile[tileId]._field3 == 0xFA && arg8 == 1) || (_mapSpecialTile[tileId]._field3 == 0xFC && arg8 == 2) || (_mapSpecialTile[tileId]._field3 == 0xFB && arg8 == 3)) { + if (_mapSpecialTile[tileId]._field4_NpcId == itemId) { + displayImp1Text(_mapSpecialTile[tileId]._field5_textId); return true; } } else if (arg8 == 4) { - int16 var6 = _mapUnknown[var8]._field3; + int16 var6 = _mapSpecialTile[tileId]._field3; if (var6 >= 0x7B && var6 <= 0xEF) { var6 -= 0x78; - if (var6 >= 0 && var6 <= 0x8B && var6 == itemId && _mapUnknown[var8]._field4_NpcId <= _npcBuf[charId]._activeScore[itemId]) { - displayImp1Text(_mapUnknown[var8]._field5_textId); + if (var6 >= 0 && var6 <= 0x8B && var6 == itemId && _mapSpecialTile[tileId]._field4_NpcId <= _npcBuf[charId]._activeScore[itemId]) { + displayImp1Text(_mapSpecialTile[tileId]._field5_textId); return true; } } @@ -2164,10 +2160,11 @@ bool EfhEngine::sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemI return true; } - if ((arg8 == 4 && _mapUnknown[var8]._field3 < 0xFA) || arg8 != 4) { - if (_mapUnknown[var8]._field7_textId > 0xFE) + // CHECKME: there's suspiciously no check on tileId + if ((arg8 == 4 && _mapSpecialTile[tileId]._field3 < 0xFA) || arg8 != 4) { + if (_mapSpecialTile[tileId]._field7_textId > 0xFE) return false; - displayImp1Text(_mapUnknown[var8]._field7_textId); + displayImp1Text(_mapSpecialTile[tileId]._field7_textId); return true; } diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 77d4deb21ca3..695e629b3b29 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -89,7 +89,7 @@ struct InvObject { int8 getUsesLeft(); }; -struct UnkMapStruct { +struct MapSpecialTileStruct { uint8 _placeId; uint8 _posX; uint8 _posY; @@ -322,7 +322,7 @@ class EfhEngine : public Engine { void displayMiddleLeftTempText(uint8 *impArray, bool flag); void transitionMap(int16 centerX, int16 centerY); void sub2455E(int16 arg0, int16 arg1, int16 arg2); - int16 sub151FD(int16 posX, int16 posY); + int16 findMapSpecialTileIndex(int16 posX, int16 posY); bool isPosOutOfMap(int16 mapPosX, int16 mapPosY); void goSouth(); void goNorth(); @@ -537,7 +537,7 @@ class EfhEngine : public Engine { Common::String _messageToBePrinted; uint8 *_mapBitmapRefArr[19]; - UnkMapStruct _mapUnknown[100]; + MapSpecialTileStruct _mapSpecialTile[100]; MapMonster _mapMonsters[64]; uint8 _mapGameMap[64][64]; diff --git a/engines/efh/files.cpp b/engines/efh/files.cpp index aa5ed2e9f1ce..51d4a60b170a 100644 --- a/engines/efh/files.cpp +++ b/engines/efh/files.cpp @@ -196,7 +196,7 @@ void EfhEngine::loadHistory() { } void EfhEngine::loadTechMapImp(int16 fileId) { - debug("loadTechMapImp %d", fileId); + debugC(3, kDebugEngine, "loadTechMapImp %d", fileId); if (fileId == 0xFF) return; diff --git a/engines/efh/init.cpp b/engines/efh/init.cpp index e5a9af06e93f..2f10413fcf07 100644 --- a/engines/efh/init.cpp +++ b/engines/efh/init.cpp @@ -44,7 +44,7 @@ void InvObject::init() { _curHitPoints = 0; } -void UnkMapStruct::init() { +void MapSpecialTileStruct::init() { _placeId = _posX = _posY = _field3 = _field4_NpcId = 0; _field5_textId = _field7_textId = 0; } @@ -229,7 +229,7 @@ EfhEngine::EfhEngine(OSystem *syst, const ADGameDescription *gd) : Engine(syst), for (int i = 0; i < 100; ++i) { _imp1PtrArray[i] = nullptr; - _mapUnknown[i].init(); + _mapSpecialTile[i].init(); } for (int i = 0; i < 432; ++i) diff --git a/engines/efh/script.cpp b/engines/efh/script.cpp index 2f650d87ff97..7d6a74e46f4f 100644 --- a/engines/efh/script.cpp +++ b/engines/efh/script.cpp @@ -310,11 +310,11 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos _unk2C8AA = 0; break; case 0x12: - // Guess : disable special tile { } + // Disable special tile if (flag) { - int16 var110 = sub151FD(_mapPosX, _mapPosY); - if (var110 != -1) - _mapUnknown[var110]._posX = 0xFF; + int16 tileId = findMapSpecialTileIndex(_mapPosX, _mapPosY); + if (tileId != -1) + _mapSpecialTile[tileId]._posX = 0xFF; } break; case 0x13: @@ -398,9 +398,10 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos displayFctFullScreen(); } - int16 mapUnkId = sub151FD(_mapPosX, _mapPosY); - if (mapUnkId != -1) { - _mapUnknown[mapUnkId]._posX = 0xFF; + int16 tileId = findMapSpecialTileIndex(_mapPosX, _mapPosY); + if (tileId != -1) { + // Disable special tile + _mapSpecialTile[tileId]._posX = 0xFF; } _redrawNeededFl = true; } @@ -418,21 +419,23 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos case 0x1A: buffer = script_readNumberArray(buffer, 2, scriptNumberArray); if (flag) { - int16 mapUnkId = sub151FD(scriptNumberArray[0], scriptNumberArray[1]); - if (mapUnkId != -1) { - _mapUnknown[mapUnkId]._posX = 0xFF; + int16 tileId = findMapSpecialTileIndex(scriptNumberArray[0], scriptNumberArray[1]); + if (tileId != -1) { + // Disable tile + _mapSpecialTile[tileId]._posX = 0xFF; } } break; case 0x1B: buffer = script_readNumberArray(buffer, 3, scriptNumberArray); if (flag) { - int16 mapUnkId = sub151FD(scriptNumberArray[0], scriptNumberArray[1]); - if (mapUnkId != -1) { - _mapUnknown[mapUnkId]._posX = 0xFF; + int16 tileId = findMapSpecialTileIndex(scriptNumberArray[0], scriptNumberArray[1]); + if (tileId != -1) { + // Disable tile + _mapSpecialTile[tileId]._posX = 0xFF; } - _mapUnknown[scriptNumberArray[2]]._posX = scriptNumberArray[0]; - _mapUnknown[scriptNumberArray[2]]._posY = scriptNumberArray[1]; + _mapSpecialTile[scriptNumberArray[2]]._posX = scriptNumberArray[0]; + _mapSpecialTile[scriptNumberArray[2]]._posY = scriptNumberArray[1]; } break; case 0x1C: From 36ea4314d2274bfb4fcd600bf9f6c566c9614244 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Thu, 5 Jan 2023 09:05:30 +0100 Subject: [PATCH 218/412] EFH: WIP sound code --- engines/efh/constants.cpp | 19 +++++++++++++ engines/efh/constants.h | 3 ++ engines/efh/efh.cpp | 59 +++++++++++++++++++++++++++++++++++++-- engines/efh/efh.h | 2 ++ 4 files changed, 80 insertions(+), 3 deletions(-) diff --git a/engines/efh/constants.cpp b/engines/efh/constants.cpp index 6d1d01c6ee9d..dfcb5704fbf3 100644 --- a/engines/efh/constants.cpp +++ b/engines/efh/constants.cpp @@ -446,4 +446,23 @@ const char kAttackVerbs[51][20] = { "shoots", "shoots" }; + +const int16 kSoundFrequency[72] = { + 18356, 17292, 16344, 15297, 14551, + 13714, 12829, 12175, 11472, 10847, + 10198, 9700, 9108, 8584, 8116, // last 3 : C, C#, D + 7648, 7231, 6818, 6449, 6087, // D#, E, F, F#, G + 5736, 5423, 5120, 4830, 4554, // G#, A, A#, B, Middle C + 4307, 4058, 3836, 3615, 3418, // C#, D, D# + 3224, 3043, 2875, 2711, 2560, + 2415, 2281, 2153, 2032, 1918, + 1810, 1709, 1612, 1521, 1435, + 1355, 1280, 1207, 1139, 1075, + 1015, 958, 897, 854, 806, + 760, 718, 677, 639, 603, + 570, 538, 507, 479, 452, + 427, 403, 380, 359, 338, + 319, 301 +}; + } // End of namespace Efh diff --git a/engines/efh/constants.h b/engines/efh/constants.h index d90cab882f5f..c08ade3e6901 100644 --- a/engines/efh/constants.h +++ b/engines/efh/constants.h @@ -39,6 +39,8 @@ struct Encounter { uint8 _nameArticle; }; +#define kDefaultNoteDuration 616; + extern const uint8 kFontWidthArray[96]; extern const uint8 kFontExtraLinesArray[96]; extern const Font kFontData[96]; @@ -48,6 +50,7 @@ extern const uint8 kByte2C7D0[60]; extern const char kPossessive[3][4]; extern const char kPersonal[3][4]; extern const char kAttackVerbs[51][20]; +extern const int16 kSoundFrequency[72]; } // End of namespace Efh diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 0d64f7b4e4c4..a6f36f5dbeb3 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -273,12 +273,65 @@ void EfhEngine::initialize() { _shouldQuit = false; } +void EfhEngine::songDelay(int delay) { + debug("songDelay %d", delay); + + int remainingDelay = delay * kDefaultNoteDuration; + Common::KeyCode input = Common::KEYCODE_INVALID; + Common::Event event; + while (input == Common::KEYCODE_INVALID && remainingDelay > 0 && !shouldQuit()) { + _system->delayMillis(20); + remainingDelay -= 20; + + _system->getEventManager()->pollEvent(event); + if (event.type == Common::EVENT_KEYUP) { + input = event.kbd.keycode; + } + } +} + +void EfhEngine::playNote(int frequencyIndex, int totalDelay) { + debug("playNote %d %d", frequencyIndex, totalDelay); +} + Common::KeyCode EfhEngine::playSong(uint8 *buffer) { - warning("STUB: playSong"); + debug("playSong"); + + Common::KeyCode inputChar = Common::KEYCODE_INVALID; + int32 totalDelay = 0; + + uint8 varC = *buffer++; + int8 stopFl = *buffer & 0x3F; + while (stopFl != 0) { + int32 delay = stopFl * varC * 0x2200 / 1000; + if (*buffer > 0x7F) + delay /= 2; + if (*buffer & 0x40) + delay = (delay * 2) / 3; + int8 frequencyIndex = *++buffer & 0xF; + ++buffer; + + if (frequencyIndex > 0x7F) + totalDelay += delay; + else if (frequencyIndex == 0) + songDelay(delay); + else { + playNote(frequencyIndex, totalDelay + delay); + totalDelay = 0; + } - _system->delayMillis(1000); + songDelay(10); + Common::Event event; + _system->getEventManager()->pollEvent(event); + if (event.type == Common::EVENT_KEYUP) { + inputChar = event.kbd.keycode; + } - return Common::KEYCODE_INVALID; + if (inputChar != Common::KEYCODE_INVALID) + stopFl = 0; + } + + return inputChar; } void EfhEngine::playIntro() { diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 695e629b3b29..332b6c68d3aa 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -285,6 +285,8 @@ class EfhEngine : public Engine { bool _saveAuthorized; void initialize(); + void songDelay(int delay); + void playNote(int frequencyIndex, int totalDelay); Common::KeyCode playSong(uint8 *buffer); void playIntro(); void initEngine(); From d5eb4d85a41117d5b08a840c57c8ca8ce1000e3a Mon Sep 17 00:00:00 2001 From: Strangerke Date: Fri, 6 Jan 2023 02:10:01 +0100 Subject: [PATCH 219/412] EFH: fix a bug in sub22293(), validate 2 functions, some renaming --- engines/efh/efh.cpp | 49 +++++++++++++++++++++++--------------------- engines/efh/efh.h | 2 +- engines/efh/init.cpp | 2 +- 3 files changed, 28 insertions(+), 25 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index a6f36f5dbeb3..e46e1daa0bfc 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -274,7 +274,7 @@ void EfhEngine::initialize() { } void EfhEngine::songDelay(int delay) { - debug("songDelay %d", delay); + debug("songDelay %ld", delay); int remainingDelay = delay * kDefaultNoteDuration; Common::KeyCode input = Common::KEYCODE_INVALID; @@ -291,12 +291,14 @@ void EfhEngine::songDelay(int delay) { } void EfhEngine::playNote(int frequencyIndex, int totalDelay) { - debug("playNote %d %d", frequencyIndex, totalDelay); + debug("playNote %d %ld", frequencyIndex, totalDelay); } Common::KeyCode EfhEngine::playSong(uint8 *buffer) { debug("playSong"); + return Common::KEYCODE_INVALID; + Common::KeyCode inputChar = Common::KEYCODE_INVALID; int32 totalDelay = 0; @@ -544,7 +546,7 @@ void EfhEngine::loadMapArrays(int idx) { _mapSpecialTile[i]._posX = mapSpecialTilePtr[9 * i + 1]; _mapSpecialTile[i]._posY = mapSpecialTilePtr[9 * i + 2]; _mapSpecialTile[i]._field3 = mapSpecialTilePtr[9 * i + 3]; - _mapSpecialTile[i]._field4_NpcId = mapSpecialTilePtr[9 * i + 4]; + _mapSpecialTile[i]._triggerId = mapSpecialTilePtr[9 * i + 4]; _mapSpecialTile[i]._field5_textId = READ_LE_UINT16(&mapSpecialTilePtr[9 * i + 5]); _mapSpecialTile[i]._field7_textId = READ_LE_UINT16(&mapSpecialTilePtr[9 * i + 7]); } @@ -1851,7 +1853,7 @@ bool EfhEngine::checkMonsterGroupDistance1OrLess(int16 monsterId) { } bool EfhEngine::handleTalk(int16 monsterId, int16 arg2, int16 itemId) { - debug("handleTalk %d %d %d", monsterId, arg2, itemId); + debugC(6, kDebugEngine, "handleTalk %d %d %d", monsterId, arg2, itemId); if (_mapMonsters[monsterId]._fullPlaceId == 0xFF) return false; @@ -2139,7 +2141,7 @@ void EfhEngine::displayImp1Text(int16 textId) { } bool EfhEngine::sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemId, int16 arg8, int16 imageSetId) { - debug("sub22293 %d-%d %d %d %d %d", mapPosX, mapPosY, charId, itemId, arg8, imageSetId); + debugC(3, kDebugEngine, "sub22293 %d-%d %d %d %d %d", mapPosX, mapPosY, charId, itemId, arg8, imageSetId); int16 tileId = findMapSpecialTileIndex(mapPosX, mapPosY); @@ -2148,7 +2150,7 @@ bool EfhEngine::sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemI displayMiddleLeftTempText(_imp2PtrArray[imageSetId], true); } else if (arg8 == 0) { if (_mapSpecialTile[tileId]._field3 == 0xFF) { - displayImp1Text(_mapSpecialTile[tileId]._field5_textId); // word! + displayImp1Text(_mapSpecialTile[tileId]._field5_textId); return true; } @@ -2156,7 +2158,7 @@ bool EfhEngine::sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemI for (int counter = 0; counter < _teamSize; ++counter) { if (_teamCharId[counter] == -1) continue; - if (_teamCharId[counter] == _mapSpecialTile[tileId]._field4_NpcId) { + if (_teamCharId[counter] == _mapSpecialTile[tileId]._triggerId) { displayImp1Text(_mapSpecialTile[tileId]._field5_textId); return true; } @@ -2167,13 +2169,13 @@ bool EfhEngine::sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemI continue; for (uint var2 = 0; var2 < 10; ++var2) { - if (_npcBuf[_teamCharId[counter]]._inventory[var2]._ref == _mapSpecialTile[tileId]._field4_NpcId) { + if (_npcBuf[_teamCharId[counter]]._inventory[var2]._ref == _mapSpecialTile[tileId]._triggerId) { displayImp1Text(_mapSpecialTile[tileId]._field5_textId); return true; } } } - // original makes a useless check on (_mapUnknownPtr[var8 * 9 + 3] > 0x7F) + // original makes a useless check on (_mapSpecialTile[tileId]._field3 > 0x7F) } else if (_mapSpecialTile[tileId]._field3 <= 0x77) { int16 var6 = _mapSpecialTile[tileId]._field3; for (int counter = 0; counter < _teamSize; ++counter) { @@ -2183,33 +2185,34 @@ bool EfhEngine::sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemI for (uint var2 = 0; var2 < 39; ++var2) { // CHECKME : the whole loop doesn't make much sense as it's using var6 instead of var2, plus _activeScore is an array of 15 bytes, not 0x77... // Also, 39 correspond to the size of activeScore + passiveScore + infoScore + the 2 remaining bytes of the struct - if (_npcBuf[_teamCharId[counter]]._activeScore[var6] >= _mapSpecialTile[tileId]._field4_NpcId) { + warning("sub22293 - _activeScore[%d]", var6); + if (_npcBuf[_teamCharId[counter]]._activeScore[var6] >= _mapSpecialTile[tileId]._triggerId) { displayImp1Text(_mapSpecialTile[tileId]._field5_textId); return true; } } } } - } else { - if ((_mapSpecialTile[tileId]._field3 == 0xFA && arg8 == 1) || (_mapSpecialTile[tileId]._field3 == 0xFC && arg8 == 2) || (_mapSpecialTile[tileId]._field3 == 0xFB && arg8 == 3)) { - if (_mapSpecialTile[tileId]._field4_NpcId == itemId) { + } else if ((_mapSpecialTile[tileId]._field3 == 0xFA && arg8 == 1) || (_mapSpecialTile[tileId]._field3 == 0xFC && arg8 == 2) || (_mapSpecialTile[tileId]._field3 == 0xFB && arg8 == 3)) { + if (_mapSpecialTile[tileId]._triggerId == itemId) { + displayImp1Text(_mapSpecialTile[tileId]._field5_textId); + return true; + } + } else if (arg8 == 4) { + int16 var6 = _mapSpecialTile[tileId]._field3; + if (var6 >= 0x78 && var6 <= 0xEF) { + var6 -= 0x78; + warning("sub22293 - _activeScore[%d]", var6); + // The 2 checks on var6 are useless, as [0x78..0xEF] - 0x78 => [0x00..0x77] + if (var6 >= 0 && var6 <= 0x8B && var6 == itemId && _mapSpecialTile[tileId]._triggerId <= _npcBuf[charId]._activeScore[itemId]) { displayImp1Text(_mapSpecialTile[tileId]._field5_textId); return true; } - } else if (arg8 == 4) { - int16 var6 = _mapSpecialTile[tileId]._field3; - if (var6 >= 0x7B && var6 <= 0xEF) { - var6 -= 0x78; - if (var6 >= 0 && var6 <= 0x8B && var6 == itemId && _mapSpecialTile[tileId]._field4_NpcId <= _npcBuf[charId]._activeScore[itemId]) { - displayImp1Text(_mapSpecialTile[tileId]._field5_textId); - return true; - } - } } } for (uint counter = 0; counter < 64; ++counter) { - if (!handleTalk(counter, arg8, itemId)) + if (handleTalk(counter, arg8, itemId)) return true; } diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 332b6c68d3aa..20515d7acbb9 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -94,7 +94,7 @@ struct MapSpecialTileStruct { uint8 _posX; uint8 _posY; uint8 _field3; - uint8 _field4_NpcId; + uint8 _triggerId; uint16 _field5_textId; uint16 _field7_textId; diff --git a/engines/efh/init.cpp b/engines/efh/init.cpp index 2f10413fcf07..db1a4b2f7465 100644 --- a/engines/efh/init.cpp +++ b/engines/efh/init.cpp @@ -45,7 +45,7 @@ void InvObject::init() { } void MapSpecialTileStruct::init() { - _placeId = _posX = _posY = _field3 = _field4_NpcId = 0; + _placeId = _posX = _posY = _field3 = _triggerId = 0; _field5_textId = _field7_textId = 0; } From 8f3ad37290942247a5bd54ceb6751d7c983ca34c Mon Sep 17 00:00:00 2001 From: Strangerke Date: Fri, 6 Jan 2023 09:13:44 +0100 Subject: [PATCH 220/412] EFH: Fix a bug in handleFight_lastAction_A, validate multiple functions, renaming --- engines/efh/efh.cpp | 2 +- engines/efh/efh.h | 4 ++-- engines/efh/fight.cpp | 33 ++++++++++++++++----------------- engines/efh/files.cpp | 4 ++-- 4 files changed, 21 insertions(+), 22 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index e46e1daa0bfc..ca1d9f81cd95 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -1822,7 +1822,7 @@ bool EfhEngine::checkMapMonsterAvailability(int16 monsterId) { } void EfhEngine::displayMonsterAnim(int16 monsterId) { - debug("displayMonsterAnim %d", monsterId); + debugC(6, kDebugEngine, "displayMonsterAnim %d", monsterId); int16 animId = kEncounters[_mapMonsters[monsterId]._monsterRef]._animId; displayAnimFrames(animId, true); diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 20515d7acbb9..e8f5f265bd2f 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -388,13 +388,13 @@ class EfhEngine : public Engine { bool isMonsterAlreadyFighting(int16 monsterId, int16 teamMonsterId); void createOpponentList(int16 monsterTeamId); void resetTeamMonsterEffects(); - void sub1BE89(int16 monsterId); + void initFight(int16 monsterId); void resetTeamMonsterIdArray(); bool isTeamMemberStatusNormal(int16 id); void getDeathTypeDescription(int16 attackerId, int16 victimId); int16 sub1C956(int16 charId, int16 unkFied18Val, bool arg4); bool sub1CB27(); - void drawCombatScreen(int16 charId, bool whiteFl, bool forceDrawFl); + void drawCombatScreen(int16 charId, bool whiteFl, bool drawFl); void getXPAndSearchCorpse(int16 charId, Common::String namePt1, Common::String namePt2, int16 monsterId); bool characterSearchesMonsterCorpse(int16 charId, int16 monsterId); void addReactionText(int16 id); diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index 14dbd0eff20d..32b862109cd2 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -71,8 +71,8 @@ void EfhEngine::createOpponentList(int16 monsterTeamId) { _teamMonsterIdArray[id] = -1; } -void EfhEngine::sub1BE89(int16 monsterId) { - debug("sub1BE89 %d", monsterId); +void EfhEngine::initFight(int16 monsterId) { + debugC(3, kDebugEngine, "initFight %d", monsterId); createOpponentList(monsterId); resetTeamMonsterEffects(); } @@ -82,7 +82,7 @@ bool EfhEngine::handleFight(int16 monsterId) { _ongoingFightFl = true; - sub1BE89(monsterId); + initFight(monsterId); if (_teamMonsterIdArray[0] == -1) { resetTeamMonsterIdArray(); @@ -455,7 +455,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { for (int16 mobsterCounter = teamMemberId; mobsterCounter < var54; ++mobsterCounter) { if (isMonsterActive(groupId, mobsterCounter) && var6E) { bool noticedFl; - if (checkMonsterMovementType(groupId, true)) { + if (!checkMonsterMovementType(groupId, true)) { setMapMonsterMovementType(groupId, 9, true); _unk2C8AA += 500; noticedFl = true; @@ -695,7 +695,7 @@ bool EfhEngine::isTPK() { } bool EfhEngine::isMonsterAlreadyFighting(int16 monsterId, int16 teamMonsterId) { - debug("isMonsterAlreadyFighting %d %d", monsterId, teamMonsterId); + debugC(6, kDebugEngine, "isMonsterAlreadyFighting %d %d", monsterId, teamMonsterId); for (int counter = 0; counter < teamMonsterId; ++counter) { if (_teamMonsterIdArray[counter] == monsterId) @@ -1142,11 +1142,11 @@ bool EfhEngine::sub1CB27() { return var4; } -void EfhEngine::drawCombatScreen(int16 charId, bool whiteFl, bool forceDrawFl) { - debug("drawCombatScreen %d %s %s", charId, whiteFl ? "True" : "False", forceDrawFl ? "True" : "False"); +void EfhEngine::drawCombatScreen(int16 charId, bool whiteFl, bool drawFl) { + debugC(6, kDebugEngine, "drawCombatScreen %d %s %s", charId, whiteFl ? "True" : "False", drawFl ? "True" : "False"); for (uint counter = 0; counter < 2; ++counter) { - if (counter == 0 || forceDrawFl) { + if (counter == 0 || drawFl) { drawMapWindow(); displayCenteredString("Combat", 128, 303, 9); drawColoredRect(200, 112, 278, 132, 0); @@ -1157,7 +1157,7 @@ void EfhEngine::drawCombatScreen(int16 charId, bool whiteFl, bool forceDrawFl) { displayLowStatusScreen(false); } - if (counter == 0 && forceDrawFl) + if (counter == 0 && drawFl) displayFctFullScreen(); } } @@ -1321,30 +1321,29 @@ void EfhEngine::addReactionText(int16 id) { } void EfhEngine::sub1C4CA(bool whiteFl) { - debug("sub1C4CA %s", whiteFl ? "True" : "False"); + debugC(5, kDebugEngine, "sub1C4CA %s", whiteFl ? "True" : "False"); int16 textPosY = 20; for (uint counter = 0; counter < 5; ++counter) { if (_teamMonsterIdArray[counter] == -1) continue; - int16 var6C = computeMonsterGroupDistance(_teamMonsterIdArray[counter]); - int16 var6E = countMonsterGroupMembers(counter); + int16 monsterDistance = computeMonsterGroupDistance(_teamMonsterIdArray[counter]); + int16 mobsterCount = countMonsterGroupMembers(counter); if (whiteFl) setTextColorWhite(); else setTextColorGrey(); setTextPos(129, textPosY); - char buffer[80]; - snprintf(buffer, 80, "%c)", 'A' + counter); + Common::String buffer = Common::String::format("%c)", 'A' + counter); displayStringAtTextPos(buffer); setTextColorRed(); int16 var1 = _mapMonsters[_teamMonsterIdArray[counter]]._possessivePronounSHL6 & 0x3F; if (var1 <= 0x3D) { - snprintf(buffer, 80, "%d %s", var6E, kEncounters[_mapMonsters[_teamMonsterIdArray[counter]]._monsterRef]._name); + buffer = Common::String::format("%d %s", mobsterCount, kEncounters[_mapMonsters[_teamMonsterIdArray[counter]]._monsterRef]._name); displayStringAtTextPos(buffer); - if (var6E > 1) + if (mobsterCount > 1) displayStringAtTextPos("s"); } else if (var1 == 0x3E) { displayStringAtTextPos("(NOT DEFINED)"); @@ -1363,7 +1362,7 @@ void EfhEngine::sub1C4CA(bool whiteFl) { } setTextColorRed(); - switch (var6C) { + switch (monsterDistance) { case 1: displayCenteredString("S", 290, 302, textPosY); break; diff --git a/engines/efh/files.cpp b/engines/efh/files.cpp index 51d4a60b170a..dfc475f313f6 100644 --- a/engines/efh/files.cpp +++ b/engines/efh/files.cpp @@ -174,7 +174,7 @@ void EfhEngine::loadNewPortrait() { } void EfhEngine::loadAnimImageSet() { - debug("loadAnimImageSet"); + debugC(3, kDebugEngine, "loadAnimImageSet"); if (_currentAnimImageSetId == _animImageSetId || _animImageSetId == 0xFF) return; @@ -189,7 +189,7 @@ void EfhEngine::loadAnimImageSet() { } void EfhEngine::loadHistory() { - debug("loadHistory"); + debugC(2, kDebugEngine, "loadHistory"); Common::String fileName = "history"; readFileToBuffer(fileName, _history); From cb8897d782fe26d926668b96679525da528faa41 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Fri, 6 Jan 2023 23:59:52 +0100 Subject: [PATCH 221/412] EFH: More renaming --- engines/efh/efh.cpp | 22 +++++++++++----------- engines/efh/efh.h | 4 ++-- engines/efh/fight.cpp | 2 +- engines/efh/menu.cpp | 2 +- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index ca1d9f81cd95..9cf0b58d2015 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -562,7 +562,7 @@ void EfhEngine::loadMapArrays(int idx) { _mapMonsters[i]._weaponItemId = mapMonstersPtr[29 * i + 5]; _mapMonsters[i]._maxDamageAbsorption = mapMonstersPtr[29 * i + 6]; _mapMonsters[i]._monsterRef = mapMonstersPtr[29 * i + 7]; - _mapMonsters[i]._moveInfo = mapMonstersPtr[29 * i + 8]; + _mapMonsters[i]._additionalInfo = mapMonstersPtr[29 * i + 8]; _mapMonsters[i]._talkTextId = mapMonstersPtr[29 * i + 9]; _mapMonsters[i]._groupSize = mapMonstersPtr[29 * i + 10]; for (int j = 0; j < 9; ++j) @@ -1595,10 +1595,10 @@ bool EfhEngine::checkMonsterMovementType(int16 id, bool teamFlag) { if (teamFlag) monsterId = _teamMonsterIdArray[id]; - if ((_mapMonsters[monsterId]._moveInfo & 0xF) >= 8) + if ((_mapMonsters[monsterId]._additionalInfo & 0xF) >= 8) return true; - if (_unk2C8AA != 0 && (_mapMonsters[monsterId]._moveInfo & 0x80) != 0) + if (_unk2C8AA != 0 && (_mapMonsters[monsterId]._additionalInfo & 0x80) != 0) return true; return false; @@ -1666,12 +1666,12 @@ void EfhEngine::handleMapMonsterMoves() { bool monsterMovedFl = false; int16 lastRangeCheck = 0; - int8 monsterMoveType = _mapMonsters[monsterId]._moveInfo & 0xF; // 0000 1111 + int8 monsterMoveType = _mapMonsters[monsterId]._additionalInfo & 0xF; // 0000 1111 - if (_unk2C8AA != 0 && (_mapMonsters[monsterId]._moveInfo & 0x80)) // 1000 0000 + if (_unk2C8AA != 0 && (_mapMonsters[monsterId]._additionalInfo & 0x80)) // 1000 0000 monsterMoveType = 9; - int16 randomModPct = _mapMonsters[monsterId]._moveInfo & 0x70; // 0111 0000 + int16 randomModPct = _mapMonsters[monsterId]._additionalInfo & 0x70; // 0111 0000 randomModPct >>= 4; // Max 7 (0111) int16 retryCounter = randomModPct; @@ -2564,8 +2564,8 @@ bool EfhEngine::hasObjectEquipped(int16 charId, int16 objectId) { } -void EfhEngine::setMapMonsterMovementType(int16 id, uint8 movementType, bool groupFl) { - debugC(2, kDebugEngine, "setMapMonsterMovementType %d 0x%X %s", id, movementType, groupFl ? "True" : "False"); +void EfhEngine::setMapMonsterAggressivenessAndMovementType(int16 id, uint8 mask, bool groupFl) { + debugC(2, kDebugEngine, "setMapMonsterAggressivenessAndMovementType %d 0x%X %s", id, mask, groupFl ? "True" : "False"); int16 monsterId; if (groupFl) { // groupFl is always True @@ -2574,9 +2574,9 @@ void EfhEngine::setMapMonsterMovementType(int16 id, uint8 movementType, bool gro monsterId = id; } - movementType &= 0x0F; - _mapMonsters[monsterId]._moveInfo &= 0xF0; - _mapMonsters[monsterId]._moveInfo |= movementType; + mask &= 0x0F; + _mapMonsters[monsterId]._additionalInfo &= 0xF0; + _mapMonsters[monsterId]._additionalInfo |= mask; } bool EfhEngine::isMonsterActive(int16 groupId, int16 id) { diff --git a/engines/efh/efh.h b/engines/efh/efh.h index e8f5f265bd2f..00dc53d39de2 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -214,7 +214,7 @@ struct MapMonster { uint8 _weaponItemId; uint8 _maxDamageAbsorption; uint8 _monsterRef; - uint8 _moveInfo; // abbb cccc a: special move flag, bbb: Pct modifier for random move, cccc movement type + uint8 _additionalInfo; // abbb cddd a: special move flag, bbb: Pct modifier for random move, c aggressiveness, ddd movetype uint8 _talkTextId; uint8 _groupSize; int16 _hitPoints[9]; @@ -370,7 +370,7 @@ class EfhEngine : public Engine { int16 getXPLevel(int32 xp); bool isItemCursed(int16 itemId); bool hasObjectEquipped(int16 charId, int16 objectId); - void setMapMonsterMovementType(int16 id, uint8 movementType, bool groupFl); + void setMapMonsterAggressivenessAndMovementType(int16 id, uint8 mask, bool groupFl); bool isMonsterActive(int16 groupId, int16 id); int16 getTileFactId(int16 mapPosX, int16 mapPosY); void setCharacterObjectToBroken(int16 charId, int16 objectId); diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index 32b862109cd2..092b032b6f60 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -456,7 +456,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { if (isMonsterActive(groupId, mobsterCounter) && var6E) { bool noticedFl; if (!checkMonsterMovementType(groupId, true)) { - setMapMonsterMovementType(groupId, 9, true); + setMapMonsterAggressivenessAndMovementType(groupId, 9, true); _unk2C8AA += 500; noticedFl = true; } else diff --git a/engines/efh/menu.cpp b/engines/efh/menu.cpp index 323811b02546..91f034dfd511 100644 --- a/engines/efh/menu.cpp +++ b/engines/efh/menu.cpp @@ -1049,7 +1049,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in displayString_3("There is no apparent affect!", false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += " The magic sparkles brilliant hues in the air!"; - setMapMonsterMovementType(teamMonsterId, _items[itemId]._field17_attackTypeDefense, true); + setMapMonsterAggressivenessAndMovementType(teamMonsterId, _items[itemId]._field17_attackTypeDefense, true); } objectUsedFl = true; break; From 3dbb8bb1a0d4700ec78c84a1949e4b1f0f338b85 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sat, 7 Jan 2023 10:20:25 +0100 Subject: [PATCH 222/412] EFH: Fix implementation of checkSpecialItemsOnCurrentPlace(), modify displayCharacterInformationOrSkills() so it doesn't rely on out of bonds reads, validate some functions and add comments --- engines/efh/constants.cpp | 3 + engines/efh/efh.cpp | 100 +------------------------- engines/efh/efh.h | 2 +- engines/efh/fight.cpp | 145 ++++++++++++++++++++++++++++++++------ engines/efh/menu.cpp | 12 +++- 5 files changed, 136 insertions(+), 126 deletions(-) diff --git a/engines/efh/constants.cpp b/engines/efh/constants.cpp index dfcb5704fbf3..a261703b8f4f 100644 --- a/engines/efh/constants.cpp +++ b/engines/efh/constants.cpp @@ -342,6 +342,7 @@ const Encounter kEncounters[] { }; const char kSkillArray[37][20] = { +// Active Scores "Flying", "Swimming", "Electrical", @@ -357,6 +358,7 @@ const char kSkillArray[37][20] = { "Explosives", "Chemistry", "Steal", +// Passive Scores "Dueling", "Marksmanship", "Fist Fighting", @@ -368,6 +370,7 @@ const char kSkillArray[37][20] = { "Automatic/SMG", "Archery", "Rocket Lncher", +// Info Scores "Strength", "Intelligence", "Piety", diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 9cf0b58d2015..ff852d02b412 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -2266,7 +2266,7 @@ void EfhEngine::computeInitiatives() { for (int counter = 0; counter < 3; ++counter) { if (_teamCharId[counter] != -1 && counter < _teamSize) { _initiatives[counter]._id = counter + 1000; - _initiatives[counter]._initiative = _npcBuf[_teamCharId[counter]]._infoScore[3]; + _initiatives[counter]._initiative = _npcBuf[_teamCharId[counter]]._infoScore[3]; // "Agility" } else { _initiatives[counter]._id = -1; _initiatives[counter]._initiative = -1; @@ -2344,104 +2344,6 @@ void EfhEngine::sub1CAB6(int16 charId) { } } -// The parameter isn't used in the original -void EfhEngine::sub1BE9A(int16 monsterId) { - debug("sub1BE9A %d", monsterId); - - // sub1BE9A - 1rst loop counter1_monsterId - Start - for (uint counter1 = 0; counter1 < 5; ++counter1) { - if (countMonsterGroupMembers(counter1)) - continue; - - for (uint counter2 = 0; counter2 < 9; ++counter2) { - _mapMonsters[_teamMonsterIdArray[counter1]]._hitPoints[counter2] = 0; - _teamMonsterEffects[counter1]._effect[counter2] = 0; - _teamMonsterEffects[counter1]._duration[counter2] = 0; - } - - _teamMonsterIdArray[counter1] = -1; - - // CHECKME: counter1 is not incrementing, which is very, very suspicious as we are copying over and over to the same destination - // if the purpose is compact the array, it should be handle differently - for (uint counter2 = counter1 + 1; counter2 < 5; ++counter2) { - for (uint var8 = 0; var8 < 9; ++var8) { - _teamMonsterEffects[counter1]._effect[var8] = _teamMonsterEffects[counter2]._effect[var8]; - _teamMonsterEffects[counter1]._duration[var8] = _teamMonsterEffects[counter2]._duration[var8]; - } - _teamMonsterIdArray[counter1] = _teamMonsterIdArray[counter2]; - } - - } - // sub1BE9A - 1rst loop counter1_monsterId - End - - int16 teamMonsterId = -1; - for (uint counter1 = 0; counter1 < 5; ++counter1) { - if (_teamMonsterIdArray[counter1] == -1) { - teamMonsterId = counter1; - break; - } - } - - if (teamMonsterId != -1) { - // sub1BE9A - loop var2 - Start - for (int var2 = 1; var2 < 3; ++var2) { - if (teamMonsterId >= 5) - break; - - for (uint ctrMapMonsterId = 0; ctrMapMonsterId < 64; ++ctrMapMonsterId) { - if (_mapMonsters[ctrMapMonsterId]._fullPlaceId == 0xFF) - continue; - - if (((_mapMonsters[ctrMapMonsterId]._possessivePronounSHL6 & 0x3F) == 0x3F && !isNpcATeamMember(_mapMonsters[ctrMapMonsterId]._npcId)) || (_mapMonsters[ctrMapMonsterId]._possessivePronounSHL6 & 0x3F) <= 0x3D) { - if (checkIfMonsterOnSameLargeMapPlace(ctrMapMonsterId)) { - bool monsterActiveFound = false; - for (uint ctrSubId = 0; ctrSubId < 9; ++ctrSubId) { - if (_mapMonsters[ctrMapMonsterId]._hitPoints[ctrSubId] > 0) { - monsterActiveFound = true; - break; - } - } - - if (!monsterActiveFound) - continue; - - if (computeMonsterGroupDistance(ctrMapMonsterId) > var2) - continue; - - if (isMonsterAlreadyFighting(ctrMapMonsterId, teamMonsterId)) - continue; - - _teamMonsterIdArray[teamMonsterId] = ctrMapMonsterId; - - // The original at this point was doing a loop on counter1, which is not a good idea as - // it was resetting the counter1 to 9 whatever its value before the loop. - // I therefore decided to use another counter as it looks like an original misbehavior/bug. - for (uint ctrEffectId = 0; ctrEffectId < 9; ++ctrEffectId) { - _teamMonsterEffects[teamMonsterId]._effect[ctrEffectId] = 0; - } - - if (++teamMonsterId >= 5) - break; - } - } - } - } - // sub1BE9A - loop var2 - End - } - - if (teamMonsterId == -1 || teamMonsterId > 4) - return; - - // sub1BE9A - last loop counter1_monsterId - Start - for (int16 ctrTeamMonsterId = teamMonsterId; ctrTeamMonsterId < 5; ++ctrTeamMonsterId) { - _teamMonsterIdArray[ctrTeamMonsterId] = -1; - for (uint ctrEffectId = 0; ctrEffectId < 9; ++ctrEffectId) { - _teamMonsterEffects[ctrTeamMonsterId]._effect[ctrEffectId] = (int16)0x8000; - } - } - // sub1BE9A - last loop counter1_monsterId - End -} - int16 EfhEngine::getTeamMonsterAnimId() { debug("getTeamMonsterAnimId"); diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 00dc53d39de2..b343fd88297c 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -363,7 +363,6 @@ class EfhEngine : public Engine { void redrawScreenForced(); int16 selectMonsterGroup(); void sub1CAB6(int16 charId); - void sub1BE9A(int16 monsterId); int16 getTeamMonsterAnimId(); int16 countMonsterGroupMembers(int16 monsterGroup); void sub1D8C2(int16 charId, int16 damage); @@ -404,6 +403,7 @@ class EfhEngine : public Engine { bool checkSpecialItemsOnCurrentPlace(int16 itemId); bool hasAdequateDefense(int16 monsterId, uint8 attackType); bool hasAdequateDefense_2(int16 charId, uint8 attackType); + void sub1BE9A(int16 monsterId); // Files int32 readFileToBuffer(Common::String &filename, uint8 *destBuffer); diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index 092b032b6f60..69f4b8d5b5b4 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -24,7 +24,7 @@ namespace Efh { void EfhEngine::createOpponentList(int16 monsterTeamId) { - debugC(3, kDebugEngine, "createOpponentList %d", monsterTeamId); + debugC(3, kDebugFight, "createOpponentList %d", monsterTeamId); int16 counter = 0; if (monsterTeamId != -1 && countAliveMonsters(monsterTeamId) > 0) { @@ -72,7 +72,7 @@ void EfhEngine::createOpponentList(int16 monsterTeamId) { } void EfhEngine::initFight(int16 monsterId) { - debugC(3, kDebugEngine, "initFight %d", monsterId); + debugC(3, kDebugFight, "initFight %d", monsterId); createOpponentList(monsterId); resetTeamMonsterEffects(); } @@ -642,7 +642,7 @@ void EfhEngine::handleFight_lastAction_D(int16 teamCharId) { } void EfhEngine::handleFight_lastAction_H(int16 teamCharId) { - debugC(3, kDebugEngine, "handleFight_lastAction_H %d", teamCharId); + debugC(3, kDebugFight, "handleFight_lastAction_H %d", teamCharId); // In the original, this function is part of handleFight. // It has been split for readability purposes. @@ -695,7 +695,7 @@ bool EfhEngine::isTPK() { } bool EfhEngine::isMonsterAlreadyFighting(int16 monsterId, int16 teamMonsterId) { - debugC(6, kDebugEngine, "isMonsterAlreadyFighting %d %d", monsterId, teamMonsterId); + debugC(6, kDebugFight, "isMonsterAlreadyFighting %d %d", monsterId, teamMonsterId); for (int counter = 0; counter < teamMonsterId; ++counter) { if (_teamMonsterIdArray[counter] == monsterId) @@ -705,7 +705,7 @@ bool EfhEngine::isMonsterAlreadyFighting(int16 monsterId, int16 teamMonsterId) { } void EfhEngine::resetTeamMonsterEffects() { - debugC(6, kDebugEngine, "resetTeamMonsterEffects"); + debugC(6, kDebugFight, "resetTeamMonsterEffects"); for (uint ctrMonsterId = 0; ctrMonsterId < 5; ++ctrMonsterId) { for (uint ctrEffectId = 0; ctrEffectId < 9; ++ctrEffectId) { _teamMonsterEffects[ctrMonsterId]._effect[ctrEffectId] = 0; @@ -715,7 +715,7 @@ void EfhEngine::resetTeamMonsterEffects() { } void EfhEngine::resetTeamMonsterIdArray() { - debugC(6, kDebugEngine, "resetTeamMonsterIdArray"); + debugC(6, kDebugFight, "resetTeamMonsterIdArray"); for (int i = 0; i < 5; ++i) { _teamMonsterIdArray[i] = -1; @@ -1143,7 +1143,7 @@ bool EfhEngine::sub1CB27() { } void EfhEngine::drawCombatScreen(int16 charId, bool whiteFl, bool drawFl) { - debugC(6, kDebugEngine, "drawCombatScreen %d %s %s", charId, whiteFl ? "True" : "False", drawFl ? "True" : "False"); + debugC(6, kDebugFight, "drawCombatScreen %d %s %s", charId, whiteFl ? "True" : "False", drawFl ? "True" : "False"); for (uint counter = 0; counter < 2; ++counter) { if (counter == 0 || drawFl) { @@ -1163,20 +1163,25 @@ void EfhEngine::drawCombatScreen(int16 charId, bool whiteFl, bool drawFl) { } void EfhEngine::getXPAndSearchCorpse(int16 charId, Common::String namePt1, Common::String namePt2, int16 monsterId) { - debugC(3, kDebugEngine, "getXPAndSearchCorpse %d %s%s %d", charId, namePt1.c_str(), namePt2.c_str(), monsterId); + debugC(3, kDebugFight, "getXPAndSearchCorpse %d %s%s %d", charId, namePt1.c_str(), namePt2.c_str(), monsterId); int16 oldXpLevel = getXPLevel(_npcBuf[charId]._xp); _npcBuf[charId]._xp += kEncounters[_mapMonsters[monsterId]._monsterRef]._xpGiven; if (getXPLevel(_npcBuf[charId]._xp) > oldXpLevel) { generateSound(15); - int16 hpGain = getRandom(20) + getRandom(_npcBuf[charId]._infoScore[4]); + int16 hpGain = getRandom(20) + getRandom(_npcBuf[charId]._infoScore[4]); // "Stamina" _npcBuf[charId]._hitPoints += hpGain; _npcBuf[charId]._maxHP += hpGain; + // "Strength", _npcBuf[charId]._infoScore[0] += getRandom(3) - 1; + // "Intelligence", _npcBuf[charId]._infoScore[1] += getRandom(3) - 1; + // "Piety", _npcBuf[charId]._infoScore[2] += getRandom(3) - 1; + // "Agility", _npcBuf[charId]._infoScore[3] += getRandom(3) - 1; + // "Stamina", _npcBuf[charId]._infoScore[4] += getRandom(3) - 1; } @@ -1321,7 +1326,7 @@ void EfhEngine::addReactionText(int16 id) { } void EfhEngine::sub1C4CA(bool whiteFl) { - debugC(5, kDebugEngine, "sub1C4CA %s", whiteFl ? "True" : "False"); + debugC(5, kDebugFight, "sub1C4CA %s", whiteFl ? "True" : "False"); int16 textPosY = 20; for (uint counter = 0; counter < 5; ++counter) { @@ -1412,7 +1417,7 @@ int16 EfhEngine::sub1DEC8(int16 groupNumber) { } int16 EfhEngine::getCharacterScore(int16 charId, int16 itemId) { - debug("getCharacterScore %d %d", charId, itemId); + debugC(3, kDebugFight, "getCharacterScore %d %d", charId, itemId); int16 totalScore = 0; switch (_items[itemId]._range) { @@ -1420,7 +1425,7 @@ int16 EfhEngine::getCharacterScore(int16 charId, int16 itemId) { totalScore = _npcBuf[charId]._passiveScore[5] + _npcBuf[charId]._passiveScore[3] + _npcBuf[charId]._passiveScore[4]; totalScore += _npcBuf[charId]._infoScore[0] / 5; totalScore += _npcBuf[charId]._infoScore[2] * 2, - totalScore += _npcBuf[charId]._infoScore[6] / 5; + totalScore += _npcBuf[charId]._infoScore[6] / 5; totalScore += 2 * _npcBuf[charId]._infoScore[5] / 5; break; case 1: @@ -1488,12 +1493,9 @@ int16 EfhEngine::getCharacterScore(int16 charId, int16 itemId) { extraScore += _items[itemId].field_13; - int16 grandTotalScore = totalScore + extraScore; - if (grandTotalScore > 60) - grandTotalScore = 60; + int16 grandTotalScore = CLIP(totalScore + extraScore + 30, 5, 90); - int16 retVal = CLIP(grandTotalScore + 30, 5, 90); - return retVal; + return grandTotalScore; } bool EfhEngine::checkSpecialItemsOnCurrentPlace(int16 itemId) { @@ -1501,13 +1503,13 @@ bool EfhEngine::checkSpecialItemsOnCurrentPlace(int16 itemId) { switch (_techDataArr[_techId][_techDataId_MapPosX * 64 + _techDataId_MapPosY]) { case 1: - if ((itemId < 0x58 || itemId > 0x68) && (itemId < 0x86 || itemId > 0x89) && (itemId < 0x74 || itemId > 0x76) && (itemId != 0x8C)) - return true; - return false; + if ((itemId >= 0x58 && itemId <= 0x68) || (itemId >= 0x86 && itemId <= 0x89) || (itemId >= 0x74 && itemId <= 0x76) || itemId == 0x8C) + return false; + return true; case 2: - if ((itemId < 0x61 || itemId > 0x63) && (itemId < 0x74 || itemId > 0x76) && (itemId < 0x86 || itemId > 0x89) && (itemId < 0x5B || itemId > 0x5E) && (itemId < 0x66 || itemId > 0x68) && (itemId != 0x8C)) - return true; - return false; + if ((itemId >= 0x61 && itemId <= 0x63) || (itemId >= 0x74 && itemId <= 0x76) || (itemId >= 0x86 && itemId <= 0x89) || itemId == 0x5B || itemId == 0x5E || itemId == 0x66 || itemId == 0x68 || itemId == 0x8C) + return false; + return true; default: return true; } @@ -1543,4 +1545,101 @@ bool EfhEngine::hasAdequateDefense_2(int16 charId, uint8 attackType) { return false; } +// The parameter isn't used in the original +void EfhEngine::sub1BE9A(int16 monsterId) { + debug("sub1BE9A %d", monsterId); + + // sub1BE9A - 1rst loop counter1_monsterId - Start + for (uint counter1 = 0; counter1 < 5; ++counter1) { + if (countMonsterGroupMembers(counter1)) + continue; + + for (uint counter2 = 0; counter2 < 9; ++counter2) { + _mapMonsters[_teamMonsterIdArray[counter1]]._hitPoints[counter2] = 0; + _teamMonsterEffects[counter1]._effect[counter2] = 0; + _teamMonsterEffects[counter1]._duration[counter2] = 0; + } + + _teamMonsterIdArray[counter1] = -1; + + // CHECKME: counter1 is not incrementing, which is very, very suspicious as we are copying over and over to the same destination + // if the purpose is compact the array, it should be handle differently + for (uint counter2 = counter1 + 1; counter2 < 5; ++counter2) { + for (uint var8 = 0; var8 < 9; ++var8) { + _teamMonsterEffects[counter1]._effect[var8] = _teamMonsterEffects[counter2]._effect[var8]; + _teamMonsterEffects[counter1]._duration[var8] = _teamMonsterEffects[counter2]._duration[var8]; + } + _teamMonsterIdArray[counter1] = _teamMonsterIdArray[counter2]; + } + } + // sub1BE9A - 1rst loop counter1_monsterId - End + + int16 teamMonsterId = -1; + for (uint counter1 = 0; counter1 < 5; ++counter1) { + if (_teamMonsterIdArray[counter1] == -1) { + teamMonsterId = counter1; + break; + } + } + + if (teamMonsterId != -1) { + // sub1BE9A - loop var2 - Start + for (int var2 = 1; var2 < 3; ++var2) { + if (teamMonsterId >= 5) + break; + + for (uint ctrMapMonsterId = 0; ctrMapMonsterId < 64; ++ctrMapMonsterId) { + if (_mapMonsters[ctrMapMonsterId]._fullPlaceId == 0xFF) + continue; + + if (((_mapMonsters[ctrMapMonsterId]._possessivePronounSHL6 & 0x3F) == 0x3F && !isNpcATeamMember(_mapMonsters[ctrMapMonsterId]._npcId)) || (_mapMonsters[ctrMapMonsterId]._possessivePronounSHL6 & 0x3F) <= 0x3D) { + if (checkIfMonsterOnSameLargeMapPlace(ctrMapMonsterId)) { + bool monsterActiveFound = false; + for (uint ctrSubId = 0; ctrSubId < 9; ++ctrSubId) { + if (_mapMonsters[ctrMapMonsterId]._hitPoints[ctrSubId] > 0) { + monsterActiveFound = true; + break; + } + } + + if (!monsterActiveFound) + continue; + + if (computeMonsterGroupDistance(ctrMapMonsterId) > var2) + continue; + + if (isMonsterAlreadyFighting(ctrMapMonsterId, teamMonsterId)) + continue; + + _teamMonsterIdArray[teamMonsterId] = ctrMapMonsterId; + + // The original at this point was doing a loop on counter1, which is not a good idea as + // it was resetting the counter1 to 9 whatever its value before the loop. + // I therefore decided to use another counter as it looks like an original misbehavior/bug. + for (uint ctrEffectId = 0; ctrEffectId < 9; ++ctrEffectId) { + _teamMonsterEffects[teamMonsterId]._effect[ctrEffectId] = 0; + } + + if (++teamMonsterId >= 5) + break; + } + } + } + } + // sub1BE9A - loop var2 - End + } + + if (teamMonsterId == -1 || teamMonsterId > 4) + return; + + // sub1BE9A - last loop counter1_monsterId - Start + for (int16 ctrTeamMonsterId = teamMonsterId; ctrTeamMonsterId < 5; ++ctrTeamMonsterId) { + _teamMonsterIdArray[ctrTeamMonsterId] = -1; + for (uint ctrEffectId = 0; ctrEffectId < 9; ++ctrEffectId) { + _teamMonsterEffects[ctrTeamMonsterId]._effect[ctrEffectId] = (int16)0x8000; + } + } + // sub1BE9A - last loop counter1_monsterId - End +} + } // End of namespace Efh diff --git a/engines/efh/menu.cpp b/engines/efh/menu.cpp index 91f034dfd511..a6e84154fe09 100644 --- a/engines/efh/menu.cpp +++ b/engines/efh/menu.cpp @@ -398,8 +398,14 @@ void EfhEngine::displayCharacterInformationOrSkills(int16 curMenuLine, int16 cha displayStringAtTextPos(buffer); setTextPos(163, textPosY); - displayStringAtTextPos(kSkillArray[_menuStatItemArr[counter]]); - buffer = Common::String::format("%d", _npcBuf[charId]._activeScore[_menuStatItemArr[counter]]); + int16 scoreId = _menuStatItemArr[counter]; + displayStringAtTextPos(kSkillArray[scoreId]); + if (scoreId < 15) + buffer = Common::String::format("%d", _npcBuf[charId]._activeScore[_menuStatItemArr[counter]]); + else if (scoreId < 26) + buffer = Common::String::format("%d", _npcBuf[charId]._passiveScore[_menuStatItemArr[counter] - 15]); + else if (scoreId < 37) + buffer = Common::String::format("%d", _npcBuf[charId]._infoScore[_menuStatItemArr[counter] - 26]); setTextPos(278, textPosY); displayStringAtTextPos(buffer); setTextColorRed(); @@ -468,7 +474,7 @@ void EfhEngine::prepareStatusMenu(int16 windowId, int16 menuId, int16 curMenuLin } void EfhEngine::displayWindowAndStatusMenu(int16 charId, int16 windowId, int16 menuId, int16 curMenuLine) { - debug("displayWindowAndStatusMenu %d %d %d %d", charId, windowId, menuId, curMenuLine); + debugC(6, kDebugEngine, "displayWindowAndStatusMenu %d %d %d %d", charId, windowId, menuId, curMenuLine); for (int counter = 0; counter < 2; ++counter) { displayWindow(_menuBuf, 0, 0, _hiResImageBuf); From 1f15de9b97551eab5b07c026126051abd0226c25 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sun, 8 Jan 2023 20:28:14 +0100 Subject: [PATCH 223/412] EFH: Move getTeamMonsterAnimId to fight.cpp (and validate it), some renaming in script_parse --- engines/efh/efh.cpp | 23 +-------- engines/efh/efh.h | 4 +- engines/efh/fight.cpp | 22 +++++++++ engines/efh/menu.cpp | 4 ++ engines/efh/script.cpp | 103 +++++++++++++++++++++-------------------- 5 files changed, 81 insertions(+), 75 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index ff852d02b412..dfffbc38f11c 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -538,6 +538,7 @@ void EfhEngine::initMapMonsters() { void EfhEngine::loadMapArrays(int idx) { debugC(6, kDebugEngine, "loadMapArrays %d", idx); + debug("TODO : rewrite the pre-loadign of data and loadMapArrays in order to avoid to lose info when changing map"); uint8 *mapSpecialTilePtr = &_mapArr[idx][2]; @@ -2344,28 +2345,6 @@ void EfhEngine::sub1CAB6(int16 charId) { } } -int16 EfhEngine::getTeamMonsterAnimId() { - debug("getTeamMonsterAnimId"); - - int16 retVal = 0xFF; - for (uint counter = 0; counter < 5; ++counter) { - int16 monsterId = _teamMonsterIdArray[counter]; - if (monsterId == -1) - continue; - - if (!checkMonsterMovementType(monsterId, false)) - continue; - - retVal = kEncounters[_mapMonsters[monsterId]._monsterRef]._animId; - break; - } - - if (retVal == 0xFF) - retVal = kEncounters[_mapMonsters[_teamMonsterIdArray[0]]._monsterRef]._animId; - - return retVal; -} - int16 EfhEngine::countMonsterGroupMembers(int16 monsterGroup) { debugC(9, kDebugEngine, "countMonsterGroupMembers %d", monsterGroup); diff --git a/engines/efh/efh.h b/engines/efh/efh.h index b343fd88297c..0eb8db566a6d 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -363,7 +363,6 @@ class EfhEngine : public Engine { void redrawScreenForced(); int16 selectMonsterGroup(); void sub1CAB6(int16 charId); - int16 getTeamMonsterAnimId(); int16 countMonsterGroupMembers(int16 monsterGroup); void sub1D8C2(int16 charId, int16 damage); int16 getXPLevel(int32 xp); @@ -404,6 +403,7 @@ class EfhEngine : public Engine { bool hasAdequateDefense(int16 monsterId, uint8 attackType); bool hasAdequateDefense_2(int16 charId, uint8 attackType); void sub1BE9A(int16 monsterId); + int16 getTeamMonsterAnimId(); // Files int32 readFileToBuffer(Common::String &filename, uint8 *destBuffer); @@ -479,7 +479,7 @@ class EfhEngine : public Engine { // Script uint8 *script_readNumberArray(uint8 *buffer, int16 destArraySize, int16 *destArray); uint8 *script_getNumber(uint8 *srcBuffer, int16 *retBuf); - int16 script_parse(Common::String str, int16 posX, int16 posY, int16 maxX, int16 maxY, bool flag); + int16 script_parse(Common::String str, int16 posX, int16 posY, int16 maxX, int16 maxY, bool scriptExecuteFlag); // Sound void generateSound1(int arg0, int arg2, int duration); diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index 69f4b8d5b5b4..5f01a494b145 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -1642,4 +1642,26 @@ void EfhEngine::sub1BE9A(int16 monsterId) { // sub1BE9A - last loop counter1_monsterId - End } +int16 EfhEngine::getTeamMonsterAnimId() { + debugC(6, kDebugFight, "getTeamMonsterAnimId"); + + int16 retVal = 0xFF; + for (uint counter = 0; counter < 5; ++counter) { + int16 monsterId = _teamMonsterIdArray[counter]; + if (monsterId == -1) + continue; + + if (!checkMonsterMovementType(monsterId, false)) + continue; + + retVal = kEncounters[_mapMonsters[monsterId]._monsterRef]._animId; + break; + } + + if (retVal == 0xFF) + retVal = kEncounters[_mapMonsters[_teamMonsterIdArray[0]]._monsterRef]._animId; + + return retVal; +} + } // End of namespace Efh diff --git a/engines/efh/menu.cpp b/engines/efh/menu.cpp index a6e84154fe09..c052aeb2a8b6 100644 --- a/engines/efh/menu.cpp +++ b/engines/efh/menu.cpp @@ -893,6 +893,10 @@ void EfhEngine::tryToggleEquipped(int16 charId, int16 objectId, int16 windowId, int16 curType = _items[itemId]._exclusiveType; if (curType != 4) { for (uint counter = 0; counter < 10; ++counter) { + if (_npcBuf[charId]._inventory[counter]._ref == 0x7FFF) { + warning("CHECKME : hack"); + continue; + } if (curType == _items[_npcBuf[charId]._inventory[counter]._ref]._exclusiveType) unequipItem(charId, objectId, windowId, menuId, curMenuLine); } diff --git a/engines/efh/script.cpp b/engines/efh/script.cpp index 7d6a74e46f4f..ca57a000d01c 100644 --- a/engines/efh/script.cpp +++ b/engines/efh/script.cpp @@ -54,13 +54,14 @@ uint8 *EfhEngine::script_getNumber(uint8 *srcBuffer, int16 *retBuf) { return buffer; } -int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 posY, int16 maxX, int16 maxY, bool flag) { - debug("script_parse %s %d-%d %d-%d %s", stringBuffer.c_str(), posX, posY, maxX, maxY, flag ? "True" : "False"); +int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 posY, int16 maxX, int16 maxY, bool scriptExecuteFlag) { + debug("script_parse stringBuffer %d-%d %d-%d %s", posX, posY, maxX, maxY, scriptExecuteFlag ? "True" : "False"); + debugC(6, kDebugScript, "%s", stringBuffer.c_str()); bool doneFlag = false; - int16 var_F2 = -1; + bool noTextFlag = true; int16 retVal = 0xFF; - int16 var_EE = 0xFF; + int16 joiningNpcId = 0xFF; uint16 curLineNb = 0; int16 numbLines = (1 + maxY - posY) / 9; int16 width = maxX - posX; @@ -74,28 +75,28 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos while (!doneFlag) { uint8 curChar = *buffer; - if (curChar != 0x5E && curChar != 0x20 && curChar != 0 && curChar != 0x7C) { - var_F2 = 0; + if (curChar != 0x5E && curChar != 0x20 && curChar != 0 && curChar != 0x7C) { // '^', ' ', NUL, '|' + noTextFlag = false; nextWord[curWordPos++] = curChar; ++buffer; continue; } - if (curChar != 0x5E) { + if (curChar != 0x5E) { // '^' if (curChar == 0) doneFlag = true; - else if (curChar == 0x7C) - var_F2 = 0; + else if (curChar == 0x7C) // '|' + noTextFlag = false; nextWord[curWordPos] = 0; int16 widthNextWord = getStringWidth(nextWord); int16 widthCurrentLine = spaceWidth + getStringWidth(curLine.c_str()); - if (widthCurrentLine + widthNextWord > width || curChar == 0x7C) { + if (widthCurrentLine + widthNextWord > width || curChar == 0x7C) { // '|' if (curLineNb >= numbLines) { doneFlag = true; } else { - if (var_F2 == 0) + if (!noTextFlag) displayStringAtTextPos(curLine); curLine = Common::String(nextWord) + " "; @@ -111,7 +112,7 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos continue; } - // At this point, curChar == 0x5E + // At this point, curChar == 0x5E '^' ++buffer; int16 opCode = 0; buffer = script_getNumber(buffer, &opCode); @@ -122,7 +123,7 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos case 0x00: // Enter room { full Place Id, posX, posY } buffer = script_readNumberArray(buffer, 3, scriptNumberArray); - if (flag) { + if (scriptExecuteFlag) { if (_largeMapFlag) { _largeMapFlag = false; _techDataId_MapPosX = _mapPosX; @@ -137,7 +138,7 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos break; case 0x01: // Exit room { } - if (flag) { + if (scriptExecuteFlag) { _largeMapFlag = true; _oldMapPosX = _mapPosX = _techDataId_MapPosX; _oldMapPosY = _mapPosY = _techDataId_MapPosY; @@ -148,7 +149,7 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos case 0x02: // Change map. { map number, posX, posY } buffer = script_readNumberArray(buffer, 3, scriptNumberArray); - if (flag) { + if (scriptExecuteFlag) { writeTechAndMapFiles(); _oldMapPosX = _mapPosX = scriptNumberArray[1]; _oldMapPosY = _mapPosY = scriptNumberArray[2]; @@ -161,7 +162,7 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos break; case 0x03: buffer = script_readNumberArray(buffer, 4, scriptNumberArray); - if (flag) { + if (scriptExecuteFlag) { int16 rangeX = scriptNumberArray[2] - scriptNumberArray[0]; int16 rangeY = scriptNumberArray[3] - scriptNumberArray[1]; @@ -173,7 +174,7 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos break; case 0x04: buffer = script_readNumberArray(buffer, 2, scriptNumberArray); - if (flag) { + if (scriptExecuteFlag) { _mapPosX = scriptNumberArray[0]; _mapPosY = scriptNumberArray[1]; _word2C880 = true; @@ -182,7 +183,7 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos break; case 0x05: buffer = script_readNumberArray(buffer, 4, scriptNumberArray); - if (flag) { + if (scriptExecuteFlag) { int16 npcId = _teamCharId[scriptNumberArray[0]]; if (npcId != -1) { int16 scoreId = scriptNumberArray[1]; @@ -193,7 +194,7 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos break; case 0x06: buffer = script_readNumberArray(buffer, 2, scriptNumberArray); - if (flag) { + if (scriptExecuteFlag) { int16 npcId = _teamCharId[scriptNumberArray[0]]; if (npcId != -1) { int16 scoreId = scriptNumberArray[1]; @@ -202,19 +203,19 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos } break; case 0x07: - if (flag) { + if (scriptExecuteFlag) { totalPartyKill(); } break; case 0x08: buffer = script_readNumberArray(buffer, 1, scriptNumberArray); - if (flag && scriptNumberArray[0] != -1) { + if (scriptExecuteFlag && scriptNumberArray[0] != -1) { _npcBuf[_teamCharId[scriptNumberArray[0]]]._hitPoints = 0; } break; case 0x09: buffer = script_readNumberArray(buffer, 2, scriptNumberArray); - if (flag) { + if (scriptExecuteFlag) { int16 npcId = _teamCharId[scriptNumberArray[0]]; if (npcId != -1) { _npcBuf[npcId]._hitPoints += getRandom(scriptNumberArray[1]); @@ -225,7 +226,7 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos break; case 0x0A: buffer = script_readNumberArray(buffer, 1, scriptNumberArray); - if (flag) { + if (scriptExecuteFlag) { int16 npcId = _teamCharId[scriptNumberArray[0]]; if (npcId != -1) { _npcBuf[npcId]._hitPoints = _npcBuf[npcId]._maxHP; @@ -234,7 +235,7 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos break; case 0x0B: buffer = script_readNumberArray(buffer, 2, scriptNumberArray); - if (flag) { + if (scriptExecuteFlag) { int16 npcId = _teamCharId[scriptNumberArray[0]]; if (npcId != -1) { _npcBuf[npcId]._hitPoints -= getRandom(scriptNumberArray[1]); @@ -245,7 +246,7 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos break; case 0x0C: buffer = script_readNumberArray(buffer, 2, scriptNumberArray); - if (flag) { + if (scriptExecuteFlag) { int16 scriptItemId = scriptNumberArray[0]; bool found = false; for (int counter = 0; counter < _teamSize && !found; ++counter) { @@ -262,7 +263,7 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos case 0x0D: // Put item in inventory { objectId } buffer = script_readNumberArray(buffer, 1, scriptNumberArray); - if (flag) { + if (scriptExecuteFlag) { int16 scriptObjectId = scriptNumberArray[0]; for (int counter = 0; counter < _teamSize; ++counter) { if (giveItemTo(_teamCharId[counter], scriptObjectId, 0xFF)) @@ -272,7 +273,7 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos break; case 0x0E: buffer = script_readNumberArray(buffer, 3, scriptNumberArray); - if (flag) { + if (scriptExecuteFlag) { int16 scriptItemId = scriptNumberArray[0]; bool found = false; for (int counter = 0; counter < _teamSize && !found; ++counter) { @@ -292,7 +293,7 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos break; case 0x0F: buffer = script_readNumberArray(buffer, 3, scriptNumberArray); - if (flag) { + if (scriptExecuteFlag) { if (isNpcATeamMember(scriptNumberArray[0])) retVal = scriptNumberArray[1]; else @@ -301,17 +302,17 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos break; case 0x10: buffer = script_readNumberArray(buffer, 1, scriptNumberArray); - if (flag) + if (scriptExecuteFlag) retVal = scriptNumberArray[0]; break; case 0x11: - if (flag) + if (scriptExecuteFlag) _unk2C8AA = 0; break; case 0x12: // Disable special tile - if (flag) { + if (scriptExecuteFlag) { int16 tileId = findMapSpecialTileIndex(_mapPosX, _mapPosY); if (tileId != -1) _mapSpecialTile[tileId]._posX = 0xFF; @@ -319,7 +320,7 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos break; case 0x13: buffer = script_readNumberArray(buffer, 3, scriptNumberArray); - if (flag && _largeMapFlag) { + if (scriptExecuteFlag && _largeMapFlag) { _word2C87A = true; loadPlacesFile(scriptNumberArray[0], false); transitionMap(scriptNumberArray[1], scriptNumberArray[2]); @@ -330,16 +331,16 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos case 0x14: // Add character to team { charId } buffer = script_readNumberArray(buffer, 1, scriptNumberArray); - if (flag) { + if (scriptExecuteFlag) { int16 scriptNpcId = scriptNumberArray[0]; if (!isNpcATeamMember(scriptNpcId)) - var_EE = scriptNpcId; + joiningNpcId = scriptNpcId; retVal = -1; } break; case 0x15: buffer = script_readNumberArray(buffer, 2, scriptNumberArray); - if (flag) { + if (scriptExecuteFlag) { _oldMapPosX = _mapPosX = scriptNumberArray[0]; _oldMapPosY = _mapPosY = scriptNumberArray[1]; _largeMapFlag = true; @@ -348,7 +349,7 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos break; case 0x16: buffer = script_readNumberArray(buffer, 1, scriptNumberArray); - if (flag) { + if (scriptExecuteFlag) { int16 scriptNpcId = scriptNumberArray[0]; // TODO: This "if" is useless, it's doing just the same loop and if statement. Consider removing it. if (isNpcATeamMember(scriptNpcId)) { @@ -363,14 +364,14 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos break; case 0x17: buffer = script_readNumberArray(buffer, 1, scriptNumberArray); - if (flag) { - int16 var110 = scriptNumberArray[0]; - displayAnimFrames(var110, true); + if (scriptExecuteFlag) { + int16 animId = scriptNumberArray[0]; + displayAnimFrames(animId, true); } break; case 0x18: buffer = script_readNumberArray(buffer, 2, scriptNumberArray); - if (flag) { + if (scriptExecuteFlag) { bool found = false; int16 scriptRandomItemId = getRandom(scriptNumberArray[1] - scriptNumberArray[0] + 1) + scriptNumberArray[0] - 1; int16 counter; @@ -408,7 +409,7 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos break; case 0x19: buffer = script_readNumberArray(buffer, 3, scriptNumberArray); - if (flag) { + if (scriptExecuteFlag) { if (_largeMapFlag) { _mapGameMap[scriptNumberArray[0]][scriptNumberArray[1]] = scriptNumberArray[2] & 0xFF; } else { @@ -418,7 +419,7 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos break; case 0x1A: buffer = script_readNumberArray(buffer, 2, scriptNumberArray); - if (flag) { + if (scriptExecuteFlag) { int16 tileId = findMapSpecialTileIndex(scriptNumberArray[0], scriptNumberArray[1]); if (tileId != -1) { // Disable tile @@ -428,7 +429,7 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos break; case 0x1B: buffer = script_readNumberArray(buffer, 3, scriptNumberArray); - if (flag) { + if (scriptExecuteFlag) { int16 tileId = findMapSpecialTileIndex(scriptNumberArray[0], scriptNumberArray[1]); if (tileId != -1) { // Disable tile @@ -440,20 +441,20 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos break; case 0x1C: buffer = script_readNumberArray(buffer, 1, scriptNumberArray); - if (flag) { + if (scriptExecuteFlag) { _history[scriptNumberArray[0]] = 0xFF; } break; case 0x1D: buffer = script_readNumberArray(buffer, 1, scriptNumberArray); - if (flag) { + if (scriptExecuteFlag) { _history[scriptNumberArray[0]] = 0; } break; case 0x1E: // Dialog with condition { historyId, dialogId1, dialogId2 } buffer = script_readNumberArray(buffer, 3, scriptNumberArray); - if (flag) { + if (scriptExecuteFlag) { if (_history[scriptNumberArray[0]] == 0) retVal = scriptNumberArray[2]; else @@ -462,12 +463,12 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos break; case 0x1F: buffer = script_readNumberArray(buffer, 1, scriptNumberArray); - if (flag) + if (scriptExecuteFlag) _unk2C8AA = scriptNumberArray[0]; break; case 0x20: - if (flag) { + if (scriptExecuteFlag) { handleWinSequence(); _system->quit(); } @@ -476,14 +477,14 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos } } - if (curLine.size() >= 0 && curLineNb < numbLines && var_F2 == 0) + if (curLine.size() >= 0 && curLineNb < numbLines && !noTextFlag) displayStringAtTextPos(curLine); - if (var_EE != 0xFF) { + if (joiningNpcId != 0xFF) { displayLowStatusScreen(true); int16 teamSlot = handleCharacterJoining(); if (teamSlot > -1) { - _teamCharId[teamSlot] = var_EE; + _teamCharId[teamSlot] = joiningNpcId; } refreshTeamSize(); } From 878576311d4d918bc36f680d97f87fb50746ff48 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sun, 8 Jan 2023 22:56:03 +0100 Subject: [PATCH 224/412] EFH: Change EFH_EFH_H_ to EFH_H based on sev's review. Fix a typo --- engines/efh/efh.cpp | 2 +- engines/efh/efh.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index dfffbc38f11c..7e277b2b919b 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -538,7 +538,7 @@ void EfhEngine::initMapMonsters() { void EfhEngine::loadMapArrays(int idx) { debugC(6, kDebugEngine, "loadMapArrays %d", idx); - debug("TODO : rewrite the pre-loadign of data and loadMapArrays in order to avoid to lose info when changing map"); + debug("TODO : rewrite the pre-loading of data and loadMapArrays in order to avoid to lose info when changing map"); uint8 *mapSpecialTilePtr = &_mapArr[idx][2]; diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 0eb8db566a6d..34a4bd18194c 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -19,8 +19,8 @@ * */ -#ifndef EFH_EFH_H -#define EFH_EFH_H +#ifndef EFH_H +#define EFH_H #include "engines/advancedDetector.h" From ba46f70a62b633ec6073f1b3ea40b19ef9ceffa2 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sun, 8 Jan 2023 23:03:42 +0100 Subject: [PATCH 225/412] EFH: Change include order in EFH.H (sev's review) --- engines/efh/efh.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 34a4bd18194c..14d7df47ea17 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -22,13 +22,12 @@ #ifndef EFH_H #define EFH_H -#include "engines/advancedDetector.h" - #include "common/file.h" #include "common/rect.h" #include "common/events.h" #include "common/serializer.h" +#include "engines/advancedDetector.h" #include "engines/engine.h" #include "graphics/surface.h" From cd888fec432e9d92bfbacfaa6117c3ea68894745 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Mon, 9 Jan 2023 00:41:07 +0100 Subject: [PATCH 226/412] EFH: Fix bug in tryToggleEquipped() --- engines/efh/menu.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/engines/efh/menu.cpp b/engines/efh/menu.cpp index c052aeb2a8b6..df459bc0e59b 100644 --- a/engines/efh/menu.cpp +++ b/engines/efh/menu.cpp @@ -893,12 +893,13 @@ void EfhEngine::tryToggleEquipped(int16 charId, int16 objectId, int16 windowId, int16 curType = _items[itemId]._exclusiveType; if (curType != 4) { for (uint counter = 0; counter < 10; ++counter) { - if (_npcBuf[charId]._inventory[counter]._ref == 0x7FFF) { + int16 curItemId = _npcBuf[charId]._inventory[counter]._ref; + if (curItemId == 0x7FFF) { warning("CHECKME : hack"); continue; } - if (curType == _items[_npcBuf[charId]._inventory[counter]._ref]._exclusiveType) - unequipItem(charId, objectId, windowId, menuId, curMenuLine); + if (curType == _items[curItemId]._exclusiveType) + unequipItem(charId, counter, windowId, menuId, curMenuLine); } } From a976d28c1d3280e8fdcc910f7a75f587b33306cb Mon Sep 17 00:00:00 2001 From: Strangerke Date: Mon, 9 Jan 2023 01:34:20 +0100 Subject: [PATCH 227/412] EFH: Fix a bug in unequipItem(), fix a bug in displayString_3() --- engines/efh/efh.h | 2 +- engines/efh/menu.cpp | 13 ++++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 14d7df47ea17..990da18be065 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -466,7 +466,7 @@ class EfhEngine : public Engine { void displayStatusMenuActions(int16 menuId, int16 curMenuLine, int16 npcId); void prepareStatusMenu(int16 windowId, int16 menuId, int16 curMenuLine, int16 charId, bool refreshFl); void displayWindowAndStatusMenu(int16 charId, int16 windowId, int16 menuId, int16 curMenuLine); - int16 displayString_3(Common::String str, bool animFl, int16 charId, int16 windowId, int16 menuId, int16 curMenuLine); + int16 displayString_3(Common::String str, bool delayFl, int16 charId, int16 windowId, int16 menuId, int16 curMenuLine); int16 handleStatusMenu(int16 gameMode, int16 charId); void unequipItem(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine); void tryToggleEquipped(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine); diff --git a/engines/efh/menu.cpp b/engines/efh/menu.cpp index df459bc0e59b..68b2f9ac8d71 100644 --- a/engines/efh/menu.cpp +++ b/engines/efh/menu.cpp @@ -485,8 +485,8 @@ void EfhEngine::displayWindowAndStatusMenu(int16 charId, int16 windowId, int16 m } } -int16 EfhEngine::displayString_3(Common::String str, bool animFl, int16 charId, int16 windowId, int16 menuId, int16 curMenuLine) { - debug("displayString_3 %s %s %d %d %d %d", str.c_str(), animFl ? "True" : "False", charId, windowId, menuId, curMenuLine); +int16 EfhEngine::displayString_3(Common::String str, bool delayFl, int16 charId, int16 windowId, int16 menuId, int16 curMenuLine) { + debug("displayString_3 %s %s %d %d %d %d", str.c_str(), delayFl ? "True" : "False", charId, windowId, menuId, curMenuLine); int16 retVal = 0; @@ -496,13 +496,16 @@ int16 EfhEngine::displayString_3(Common::String str, bool animFl, int16 charId, if (counter == 0) { script_parse(str, 28, 122, 105, 166, false); - displayFctFullScreen(); } else { retVal = script_parse(str, 28, 122, 105, 166, true); } + // The original is only calling displayFctFullScreen when counter = 0, but it's related to the screen buffers which aren't used in ScummVM implementation + // Calling it once fix the almost unreadable text displayed otherwise. + // Maybe a refactoring to remove those 0..1 loop would be useful at some point. + displayFctFullScreen(); } - if (animFl) { + if (delayFl) { getLastCharAfterAnimCount(_guessAnimationAmount); displayWindowAndStatusMenu(charId, windowId, menuId, curMenuLine); } @@ -874,7 +877,7 @@ void EfhEngine::unequipItem(int16 charId, int16 objectId, int16 windowId, int16 int16 itemId = _npcBuf[charId]._inventory[objectId]._ref; - if (isItemCursed(itemId)) { + if (!isItemCursed(itemId)) { _npcBuf[charId]._inventory[objectId]._stat1 &= 0x7F; } else { // Original message. "Cursed item can't be unequipped" would make more sense, imho From d7730488695a8de46b4a9d7dc4d28321cf8af320 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Mon, 9 Jan 2023 01:58:23 +0100 Subject: [PATCH 228/412] EFH: Fix several issues in handleStatusMenu() / Trade --- engines/efh/menu.cpp | 87 +++++++++++++++++++++++--------------------- 1 file changed, 45 insertions(+), 42 deletions(-) diff --git a/engines/efh/menu.cpp b/engines/efh/menu.cpp index 68b2f9ac8d71..b699ec9f4549 100644 --- a/engines/efh/menu.cpp +++ b/engines/efh/menu.cpp @@ -733,58 +733,61 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { itemId = _npcBuf[charId]._inventory[objectId]._ref; if (hasObjectEquipped(charId, objectId) && isItemCursed(itemId)) { displayString_3("The item is cursed! IT IS EVIL!!!!!!!!", true, charId, windowId, menuId, curMenuLine); - } else if (hasObjectEquipped(charId, objectId)) { + break; + } + + if (hasObjectEquipped(charId, objectId)) { displayString_3("Item is Equipped! Trade anyway?", false, charId, windowId, menuId, curMenuLine); if (!getValidationFromUser()) validationFl = false; displayWindowAndStatusMenu(charId, windowId, menuId, curMenuLine); + } + + if (validationFl) { + bool givenFl; + int16 destCharId; + do { + if (_teamCharId[2] != -1) { + displayString_3("Who will you give the item to?", false, charId, windowId, menuId, curMenuLine); + destCharId = selectOtherCharFromTeam(); + var2 = false; + } else if (_teamCharId[1] == -1) { + destCharId = 0x1A; + var2 = false; + } else { + var2 = true; + if (_teamCharId[0] == charId) + destCharId = 1; + else + destCharId = 0; + } - if (validationFl) { - bool givenFl; - int16 destCharId; - do { - if (_teamCharId[2] != -1) { - displayString_3("Who will you give the item to?", false, charId, windowId, menuId, curMenuLine); - destCharId = selectOtherCharFromTeam(); - var2 = false; - } else if (_teamCharId[1]) { - destCharId = 0x1A; - var2 = false; - } else { - var2 = true; - if (_teamCharId[0] == charId) - destCharId = 1; - else - destCharId = 0; - } - - if (destCharId != 0x1A && destCharId != 0x1B) { - givenFl = giveItemTo(_teamCharId[destCharId], objectId, charId); - if (!givenFl) { - displayString_3("That character cannot carry anymore!", false, charId, windowId, menuId, curMenuLine); - getLastCharAfterAnimCount(_guessAnimationAmount); - } - } else { - if (destCharId == 0x1A) { - displayString_3("No one to trade with!", false, charId, windowId, menuId, curMenuLine); - getLastCharAfterAnimCount(_guessAnimationAmount); - destCharId = 0x1B; - } - givenFl = false; + if (destCharId != 0x1A && destCharId != 0x1B) { + givenFl = giveItemTo(_teamCharId[destCharId], objectId, charId); + if (!givenFl) { + displayString_3("That character cannot carry anymore!", false, charId, windowId, menuId, curMenuLine); + getLastCharAfterAnimCount(_guessAnimationAmount); } - } while (!givenFl && !var2 && destCharId != 0x1B); - - if (givenFl) { - removeObject(charId, objectId); - if (gameMode == 2) { - restoreAnimImageSetId(); - _statusMenuActive = false; - return 0x7D00; + } else { + if (destCharId == 0x1A) { + displayString_3("No one to trade with!", false, charId, windowId, menuId, curMenuLine); + getLastCharAfterAnimCount(_guessAnimationAmount); + destCharId = 0x1B; } + givenFl = false; } + } while (!givenFl && !var2 && destCharId != 0x1B); - displayWindowAndStatusMenu(charId, windowId, menuId, curMenuLine); + if (givenFl) { + removeObject(charId, objectId); + if (gameMode == 2) { + restoreAnimImageSetId(); + _statusMenuActive = false; + return 0x7D00; + } } + + displayWindowAndStatusMenu(charId, windowId, menuId, curMenuLine); } break; case 4: From 5bc5534ca343164e13a86bd4324032474cc871c5 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Mon, 9 Jan 2023 08:56:08 +0100 Subject: [PATCH 229/412] EFH: Make menu code slightly more readable by using an enum --- engines/efh/constants.h | 13 ++++++ engines/efh/menu.cpp | 98 +++++++++++++++++++++-------------------- 2 files changed, 63 insertions(+), 48 deletions(-) diff --git a/engines/efh/constants.h b/engines/efh/constants.h index c08ade3e6901..46b3e2ed6dbf 100644 --- a/engines/efh/constants.h +++ b/engines/efh/constants.h @@ -25,6 +25,19 @@ #include "common/scummsys.h" namespace Efh { +enum EfhMenuItems { + kEfhMenuEquip = 0, + kEfhMenuUse = 1, + kEfhMenuGive = 2, + kEfhMenuTrade = 3, + kEfhMenuDrop = 4, + kEfhMenuInfo = 5, + kEfhMenuPassive = 6, + kEfhMenuActive = 7, + kEfhMenuLeave = 8, + kEfhMenuInvalid = 9 +}; + struct Font { uint8 _lines[8]; }; diff --git a/engines/efh/menu.cpp b/engines/efh/menu.cpp index b699ec9f4549..56c487fdc39f 100644 --- a/engines/efh/menu.cpp +++ b/engines/efh/menu.cpp @@ -241,15 +241,15 @@ void EfhEngine::prepareStatusRightWindowIndexes(int16 menuId, int16 charId) { _menuItemCounter = 0; switch (menuId) { - case 5: + case kEfhMenuInfo: minId = 26; maxId = 36; break; - case 6: + case kEfhMenuPassive: minId = 15; maxId = 25; break; - case 7: + case kEfhMenuActive: minId = 0; maxId = 14; break; @@ -419,40 +419,40 @@ void EfhEngine::displayStatusMenuActions(int16 menuId, int16 curMenuLine, int16 displayCenteredString("(ESCape Aborts)", 144, 310, 175); _textColor = 0x0E; switch (menuId) { - case 0: + case kEfhMenuEquip: displayCenteredString("Select Item to Equip", 144, 310, 15); displayCharacterSummary(curMenuLine, npcId); break; - case 1: + case kEfhMenuUse: displayCenteredString("Select Item to Use", 144, 310, 15); displayCharacterSummary(curMenuLine, npcId); break; - case 2: + case kEfhMenuGive: displayCenteredString("Select Item to Give", 144, 310, 15); displayCharacterSummary(curMenuLine, npcId); break; - case 3: + case kEfhMenuTrade: displayCenteredString("Select Item to Trade", 144, 310, 15); displayCharacterSummary(curMenuLine, npcId); break; - case 4: + case kEfhMenuDrop: displayCenteredString("Select Item to Drop", 144, 310, 15); displayCharacterSummary(curMenuLine, npcId); break; - case 5: + case kEfhMenuInfo: displayCenteredString("Character Information", 144, 310, 15); displayCharacterInformationOrSkills(curMenuLine, npcId); break; - case 6: + case kEfhMenuPassive: displayCenteredString("Passive Skills", 144, 310, 15); displayCharacterInformationOrSkills(curMenuLine, npcId); break; - case 7: + case kEfhMenuActive: displayCenteredString("Active Skills", 144, 310, 15); displayCharacterInformationOrSkills(curMenuLine, npcId); break; - case 8: - case 9: + case kEfhMenuLeave: + case kEfhMenuInvalid: displayCenteredString("Character Summary", 144, 310, 15); displayCharacterSummary(curMenuLine, npcId); break; @@ -516,11 +516,11 @@ int16 EfhEngine::displayString_3(Common::String str, bool delayFl, int16 charId, int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { debug("handleStatusMenu %d %d", gameMode, charId); - int16 menuId = 9; + int16 menuId = kEfhMenuInvalid; int16 selectedLine = -1; int16 windowId = -1; int16 curMenuLine = -1; - bool var10 = false; + bool selectionDoneFl = false; bool var2 = false; saveAnimImageSetId(); @@ -534,50 +534,50 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { if (windowId != -1) prepareStatusMenu(windowId, menuId, curMenuLine, charId, true); else - windowId = 0; + windowId = kEfhMenuEquip; do { Common::KeyCode var19 = handleAndMapInput(false); if (_menuDepth == 0) { switch (var19) { case Common::KEYCODE_ESCAPE: - windowId = 8; + windowId = kEfhMenuLeave; var19 = Common::KEYCODE_RETURN; break; case Common::KEYCODE_a: - windowId = 7; + windowId = kEfhMenuActive; var19 = Common::KEYCODE_RETURN; break; case Common::KEYCODE_d: - windowId = 4; + windowId = kEfhMenuDrop; var19 = Common::KEYCODE_RETURN; break; case Common::KEYCODE_e: - windowId = 0; + windowId = kEfhMenuEquip; var19 = Common::KEYCODE_RETURN; break; case Common::KEYCODE_g: - windowId = 2; + windowId = kEfhMenuGive; var19 = Common::KEYCODE_RETURN; break; case Common::KEYCODE_i: - windowId = 5; + windowId = kEfhMenuInfo; var19 = Common::KEYCODE_RETURN; break; case Common::KEYCODE_l: - windowId = 8; + windowId = kEfhMenuLeave; var19 = Common::KEYCODE_RETURN; break; case Common::KEYCODE_p: - windowId = 6; + windowId = kEfhMenuPassive; var19 = Common::KEYCODE_RETURN; break; case Common::KEYCODE_t: - windowId = 3; + windowId = kEfhMenuTrade; var19 = Common::KEYCODE_RETURN; break; case Common::KEYCODE_u: - windowId = 1; + windowId = kEfhMenuUse; var19 = Common::KEYCODE_RETURN; break; // case 0xFB: Joystick button 2 @@ -601,8 +601,8 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { // case 0xFA: Joystick button 1 if (_menuDepth == 0) { menuId = windowId; - if (menuId > 7) - var10 = true; + if (menuId >= kEfhMenuLeave) + selectionDoneFl = true; else { _menuDepth = 1; curMenuLine = 0; @@ -611,18 +611,18 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { if (_menuItemCounter == 0) { _menuDepth = 0; curMenuLine = -1; - menuId = 9; + menuId = kEfhMenuInvalid; prepareStatusMenu(windowId, menuId, curMenuLine, charId, true); } else { selectedLine = curMenuLine; - var10 = true; + selectionDoneFl = true; } } break; case Common::KEYCODE_ESCAPE: _menuDepth = 0; curMenuLine = -1; - menuId = 9; + menuId = kEfhMenuInvalid; prepareStatusMenu(windowId, menuId, curMenuLine, charId, true); break; case Common::KEYCODE_2: @@ -634,8 +634,8 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { case Common::KEYCODE_KP6: // Original checks joystick axis: case 0xCC, 0xCF if (_menuDepth == 0) { - if (++windowId > 8) - windowId = 0; + if (++windowId > kEfhMenuLeave) + windowId = kEfhMenuEquip; } else if (_menuDepth == 1) { if (_menuItemCounter != 0) { ++curMenuLine; @@ -653,8 +653,8 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { case Common::KEYCODE_KP8: // Original checks joystick axis: case 0xC7, 0xCA if (_menuDepth == 0) { - if (--windowId < 0) - windowId = 8; + if (--windowId < kEfhMenuEquip) + windowId = kEfhMenuLeave; } else if (_menuDepth == 1) { if (_menuItemCounter != 0) { --curMenuLine; @@ -669,14 +669,14 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { prepareStatusMenu(windowId, menuId, curMenuLine, charId, true); - } while (!var10); + } while (!selectionDoneFl); // Loop until a menu entry is confirmed by the user by pressing the enter key bool validationFl = true; int16 objectId; int16 itemId; switch (menuId) { - case 0: + case kEfhMenuEquip: objectId = _menuStatItemArr[selectedLine]; itemId = _npcBuf[charId]._inventory[objectId]._ref; // CHECKME: Useless? tryToggleEquipped(charId, objectId, windowId, menuId, curMenuLine); @@ -686,7 +686,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { return 0x7D00; } break; - case 1: + case kEfhMenuUse: objectId = _menuStatItemArr[selectedLine]; itemId = _npcBuf[charId]._inventory[objectId]._ref; if (gameMode == 2) { @@ -702,7 +702,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { useObject(charId, objectId, windowId, menuId, curMenuLine, 2); break; - case 2: + case kEfhMenuGive: objectId = _menuStatItemArr[selectedLine]; itemId = _npcBuf[charId]._inventory[objectId]._ref; if (hasObjectEquipped(charId, objectId) && isItemCursed(itemId)) { @@ -728,7 +728,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { } break; - case 3: + case kEfhMenuTrade: objectId = _menuStatItemArr[selectedLine]; itemId = _npcBuf[charId]._inventory[objectId]._ref; if (hasObjectEquipped(charId, objectId) && isItemCursed(itemId)) { @@ -790,7 +790,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { displayWindowAndStatusMenu(charId, windowId, menuId, curMenuLine); } break; - case 4: + case kEfhMenuDrop: objectId = _menuStatItemArr[selectedLine]; itemId = _npcBuf[charId]._inventory[objectId]._ref; if (hasObjectEquipped(charId, objectId) && isItemCursed(itemId)) { @@ -817,7 +817,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { } } break; - case 5: + case kEfhMenuInfo: objectId = _menuStatItemArr[selectedLine]; if (gameMode == 2) { displayString_3("Not a Combat Option!", true, charId, windowId, menuId, curMenuLine); @@ -829,7 +829,8 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { } } break; - case 6: // Identical to case 5? + case kEfhMenuPassive: + // Identical to case 5? objectId = _menuStatItemArr[selectedLine]; if (gameMode == 2) { displayString_3("Not a Combat Option!", true, charId, windowId, menuId, curMenuLine); @@ -841,7 +842,8 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { } } break; - case 7: // Identical to case 5? + case kEfhMenuActive: + // Identical to case 5? objectId = _menuStatItemArr[selectedLine]; if (gameMode == 2) { displayString_3("Not a Combat Option!", true, charId, windowId, menuId, curMenuLine); @@ -857,15 +859,15 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { break; } - if (menuId != 8) { - var10 = false; + if (menuId != kEfhMenuLeave) { + selectionDoneFl = false; _menuDepth = 0; - menuId = 9; + menuId = kEfhMenuInvalid; selectedLine = -1; curMenuLine = -1; } - if (menuId == 8) { + if (menuId == kEfhMenuLeave) { restoreAnimImageSetId(); _statusMenuActive = false; return 0x7FFF; From 751f2859ea6196052730ae6a604db9d607a64936 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Mon, 9 Jan 2023 09:11:16 +0100 Subject: [PATCH 230/412] EFH: Fix a bug in giveItemTo() --- engines/efh/efh.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 7e277b2b919b..be8cdee3fde1 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -996,9 +996,9 @@ bool EfhEngine::giveItemTo(int16 charId, int16 objectId, int16 fromCharId) { _npcBuf[charId]._inventory[newObjectId]._curHitPoints = _items[objectId]._defense; _npcBuf[charId]._inventory[newObjectId]._stat1 = _items[objectId]._uses; } else { - _npcBuf[charId]._inventory[newObjectId]._ref = _npcBuf[fromCharId]._inventory[newObjectId]._ref; - _npcBuf[charId]._inventory[newObjectId]._curHitPoints = _npcBuf[fromCharId]._inventory[newObjectId]._curHitPoints; - _npcBuf[charId]._inventory[newObjectId]._stat1 = _npcBuf[fromCharId]._inventory[newObjectId].getUsesLeft(); // not equipped as the upper bit isn't set (0x80) + _npcBuf[charId]._inventory[newObjectId]._ref = _npcBuf[fromCharId]._inventory[objectId]._ref; + _npcBuf[charId]._inventory[newObjectId]._curHitPoints = _npcBuf[fromCharId]._inventory[objectId]._curHitPoints; + _npcBuf[charId]._inventory[newObjectId]._stat1 = _npcBuf[fromCharId]._inventory[objectId].getUsesLeft(); // not equipped as the upper bit isn't set (0x80) } return true; From dad84346eb4341d8f85535f813851db6d9f1b089 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Tue, 10 Jan 2023 00:13:17 +0100 Subject: [PATCH 231/412] EFH: Validate handleStatusMenu, remove duplicate code --- engines/efh/menu.cpp | 41 ++++++----------------------------------- 1 file changed, 6 insertions(+), 35 deletions(-) diff --git a/engines/efh/menu.cpp b/engines/efh/menu.cpp index 56c487fdc39f..4290a021fee9 100644 --- a/engines/efh/menu.cpp +++ b/engines/efh/menu.cpp @@ -514,7 +514,7 @@ int16 EfhEngine::displayString_3(Common::String str, bool delayFl, int16 charId, } int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { - debug("handleStatusMenu %d %d", gameMode, charId); + debugC(3, kDebugEngine, "handleStatusMenu %d %d", gameMode, charId); int16 menuId = kEfhMenuInvalid; int16 selectedLine = -1; @@ -718,8 +718,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { displayString_3("Not a Combat Option !", true, charId, windowId, menuId, curMenuLine); } else { removeObject(charId, objectId); - int16 var8 = sub22293(_mapPosX, _mapPosY, charId, itemId, 3, -1); - if (var8 != 0) { + if (sub22293(_mapPosX, _mapPosY, charId, itemId, 3, -1)) { _statusMenuActive = false; return -1; } @@ -809,8 +808,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { return 0x7D00; } - bool var8 = sub22293(_mapPosX, _mapPosY, charId, itemId, 1, -1); - if (var8) { + if (sub22293(_mapPosX, _mapPosY, charId, itemId, 1, -1)) { _statusMenuActive = false; return -1; } @@ -818,41 +816,14 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { } break; case kEfhMenuInfo: - objectId = _menuStatItemArr[selectedLine]; - if (gameMode == 2) { - displayString_3("Not a Combat Option!", true, charId, windowId, menuId, curMenuLine); - } else { - bool var8 = sub22293(_mapPosX, _mapPosY, charId, objectId, 4, -1); - if (var8) { - _statusMenuActive = false; - return -1; - } - } - break; case kEfhMenuPassive: - // Identical to case 5? - objectId = _menuStatItemArr[selectedLine]; - if (gameMode == 2) { - displayString_3("Not a Combat Option!", true, charId, windowId, menuId, curMenuLine); - } else { - bool var8 = sub22293(_mapPosX, _mapPosY, charId, objectId, 4, -1); - if (var8) { - _statusMenuActive = false; - return -1; - } - } - break; case kEfhMenuActive: - // Identical to case 5? objectId = _menuStatItemArr[selectedLine]; if (gameMode == 2) { displayString_3("Not a Combat Option!", true, charId, windowId, menuId, curMenuLine); - } else { - bool var8 = sub22293(_mapPosX, _mapPosY, charId, objectId, 4, -1); - if (var8) { - _statusMenuActive = false; - return -1; - } + } else if (sub22293(_mapPosX, _mapPosY, charId, objectId, 4, -1)) { + _statusMenuActive = false; + return -1; } break; default: From f5246243828e4aa49af1639667a6eca4d73b2a58 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Tue, 10 Jan 2023 00:21:17 +0100 Subject: [PATCH 232/412] EFH: Rename displayString_3 to displayStringInSmallWindowWithBorder --- engines/efh/efh.h | 2 +- engines/efh/menu.cpp | 92 ++++++++++++++++++++++---------------------- 2 files changed, 47 insertions(+), 47 deletions(-) diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 990da18be065..0466bcfaec0d 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -466,7 +466,7 @@ class EfhEngine : public Engine { void displayStatusMenuActions(int16 menuId, int16 curMenuLine, int16 npcId); void prepareStatusMenu(int16 windowId, int16 menuId, int16 curMenuLine, int16 charId, bool refreshFl); void displayWindowAndStatusMenu(int16 charId, int16 windowId, int16 menuId, int16 curMenuLine); - int16 displayString_3(Common::String str, bool delayFl, int16 charId, int16 windowId, int16 menuId, int16 curMenuLine); + int16 displayStringInSmallWindowWithBorder(Common::String str, bool delayFl, int16 charId, int16 windowId, int16 menuId, int16 curMenuLine); int16 handleStatusMenu(int16 gameMode, int16 charId); void unequipItem(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine); void tryToggleEquipped(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine); diff --git a/engines/efh/menu.cpp b/engines/efh/menu.cpp index 4290a021fee9..d25ae4f16d3a 100644 --- a/engines/efh/menu.cpp +++ b/engines/efh/menu.cpp @@ -485,8 +485,8 @@ void EfhEngine::displayWindowAndStatusMenu(int16 charId, int16 windowId, int16 m } } -int16 EfhEngine::displayString_3(Common::String str, bool delayFl, int16 charId, int16 windowId, int16 menuId, int16 curMenuLine) { - debug("displayString_3 %s %s %d %d %d %d", str.c_str(), delayFl ? "True" : "False", charId, windowId, menuId, curMenuLine); +int16 EfhEngine::displayStringInSmallWindowWithBorder(Common::String str, bool delayFl, int16 charId, int16 windowId, int16 menuId, int16 curMenuLine) { + debug("displayStringInSmallWindowWithBorder %s %s %d %d %d %d", str.c_str(), delayFl ? "True" : "False", charId, windowId, menuId, curMenuLine); int16 retVal = 0; @@ -706,16 +706,16 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { objectId = _menuStatItemArr[selectedLine]; itemId = _npcBuf[charId]._inventory[objectId]._ref; if (hasObjectEquipped(charId, objectId) && isItemCursed(itemId)) { - displayString_3("The item is cursed! IT IS EVIL!!!!!!!!", true, charId, windowId, menuId, curMenuLine); + displayStringInSmallWindowWithBorder("The item is cursed! IT IS EVIL!!!!!!!!", true, charId, windowId, menuId, curMenuLine); } else if (hasObjectEquipped(charId, objectId)) { - displayString_3("Item is Equipped! Give anyway?", false, charId, windowId, menuId, curMenuLine); + displayStringInSmallWindowWithBorder("Item is Equipped! Give anyway?", false, charId, windowId, menuId, curMenuLine); if (!getValidationFromUser()) validationFl = false; displayWindowAndStatusMenu(charId, windowId, menuId, curMenuLine); if (validationFl) { if (gameMode == 2) { - displayString_3("Not a Combat Option !", true, charId, windowId, menuId, curMenuLine); + displayStringInSmallWindowWithBorder("Not a Combat Option !", true, charId, windowId, menuId, curMenuLine); } else { removeObject(charId, objectId); if (sub22293(_mapPosX, _mapPosY, charId, itemId, 3, -1)) { @@ -731,12 +731,12 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { objectId = _menuStatItemArr[selectedLine]; itemId = _npcBuf[charId]._inventory[objectId]._ref; if (hasObjectEquipped(charId, objectId) && isItemCursed(itemId)) { - displayString_3("The item is cursed! IT IS EVIL!!!!!!!!", true, charId, windowId, menuId, curMenuLine); + displayStringInSmallWindowWithBorder("The item is cursed! IT IS EVIL!!!!!!!!", true, charId, windowId, menuId, curMenuLine); break; } if (hasObjectEquipped(charId, objectId)) { - displayString_3("Item is Equipped! Trade anyway?", false, charId, windowId, menuId, curMenuLine); + displayStringInSmallWindowWithBorder("Item is Equipped! Trade anyway?", false, charId, windowId, menuId, curMenuLine); if (!getValidationFromUser()) validationFl = false; displayWindowAndStatusMenu(charId, windowId, menuId, curMenuLine); @@ -747,7 +747,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { int16 destCharId; do { if (_teamCharId[2] != -1) { - displayString_3("Who will you give the item to?", false, charId, windowId, menuId, curMenuLine); + displayStringInSmallWindowWithBorder("Who will you give the item to?", false, charId, windowId, menuId, curMenuLine); destCharId = selectOtherCharFromTeam(); var2 = false; } else if (_teamCharId[1] == -1) { @@ -764,12 +764,12 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { if (destCharId != 0x1A && destCharId != 0x1B) { givenFl = giveItemTo(_teamCharId[destCharId], objectId, charId); if (!givenFl) { - displayString_3("That character cannot carry anymore!", false, charId, windowId, menuId, curMenuLine); + displayStringInSmallWindowWithBorder("That character cannot carry anymore!", false, charId, windowId, menuId, curMenuLine); getLastCharAfterAnimCount(_guessAnimationAmount); } } else { if (destCharId == 0x1A) { - displayString_3("No one to trade with!", false, charId, windowId, menuId, curMenuLine); + displayStringInSmallWindowWithBorder("No one to trade with!", false, charId, windowId, menuId, curMenuLine); getLastCharAfterAnimCount(_guessAnimationAmount); destCharId = 0x1B; } @@ -793,9 +793,9 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { objectId = _menuStatItemArr[selectedLine]; itemId = _npcBuf[charId]._inventory[objectId]._ref; if (hasObjectEquipped(charId, objectId) && isItemCursed(itemId)) { - displayString_3("The item is cursed! IT IS EVIL!!!!!!!!", true, charId, windowId, menuId, curMenuLine); + displayStringInSmallWindowWithBorder("The item is cursed! IT IS EVIL!!!!!!!!", true, charId, windowId, menuId, curMenuLine); } else if (hasObjectEquipped(charId, objectId)) { - displayString_3("Item Is Equipped! Drop Anyway?", false, charId, windowId, menuId, curMenuLine); + displayStringInSmallWindowWithBorder("Item Is Equipped! Drop Anyway?", false, charId, windowId, menuId, curMenuLine); if (!getValidationFromUser()) validationFl = false; displayWindowAndStatusMenu(charId, windowId, menuId, curMenuLine); @@ -820,7 +820,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { case kEfhMenuActive: objectId = _menuStatItemArr[selectedLine]; if (gameMode == 2) { - displayString_3("Not a Combat Option!", true, charId, windowId, menuId, curMenuLine); + displayStringInSmallWindowWithBorder("Not a Combat Option!", true, charId, windowId, menuId, curMenuLine); } else if (sub22293(_mapPosX, _mapPosY, charId, objectId, 4, -1)) { _statusMenuActive = false; return -1; @@ -857,7 +857,7 @@ void EfhEngine::unequipItem(int16 charId, int16 objectId, int16 windowId, int16 _npcBuf[charId]._inventory[objectId]._stat1 &= 0x7F; } else { // Original message. "Cursed item can't be unequipped" would make more sense, imho - displayString_3("Cursed Item Already Equipped!", true, charId, windowId, menuId, curMenuLine); + displayStringInSmallWindowWithBorder("Cursed Item Already Equipped!", true, charId, windowId, menuId, curMenuLine); } } @@ -901,7 +901,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in switch (_items[itemId]._specialEffect - 1) { case 0: // "Demonic Powers", "MindDomination", "Guilt Trip", "Sleep Grenade", "SleepGrenader" if (argA == 2) { - displayString_3("The item emits a low droning hum...", false, charId, teamMonsterId, menuId, curMenuLine); + displayStringInSmallWindowWithBorder("The item emits a low droning hum...", false, charId, teamMonsterId, menuId, curMenuLine); } else { int16 victims = 0; _messageToBePrinted += " The item emits a low droning hum..."; @@ -940,7 +940,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in break; case 1: // "Chilling Touch", "Guilt", "Petrify Rod", "Elmer's Gun" if (argA == 2) { - displayString_3("The item grows very cold for a moment...", false, charId, teamMonsterId, menuId, curMenuLine); + displayStringInSmallWindowWithBorder("The item grows very cold for a moment...", false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += " The item emits a blue beam..."; int16 victim = 0; @@ -981,7 +981,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in break; case 2: if (argA == 2) { - displayString_3("A serene feeling passes through the air...", false, charId, teamMonsterId, menuId, curMenuLine); + displayStringInSmallWindowWithBorder("A serene feeling passes through the air...", false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += " The combat pauses...as there is a moment of forgiveness..."; _unk2C8AA = 0; @@ -991,7 +991,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in break; case 4: // "Unholy Sinwave", "Holy Water" if (argA == 2) { - displayString_3("A dark sense fills your soul...then fades!", false, charId, teamMonsterId, menuId, curMenuLine); + displayStringInSmallWindowWithBorder("A dark sense fills your soul...then fades!", false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += " A dark gray fiery whirlwind surrounds the poor victim...the power fades and death abounds!"; if (getRandom(100) < 50) { @@ -1015,7 +1015,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in break; case 5: // "Lucifer'sTouch", "Book of Death", "Holy Cross" if (argA == 2) { - displayString_3("A dark sense fills your soul...then fades!", false, charId, teamMonsterId, menuId, curMenuLine); + displayStringInSmallWindowWithBorder("A dark sense fills your soul...then fades!", false, charId, teamMonsterId, menuId, curMenuLine); } else { if (getRandom(100) < 50) { _messageToBePrinted += " A dark fiery whirlwind surrounds the poor victim...the power fades and all targeted die!"; @@ -1036,7 +1036,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in break; case 12: // "Terror Gaze", "Servitude Rod", "Despair Ankh", "ConfusionPrism", "Pipe of Peace", "Red Cape", "Peace Symbol", "Hell Badge" if (argA == 2) { - displayString_3("There is no apparent affect!", false, charId, teamMonsterId, menuId, curMenuLine); + displayStringInSmallWindowWithBorder("There is no apparent affect!", false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += " The magic sparkles brilliant hues in the air!"; setMapMonsterAggressivenessAndMovementType(teamMonsterId, _items[itemId]._field17_attackTypeDefense, true); @@ -1046,7 +1046,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in case 14: { // "Feathered Cap" int16 varAA; if (argA == 2) { - displayString_3("Who will use the item?", false, charId, teamMonsterId, menuId, curMenuLine); + displayStringInSmallWindowWithBorder("Who will use the item?", false, charId, teamMonsterId, menuId, curMenuLine); varAA = selectOtherCharFromTeam(); } else { varAA = teamMonsterId; @@ -1055,7 +1055,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in if (varAA != 0x1B) { buffer1 = " The magic makes the user as quick and agile as a bird!"; if (argA == 2) { - displayString_3(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); + displayStringInSmallWindowWithBorder(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; } @@ -1069,7 +1069,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in case 15: { // "Regal Crown" int16 teamCharId; if (argA == 2) { - displayString_3("Who will use the item?", false, charId, teamMonsterId, menuId, curMenuLine); + displayStringInSmallWindowWithBorder("Who will use the item?", false, charId, teamMonsterId, menuId, curMenuLine); teamCharId = selectOtherCharFromTeam(); } else { teamCharId = teamMonsterId; @@ -1078,7 +1078,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in if (teamCharId != 0x1B) { buffer1 = " The magic makes the user invisible!"; if (argA == 2) { - displayString_3(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); + displayStringInSmallWindowWithBorder(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; } @@ -1099,7 +1099,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in totalPartyKill(); buffer1 = "The entire party vanishes in a flash... only to appear in stone !"; if (argA == 2) { - displayString_3(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); + displayStringInSmallWindowWithBorder(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; retVal = true; @@ -1108,7 +1108,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in if (tileFactId == 0 || tileFactId == 0x48) { buffer1 = "The entire party vanishes in a flash...but re-appears, as if nothing happened!"; if (argA == 2) { - displayString_3(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); + displayStringInSmallWindowWithBorder(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; retVal = true; @@ -1116,7 +1116,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in } else { buffer1 = "The entire party vanishes in a flash...only to appear elsewhere!"; if (argA == 2) { - displayString_3(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); + displayStringInSmallWindowWithBorder(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; retVal = true; @@ -1134,7 +1134,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in totalPartyKill(); buffer1 = "The entire party vanishes in a flash... only to appear in stone !"; if (argA == 2) { - displayString_3(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); + displayStringInSmallWindowWithBorder(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; retVal = true; @@ -1143,7 +1143,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in if (tileFactId == 0 || tileFactId == 0x48) { buffer1 = "The entire party vanishes in a flash...but re-appears, as if nothing happened!"; if (argA == 2) { - displayString_3(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); + displayStringInSmallWindowWithBorder(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; retVal = true; @@ -1151,7 +1151,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in } else { buffer1 = "The entire party vanishes in a flash...only to appear elsewhere!"; if (argA == 2) { - displayString_3(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); + displayStringInSmallWindowWithBorder(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; retVal = true; @@ -1163,7 +1163,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in } break; case 18: if (argA == 2) { - displayString_3("The item makes a loud noise!", false, charId, teamMonsterId, menuId, curMenuLine); + displayStringInSmallWindowWithBorder("The item makes a loud noise!", false, charId, teamMonsterId, menuId, curMenuLine); } else { int16 teamCharId = teamMonsterId; if (teamCharId != 0x1B) { @@ -1182,7 +1182,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in case 19: // "Junk" buffer1 = " * The item breaks!"; if (argA == 2) { - displayString_3(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); + displayStringInSmallWindowWithBorder(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; } @@ -1218,7 +1218,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in } buffer1 += "'"; if (argA == 2) { - displayString_3(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); + displayStringInSmallWindowWithBorder(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; retVal = true; @@ -1229,7 +1229,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in case 24: { int16 teamCharId; if (argA == 2) { - displayString_3("Who will use this item?", false, charId, teamMonsterId, menuId, curMenuLine); + displayStringInSmallWindowWithBorder("Who will use this item?", false, charId, teamMonsterId, menuId, curMenuLine); teamCharId = selectOtherCharFromTeam(); } else teamCharId = teamMonsterId; @@ -1247,7 +1247,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in buffer1 = Common::String::format("%s increased 1 point!", kSkillArray[varAE]); if (argA == 2) { - displayString_3(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); + displayStringInSmallWindowWithBorder(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; retVal = true; @@ -1259,7 +1259,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in case 25: { int16 teamCharId; if (argA == 2) { - displayString_3("Who will use this item?", false, charId, teamMonsterId, menuId, curMenuLine); + displayStringInSmallWindowWithBorder("Who will use this item?", false, charId, teamMonsterId, menuId, curMenuLine); teamCharId = selectOtherCharFromTeam(); } else teamCharId = teamMonsterId; @@ -1277,7 +1277,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in buffer1 = Common::String::format("%s lowered 1 point!", kSkillArray[varAE]); if (argA == 2) { - displayString_3(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); + displayStringInSmallWindowWithBorder(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; retVal = true; @@ -1289,7 +1289,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in case 26: // "Black Sphere" buffer1 = "The entire party collapses, dead!!!"; if (argA == 2) { - displayString_3(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); + displayStringInSmallWindowWithBorder(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; retVal = true; @@ -1300,7 +1300,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in case 27: { // "Magic Pyramid", "Razor Blade" int16 teamCharId; if (argA == 2) { - displayString_3("Who will use the item?", false, charId, teamMonsterId, menuId, curMenuLine); + displayStringInSmallWindowWithBorder("Who will use the item?", false, charId, teamMonsterId, menuId, curMenuLine); teamCharId = selectOtherCharFromTeam(); } else { teamCharId = teamMonsterId; @@ -1310,7 +1310,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in _npcBuf[_teamCharId[teamCharId]]._hitPoints = 0; buffer1 = Common::String::format("%s collapses, dead!!!", _npcBuf[_teamCharId[teamCharId]]._name); if (argA == 2) { - displayString_3(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); + displayStringInSmallWindowWithBorder(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; retVal = true; @@ -1321,7 +1321,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in } break; case 28: // "Bugle" if (argA == 2) { - displayString_3("The item makes a loud noise!", false, charId, teamMonsterId, menuId, curMenuLine); + displayStringInSmallWindowWithBorder("The item makes a loud noise!", false, charId, teamMonsterId, menuId, curMenuLine); } else { int16 teamCharId = teamMonsterId; if (teamCharId != 0x1B) { @@ -1340,7 +1340,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in case 29: { // "Healing Spray", "Healing Elixir", "Curing Potion", "Magic Potion" int16 teamCharId; if (argA == 2) { - displayString_3("Who will use the item?", false, charId, teamMonsterId, menuId, curMenuLine); + displayStringInSmallWindowWithBorder("Who will use the item?", false, charId, teamMonsterId, menuId, curMenuLine); teamCharId = selectOtherCharFromTeam(); } else { teamCharId = teamMonsterId; @@ -1359,7 +1359,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in } if (argA == 2) { - displayString_3(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); + displayStringInSmallWindowWithBorder(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; retVal = true; @@ -1370,7 +1370,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in case 30: { int16 teamCharId; if (argA == 2) { - displayString_3("Who will use the item?", false, charId, teamMonsterId, menuId, curMenuLine); + displayStringInSmallWindowWithBorder("Who will use the item?", false, charId, teamMonsterId, menuId, curMenuLine); teamCharId = selectOtherCharFromTeam(); } else { teamCharId = teamMonsterId; @@ -1389,7 +1389,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in } if (argA == 2) { - displayString_3(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); + displayStringInSmallWindowWithBorder(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; retVal = true; @@ -1421,7 +1421,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in buffer1 = " * The item breaks!"; if (argA == 2) { getLastCharAfterAnimCount(_guessAnimationAmount); - displayString_3(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); + displayStringInSmallWindowWithBorder(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; } From a5407440f47d8a3f7652c59faec9e74abce257e2 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Tue, 10 Jan 2023 07:20:28 +0100 Subject: [PATCH 233/412] EFH: Validate one more function, renaming --- engines/efh/efh.h | 4 ++-- engines/efh/fight.cpp | 8 ++++---- engines/efh/files.cpp | 2 +- engines/efh/init.cpp | 2 +- engines/efh/savegames.cpp | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 0466bcfaec0d..898ae78ec385 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -154,7 +154,7 @@ struct NPCStruct { uint8 field_6B; uint8 field_6C; uint8 field_6D; - uint8 _unkItemId; + uint8 _defaultDefenseItemId; uint8 field_6F; uint8 field_70; uint8 field_71; @@ -400,7 +400,7 @@ class EfhEngine : public Engine { int16 getCharacterScore(int16 charId, int16 itemId); bool checkSpecialItemsOnCurrentPlace(int16 itemId); bool hasAdequateDefense(int16 monsterId, uint8 attackType); - bool hasAdequateDefense_2(int16 charId, uint8 attackType); + bool hasAdequateDefenseNPC(int16 charId, uint8 attackType); void sub1BE9A(int16 monsterId); int16 getTeamMonsterAnimId(); diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index 5f01a494b145..75394a3300d9 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -203,7 +203,7 @@ bool EfhEngine::handleFight(int16 monsterId) { ++var62; - if (hasAdequateDefense_2(_teamCharId[var7E], _items[monsterWeaponItemId]._attackType)) + if (hasAdequateDefenseNPC(_teamCharId[var7E], _items[monsterWeaponItemId]._attackType)) continue; int16 var7C = getRandom(_items[monsterWeaponItemId]._damage); @@ -1526,10 +1526,10 @@ bool EfhEngine::hasAdequateDefense(int16 monsterId, uint8 attackType) { return _items[itemId]._field17_attackTypeDefense == attackType; } -bool EfhEngine::hasAdequateDefense_2(int16 charId, uint8 attackType) { - debug("hasAdequateDefense_2 %d %d", charId, attackType); +bool EfhEngine::hasAdequateDefenseNPC(int16 charId, uint8 attackType) { + debugC(3, kDebugFight, "hasAdequateDefenseNPC %d %d", charId, attackType); - int16 itemId = _npcBuf[charId]._unkItemId; + int16 itemId = _npcBuf[charId]._defaultDefenseItemId; if (_items[itemId]._specialEffect == 0 && _items[itemId]._field17_attackTypeDefense == attackType) return true; diff --git a/engines/efh/files.cpp b/engines/efh/files.cpp index dfc475f313f6..1c53d35736e5 100644 --- a/engines/efh/files.cpp +++ b/engines/efh/files.cpp @@ -295,7 +295,7 @@ void EfhEngine::loadNPCS() { _npcBuf[i].field_6B = f.readByte(); _npcBuf[i].field_6C = f.readByte(); _npcBuf[i].field_6D = f.readByte(); - _npcBuf[i]._unkItemId = f.readByte(); + _npcBuf[i]._defaultDefenseItemId = f.readByte(); _npcBuf[i].field_6F = f.readByte(); _npcBuf[i].field_70 = f.readByte(); _npcBuf[i].field_71 = f.readByte(); diff --git a/engines/efh/init.cpp b/engines/efh/init.cpp index db1a4b2f7465..7efea57cc863 100644 --- a/engines/efh/init.cpp +++ b/engines/efh/init.cpp @@ -114,7 +114,7 @@ void NPCStruct::init() { field_6B = 0; field_6C = 0; field_6D = 0; - _unkItemId = 0; + _defaultDefenseItemId = 0; field_6F = 0; field_70 = 0; field_71 = 0; diff --git a/engines/efh/savegames.cpp b/engines/efh/savegames.cpp index 00b9ea278f5b..ed64a0c5a235 100644 --- a/engines/efh/savegames.cpp +++ b/engines/efh/savegames.cpp @@ -198,7 +198,7 @@ void EfhEngine::synchronize(Common::Serializer &s) { s.syncAsByte(_npcBuf[i].field_6B); s.syncAsByte(_npcBuf[i].field_6C); s.syncAsByte(_npcBuf[i].field_6D); - s.syncAsByte(_npcBuf[i]._unkItemId); + s.syncAsByte(_npcBuf[i]._defaultDefenseItemId); s.syncAsByte(_npcBuf[i].field_6F); s.syncAsByte(_npcBuf[i].field_70); s.syncAsByte(_npcBuf[i].field_71); From a2e496f783fb2b9db54074523d9ffcb2eff2587d Mon Sep 17 00:00:00 2001 From: Strangerke Date: Tue, 10 Jan 2023 23:54:28 +0100 Subject: [PATCH 234/412] EFH: Add a new enum, validate some more functions, some renaming --- engines/efh/constants.h | 10 ++++++ engines/efh/efh.h | 2 +- engines/efh/fight.cpp | 80 +++++++++++++++++++++-------------------- 3 files changed, 52 insertions(+), 40 deletions(-) diff --git a/engines/efh/constants.h b/engines/efh/constants.h index 46b3e2ed6dbf..2cc2f3916a3b 100644 --- a/engines/efh/constants.h +++ b/engines/efh/constants.h @@ -38,6 +38,16 @@ enum EfhMenuItems { kEfhMenuInvalid = 9 }; +enum EfhReactionType { + kEfhReactionReels = 0, + kEfhReactionCriesOut = 1, + kEfhReactionFalters = 2, + kEfhReactionWinces = 3, + kEfhReactionScreams = 4, + kEfhReactionChortles = 5, + kEfhReactionLaughs = 6 +}; + struct Font { uint8 _lines[8]; }; diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 898ae78ec385..08faff8d3c71 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -396,7 +396,7 @@ class EfhEngine : public Engine { bool characterSearchesMonsterCorpse(int16 charId, int16 monsterId); void addReactionText(int16 id); void sub1C4CA(bool WhiteFl); - int16 sub1DEC8(int16 groupNumber); + int16 getWeakestMobster(int16 groupNumber); int16 getCharacterScore(int16 charId, int16 itemId); bool checkSpecialItemsOnCurrentPlace(int16 itemId); bool hasAdequateDefense(int16 monsterId, uint8 attackType); diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index 75394a3300d9..727169e54207 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -272,20 +272,20 @@ bool EfhEngine::handleFight(int16 monsterId) { // handleFight - Add reaction text - start if (var62 != 0 && originalDamage > 0 && getRandom(100) <= 35 && _npcBuf[_teamCharId[var7E]]._hitPoints > 0) { if (_npcBuf[_teamCharId[var7E]]._hitPoints - 5 <= originalDamage) { - addReactionText(0); + addReactionText(kEfhReactionReels); } else if (_npcBuf[_teamCharId[var7E]]._hitPoints < _npcBuf[_teamCharId[var7E]]._maxHP / 8) { - addReactionText(1); + addReactionText(kEfhReactionCriesOut); } else if (_npcBuf[_teamCharId[var7E]]._hitPoints < _npcBuf[_teamCharId[var7E]]._maxHP / 4) { - addReactionText(2); + addReactionText(kEfhReactionFalters); } else if (_npcBuf[_teamCharId[var7E]]._hitPoints < _npcBuf[_teamCharId[var7E]]._maxHP / 2) { - addReactionText(3); + addReactionText(kEfhReactionWinces); } else if (_npcBuf[_teamCharId[var7E]]._hitPoints < _npcBuf[_teamCharId[var7E]]._maxHP / 3) { // CHECKME: Doesn't make any sense to check /3 after /2... I don't get it - addReactionText(4); + addReactionText(kEfhReactionScreams); } else if (_npcBuf[_teamCharId[var7E]]._maxHP / 8 >= originalDamage) { - addReactionText(5); + addReactionText(kEfhReactionChortles); } else if (originalDamage == 0 && getRandom(100) < 35) { - addReactionText(6); + addReactionText(kEfhReactionLaughs); } } // handleFight - Add reaction text - end @@ -439,7 +439,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { int16 var54; int16 teamMemberId; if (_items[teamCharItemId]._range < 3) { - teamMemberId = sub1DEC8(monsterGroupNumber); + teamMemberId = getWeakestMobster(monsterGroupNumber); var54 = teamMemberId + 1; } else { teamMemberId = 0; @@ -551,20 +551,20 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { // Action A - Add reaction text - Start if (hitCount != 0 && originalDamage > 0 && getRandom(100) <= 35 && _mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[mobsterCounter] > 0) { if (_mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[mobsterCounter] - 5 <= originalDamage) { - addReactionText(0); + addReactionText(kEfhReactionReels); } else if (_mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[mobsterCounter] < hitPointsBefore / 8) { - addReactionText(1); + addReactionText(kEfhReactionCriesOut); } else if (_mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[mobsterCounter] < hitPointsBefore / 4) { - addReactionText(2); + addReactionText(kEfhReactionFalters); } else if (_mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[mobsterCounter] < hitPointsBefore / 2) { - addReactionText(3); + addReactionText(kEfhReactionWinces); } else if (_mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[mobsterCounter] < hitPointsBefore / 3) { // CHECKME: Doesn't make any sense to check /3 after /2... I don't get it - addReactionText(4); + addReactionText(kEfhReactionScreams); } else if (hitPointsBefore / 8 >= originalDamage) { - addReactionText(5); + addReactionText(kEfhReactionChortles); } else if (originalDamage == 0 && getRandom(100) < 35) { - addReactionText(6); + addReactionText(kEfhReactionLaughs); } } // Action A - Add reaction text - End @@ -1210,12 +1210,12 @@ bool EfhEngine::characterSearchesMonsterCorpse(int16 charId, int16 monsterId) { } void EfhEngine::addReactionText(int16 id) { - debug("addReactionText %d", id); + debugC(3, kDebugFight, "addReactionText %d", id); int16 rand3 = getRandom(3); switch (id) { - case 0: + case kEfhReactionReels: switch (rand3) { case 1: _messageToBePrinted += Common::String::format(" %s%s reels from the blow!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); @@ -1230,7 +1230,7 @@ void EfhEngine::addReactionText(int16 id) { break; } break; - case 1: + case kEfhReactionCriesOut: switch (rand3) { case 1: _messageToBePrinted += Common::String::format(" %s%s cries out in agony!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); @@ -1245,7 +1245,7 @@ void EfhEngine::addReactionText(int16 id) { break; } break; - case 2: + case kEfhReactionFalters: switch (rand3) { case 1: _messageToBePrinted += Common::String::format(" %s%s is staggering!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); @@ -1260,7 +1260,7 @@ void EfhEngine::addReactionText(int16 id) { break; } break; - case 3: + case kEfhReactionWinces: switch (rand3) { case 1: _messageToBePrinted += Common::String::format(" %s%s winces from the pain!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); @@ -1275,7 +1275,7 @@ void EfhEngine::addReactionText(int16 id) { break; } break; - case 4: + case kEfhReactionScreams: switch (rand3) { case 1: _messageToBePrinted += Common::String::format(" %s%s screams!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); @@ -1290,7 +1290,7 @@ void EfhEngine::addReactionText(int16 id) { break; } break; - case 5: + case kEfhReactionChortles: switch (rand3) { case 1: _messageToBePrinted += Common::String::format(" %s%s chortles!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); @@ -1305,7 +1305,7 @@ void EfhEngine::addReactionText(int16 id) { break; } break; - case 6: + case kEfhReactionLaughs: switch (rand3) { case 1: _messageToBePrinted += Common::String::format(" %s%s laughs at the feeble attack!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); @@ -1386,10 +1386,10 @@ void EfhEngine::sub1C4CA(bool whiteFl) { } } -int16 EfhEngine::sub1DEC8(int16 groupNumber) { - debug("sub1DEC8 %d", groupNumber); +int16 EfhEngine::getWeakestMobster(int16 groupNumber) { + debugC(3, kDebugFight, "getWeakestMobster %d", groupNumber); - int16 var4 = -1; + int16 weakestMobsterId = -1; int16 monsterId = _teamMonsterIdArray[groupNumber]; if (monsterId == -1) @@ -1397,23 +1397,24 @@ int16 EfhEngine::sub1DEC8(int16 groupNumber) { for (uint counter = 0; counter < 9; ++counter) { if (isMonsterActive(groupNumber, counter)) { - var4 = counter; + weakestMobsterId = counter; break; } } - for (int16 counter = var4 + 1; counter < 9; ++counter) { + for (int16 counter = weakestMobsterId + 1; counter < 9; ++counter) { if (!isMonsterActive(groupNumber, counter)) continue; - if (_mapMonsters[monsterId]._hitPoints[var4] > _mapMonsters[monsterId]._hitPoints[counter]) - var4 = counter; + if (_mapMonsters[monsterId]._hitPoints[weakestMobsterId] > _mapMonsters[monsterId]._hitPoints[counter]) + weakestMobsterId = counter; } - if (_mapMonsters[monsterId]._hitPoints[var4] <= 0) + // Useless check, as the + if (_mapMonsters[monsterId]._hitPoints[weakestMobsterId] <= 0) return -1; - return var4; + return weakestMobsterId; } int16 EfhEngine::getCharacterScore(int16 charId, int16 itemId) { @@ -1499,24 +1500,25 @@ int16 EfhEngine::getCharacterScore(int16 charId, int16 itemId) { } bool EfhEngine::checkSpecialItemsOnCurrentPlace(int16 itemId) { - debug("checkSpecialItemsOnCurrentPlace %d", itemId); + debugC(3, kDebugFight, "checkSpecialItemsOnCurrentPlace %d", itemId); + bool retVal = true; switch (_techDataArr[_techId][_techDataId_MapPosX * 64 + _techDataId_MapPosY]) { case 1: if ((itemId >= 0x58 && itemId <= 0x68) || (itemId >= 0x86 && itemId <= 0x89) || (itemId >= 0x74 && itemId <= 0x76) || itemId == 0x8C) - return false; - return true; + retVal = false; case 2: if ((itemId >= 0x61 && itemId <= 0x63) || (itemId >= 0x74 && itemId <= 0x76) || (itemId >= 0x86 && itemId <= 0x89) || itemId == 0x5B || itemId == 0x5E || itemId == 0x66 || itemId == 0x68 || itemId == 0x8C) - return false; - return true; + retVal = false; default: - return true; + break; } + + return retVal; } bool EfhEngine::hasAdequateDefense(int16 monsterId, uint8 attackType) { - debug("hasAdequateDefense %d %d", monsterId, attackType); + debugC(3, kDebugFight, "hasAdequateDefense %d %d", monsterId, attackType); int16 itemId = _mapMonsters[monsterId]._weaponItemId; From 0e6a5d9d0c750722010d899470fd399ec65a135d Mon Sep 17 00:00:00 2001 From: Strangerke Date: Wed, 11 Jan 2023 07:16:11 +0100 Subject: [PATCH 235/412] EFH: Fix bug in characterSearchesMonsterCorpse() --- engines/efh/fight.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index 727169e54207..435d1f1e9e56 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -1191,7 +1191,7 @@ void EfhEngine::getXPAndSearchCorpse(int16 charId, Common::String namePt1, Commo } bool EfhEngine::characterSearchesMonsterCorpse(int16 charId, int16 monsterId) { - debug("characterSearchesMonsterCorpse %d %d", charId, monsterId); + debugC(3, kDebugFight, "characterSearchesMonsterCorpse %d %d", charId, monsterId); int16 rndVal = getRandom(100); if (kEncounters[_mapMonsters[monsterId]._monsterRef]._dropOccurrencePct < rndVal) @@ -1199,7 +1199,7 @@ bool EfhEngine::characterSearchesMonsterCorpse(int16 charId, int16 monsterId) { rndVal = getRandom(5) - 1; int16 itemId = kEncounters[_mapMonsters[monsterId]._monsterRef]._dropItemId[rndVal]; - if (itemId == -1) + if (itemId == -1 || itemId == 0) return false; if (!giveItemTo(charId, itemId, 0xFF)) From b8544bb762b43ad8ac5c2027fe51bdc8650a2a7d Mon Sep 17 00:00:00 2001 From: Strangerke Date: Wed, 11 Jan 2023 23:11:24 +0100 Subject: [PATCH 236/412] EFH: Fix a couple of issues in sub1C956, renaming --- engines/efh/efh.cpp | 40 ++++++++++++++--------------- engines/efh/fight.cpp | 58 ++++++++++++++++++++++--------------------- 2 files changed, 50 insertions(+), 48 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index be8cdee3fde1..0ce8a10ee37e 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -885,8 +885,8 @@ void EfhEngine::refreshTeamSize() { debugC(6, kDebugEngine, "refreshTeamSize"); _teamSize = 0; - for (uint counter = 0; counter < 3; ++counter) { - if (_teamCharId[counter] != -1) + for (uint charId = 0; charId < 3; ++charId) { + if (_teamCharId[charId] != -1) ++_teamSize; } } @@ -894,8 +894,8 @@ void EfhEngine::refreshTeamSize() { bool EfhEngine::isNpcATeamMember(int16 id) { debugC(6, kDebugEngine,"isNpcATeamMember %d", id); - for (int counter = 0; counter < _teamSize; ++counter) { - if (_teamCharId[counter] == id) + for (int charId = 0; charId < _teamSize; ++charId) { + if (_teamCharId[charId] == id) return true; } @@ -1916,10 +1916,10 @@ bool EfhEngine::handleTalk(int16 monsterId, int16 arg2, int16 itemId) { } break; case 4: - for (int counter = 0; counter < _teamSize; ++counter) { - for (uint charId = 0; charId < 10; ++charId) { - if (_npcBuf[_teamCharId[counter]]._inventory[charId]._ref == _npcBuf[npcId].field11_NpcId) { - removeObject(_teamCharId[counter], charId); + for (int charId = 0; charId < _teamSize; ++charId) { + for (uint inventoryId = 0; inventoryId < 10; ++inventoryId) { + if (_npcBuf[_teamCharId[charId]]._inventory[inventoryId]._ref == _npcBuf[npcId].field11_NpcId) { + removeObject(_teamCharId[charId], inventoryId); displayMonsterAnim(monsterId); displayImp1Text(_npcBuf[npcId].field14_textId); displayAnimFrames(0xFE, true); @@ -1937,9 +1937,9 @@ bool EfhEngine::handleTalk(int16 monsterId, int16 arg2, int16 itemId) { } break; case 6: - for (int counter = 0; counter < _teamSize; ++counter) { - for (uint charId = 0; charId < 10; ++charId) { - if (_npcBuf[_teamCharId[counter]]._inventory[charId]._ref == _npcBuf[npcId].field11_NpcId) { + for (int charId = 0; charId < _teamSize; ++charId) { + for (uint inventoryId = 0; inventoryId < 10; ++inventoryId) { + if (_npcBuf[_teamCharId[charId]]._inventory[inventoryId]._ref == _npcBuf[npcId].field11_NpcId) { displayMonsterAnim(monsterId); displayImp1Text(_npcBuf[npcId].field14_textId); displayAnimFrames(0xFE, true); @@ -1949,9 +1949,9 @@ bool EfhEngine::handleTalk(int16 monsterId, int16 arg2, int16 itemId) { } break; case 7: - for (int counter = 0; counter < _teamSize; ++counter) { - if (_npcBuf[npcId].field11_NpcId == _teamCharId[counter]) { - removeCharacterFromTeam(counter); + for (int charId = 0; charId < _teamSize; ++charId) { + if (_npcBuf[npcId].field11_NpcId == _teamCharId[charId]) { + removeCharacterFromTeam(charId); displayMonsterAnim(monsterId); displayImp1Text(_npcBuf[npcId].field14_textId); displayAnimFrames(0xFE, true); @@ -1960,11 +1960,11 @@ bool EfhEngine::handleTalk(int16 monsterId, int16 arg2, int16 itemId) { } break; case 8: - for (int counter = 0; counter < _teamSize; ++counter) { - if (_npcBuf[npcId].field11_NpcId == _teamCharId[counter]) { + for (int charId = 0; charId < _teamSize; ++charId) { + if (_npcBuf[npcId].field11_NpcId == _teamCharId[charId]) { displayMonsterAnim(monsterId); _enemyNamePt2 = _npcBuf[npcId]._name; - _characterNamePt2 = _npcBuf[_teamCharId[counter]]._name; + _characterNamePt2 = _npcBuf[_teamCharId[charId]]._name; Common::String buffer = Common::String::format("%s asks that %s leave your party.", _enemyNamePt2.c_str(), _characterNamePt2.c_str()); for (uint i = 0; i < 2; ++i) { clearBottomTextZone(0); @@ -1978,7 +1978,7 @@ bool EfhEngine::handleTalk(int16 monsterId, int16 arg2, int16 itemId) { setTextColorRed(); Common::KeyCode input = mapInputCode(waitForKey()); if (input == Common::KEYCODE_y) { - removeCharacterFromTeam(counter); + removeCharacterFromTeam(charId); displayImp1Text(_npcBuf[npcId].field14_textId); } displayAnimFrames(0xFE, true); @@ -1987,8 +1987,8 @@ bool EfhEngine::handleTalk(int16 monsterId, int16 arg2, int16 itemId) { } break; case 9: - for (int counter = 0; counter < _teamSize; ++counter) { - if (_npcBuf[npcId].field11_NpcId == _teamCharId[counter]) { + for (int charId = 0; charId < _teamSize; ++charId) { + if (_npcBuf[npcId].field11_NpcId == _teamCharId[charId]) { displayMonsterAnim(monsterId); displayImp1Text(_npcBuf[npcId].field14_textId); displayAnimFrames(0xFE, true); diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index 435d1f1e9e56..1ccfd5a66906 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -1040,30 +1040,30 @@ int16 EfhEngine::sub1C956(int16 charId, int16 unkFied18Val, bool arg4) { } bool EfhEngine::sub1CB27() { - debug("sub1CB27"); + debugC(3, kDebugFight, "sub1CB27"); + warning("To be renamed: sub1CB27"); - bool var4 = false; - for (int counter1 = 0; counter1 < _teamSize; ++counter1) { - _teamLastAction[counter1] = 0; - if (!isTeamMemberStatusNormal(counter1)) + bool retVal = false; + for (int charId = 0; charId < _teamSize; ++charId) { + _teamLastAction[charId] = 0; + if (!isTeamMemberStatusNormal(charId)) continue; - var4 = true; + retVal = true; do { - drawCombatScreen(_teamCharId[counter1], false, true); - Common::KeyCode var1 = handleAndMapInput(true); - switch (var1) { + drawCombatScreen(_teamCharId[charId], false, true); + switch (handleAndMapInput(true)) { case Common::KEYCODE_a: // Attack - _teamLastAction[counter1] = 'A'; - _teamNextAttack[counter1] = sub1C956(_teamCharId[counter1], 9, true); - if (_teamNextAttack[counter1] == -1) - _teamLastAction[counter1] = 0; + _teamLastAction[charId] = 'A'; + _teamNextAttack[charId] = sub1C956(_teamCharId[charId], 9, true); + if (_teamNextAttack[charId] == -1) + _teamLastAction[charId] = 0; break; case Common::KEYCODE_d: // Defend - _teamLastAction[counter1] = 'D'; + _teamLastAction[charId] = 'D'; break; case Common::KEYCODE_h: // Hide - _teamLastAction[counter1] = 'H'; + _teamLastAction[charId] = 'H'; break; case Common::KEYCODE_r: // Run for (int counter2 = 0; counter2 < _teamSize; ++counter2) { @@ -1071,16 +1071,16 @@ bool EfhEngine::sub1CB27() { } return true; case Common::KEYCODE_s: { // Status - int16 var8 = handleStatusMenu(2, _teamCharId[counter1]); - sub1CAB6(_teamCharId[counter1]); + int16 var8 = handleStatusMenu(2, _teamCharId[charId]); + sub1CAB6(_teamCharId[charId]); if (var8 > 999) { if (var8 == 0x7D00) - _teamLastAction[counter1] = 'S'; + _teamLastAction[charId] = 'S'; } else { - _teamLastAction[counter1] = 'U'; - _word31780[counter1] = var8; - int16 var6 = _npcBuf[_teamCharId[counter1]]._inventory[var8]._ref; - switch (var6 - 1) { + _teamLastAction[charId] = 'U'; + _word31780[charId] = var8; + int16 invEffect = _items[_npcBuf[_teamCharId[charId]]._inventory[var8]._ref]._specialEffect; + switch (invEffect - 1) { case 0: case 1: case 2: @@ -1093,7 +1093,7 @@ bool EfhEngine::sub1CB27() { case 10: case 12: case 13: - _teamNextAttack[counter1] = sub1C956(_teamCharId[counter1], 9, false); + _teamNextAttack[charId] = sub1C956(_teamCharId[charId], 9, false); break; case 9: @@ -1108,13 +1108,13 @@ bool EfhEngine::sub1CB27() { case 29: case 30: displayBoxWithText("Select Character:", 3, 1, false); - _teamNextAttack[counter1] = selectOtherCharFromTeam(); + _teamNextAttack[charId] = selectOtherCharFromTeam(); break; case 16: case 17: case 26: - _teamNextAttack[counter1] = 0xC8; + _teamNextAttack[charId] = 0xC8; break; case 19: @@ -1123,6 +1123,8 @@ bool EfhEngine::sub1CB27() { case 22: case 23: default: + _word31780[charId] = var8; + _teamNextAttack[charId] = -1; break; } } @@ -1131,15 +1133,15 @@ bool EfhEngine::sub1CB27() { case Common::KEYCODE_t: // Terrain redrawScreenForced(); getInputBlocking(); - drawCombatScreen(_teamCharId[counter1], false, true); + drawCombatScreen(_teamCharId[charId], false, true); break; default: break; } - } while (_teamLastAction[counter1] == 0); + } while (_teamLastAction[charId] == 0); } - return var4; + return retVal; } void EfhEngine::drawCombatScreen(int16 charId, bool whiteFl, bool drawFl) { From ac5da028ef6b2bf607e8efd75c21ec8019d7d0a0 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Thu, 12 Jan 2023 09:14:08 +0100 Subject: [PATCH 237/412] EFH: Renaming --- engines/efh/fight.cpp | 92 +++++++++++++++++++++---------------------- engines/efh/init.cpp | 6 +-- engines/efh/menu.cpp | 24 +++++------ 3 files changed, 61 insertions(+), 61 deletions(-) diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index 1ccfd5a66906..d58492b598cd 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -158,9 +158,9 @@ bool EfhEngine::handleFight(int16 monsterId) { } } } else if (checkMonsterMovementType(monsterGroupIdOrMonsterId, true)) { - // handleFight - Loop on var86 - Start - for (uint var86 = 0; var86 < 9; ++var86) { - if (isMonsterActive(monsterGroupIdOrMonsterId, var86)) { + // handleFight - Loop on mobsterId - Start + for (uint ctrMobsterId = 0; ctrMobsterId < 9; ++ctrMobsterId) { + if (isMonsterActive(monsterGroupIdOrMonsterId, ctrMobsterId)) { int16 monsterWeaponItemId = _mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._weaponItemId; if (monsterWeaponItemId == 0xFF) monsterWeaponItemId = 0x3F; @@ -337,9 +337,9 @@ bool EfhEngine::handleFight(int16 monsterId) { } // handleFight - Loop on var7E - End } - } else if (_mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._hitPoints[var86] > 0 && _teamMonsterEffects[monsterGroupIdOrMonsterId]._effect[var86]) { - --_teamMonsterEffects[monsterGroupIdOrMonsterId]._duration[var86]; - if (_teamMonsterEffects[monsterGroupIdOrMonsterId]._duration[var86] <= 0) { + } else if (_mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._hitPoints[ctrMobsterId] > 0 && _teamMonsterEffects[monsterGroupIdOrMonsterId]._effect[ctrMobsterId]) { + --_teamMonsterEffects[monsterGroupIdOrMonsterId]._duration[ctrMobsterId]; + if (_teamMonsterEffects[monsterGroupIdOrMonsterId]._duration[ctrMobsterId] <= 0) { _enemyNamePt2 = kEncounters[_mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._monsterRef]._name; int16 var70 = kEncounters[_mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._monsterRef]._nameArticle; if (var70 == 2) @@ -347,7 +347,7 @@ bool EfhEngine::handleFight(int16 monsterId) { else _enemyNamePt1 = ""; - switch (_teamMonsterEffects[monsterGroupIdOrMonsterId]._effect[var86]) { + switch (_teamMonsterEffects[monsterGroupIdOrMonsterId]._effect[ctrMobsterId]) { case 1: _messageToBePrinted = Common::String::format("%s%s wakes up!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str()); break; @@ -358,12 +358,12 @@ bool EfhEngine::handleFight(int16 monsterId) { _messageToBePrinted = Common::String::format("%s%s recovers!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str()); break; } - _teamMonsterEffects[monsterGroupIdOrMonsterId]._effect[var86] = 0; + _teamMonsterEffects[monsterGroupIdOrMonsterId]._effect[ctrMobsterId] = 0; displayBoxWithText(_messageToBePrinted, 1, 2, true); } } } - // handleFight - Loop on var86 - End + // handleFight - Loop on mobsterId - End } } @@ -452,8 +452,8 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { if (_teamMonsterIdArray[groupId] == -1) continue; - for (int16 mobsterCounter = teamMemberId; mobsterCounter < var54; ++mobsterCounter) { - if (isMonsterActive(groupId, mobsterCounter) && var6E) { + for (int16 ctrMobsterId = teamMemberId; ctrMobsterId < var54; ++ctrMobsterId) { + if (isMonsterActive(groupId, ctrMobsterId) && var6E) { bool noticedFl; if (!checkMonsterMovementType(groupId, true)) { setMapMonsterAggressivenessAndMovementType(groupId, 9, true); @@ -467,7 +467,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { int16 monsterId = _teamMonsterIdArray[groupId]; int16 characterPronoun = kEncounters[_mapMonsters[monsterId]._monsterRef]._nameArticle; int16 charScore = getCharacterScore(_teamCharId[teamCharId], teamCharItemId); - int16 hitPointsBefore = _mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[mobsterCounter]; + int16 hitPointsBefore = _mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId]; int16 hitCount = 0; int16 originalDamage = 0; int16 damagePointsAbsorbed = 0; @@ -500,7 +500,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { hitCount = 0; if (hitCount > 0) { - _mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[mobsterCounter] -= originalDamage; + _mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] -= originalDamage; if (hitCount > 1) { _attackBuffer = Common::String::format("%d times ", hitCount); } else { @@ -531,7 +531,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s, but does no damage!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[verbId], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[ennemyPronoun], _nameBuffer.c_str()); } else if (hitPoints == 1) { _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s for 1 point", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[verbId], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[ennemyPronoun], _nameBuffer.c_str()); - if (_mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[mobsterCounter] <= 0) { + if (_mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] <= 0) { getDeathTypeDescription(groupId, teamCharId + 1000); getXPAndSearchCorpse(_teamCharId[teamCharId], _enemyNamePt1, _enemyNamePt2, _teamMonsterIdArray[groupId]); } else { @@ -539,7 +539,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { } } else { _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s for %d points", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[verbId], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[ennemyPronoun], _nameBuffer.c_str(), hitPoints); - if (_mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[mobsterCounter] <= 0) { + if (_mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] <= 0) { getDeathTypeDescription(groupId, teamCharId + 1000); getXPAndSearchCorpse(_teamCharId[teamCharId], _enemyNamePt1, _enemyNamePt2, _teamMonsterIdArray[groupId]); } else { @@ -549,16 +549,16 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { // Action A - Check damages - End // Action A - Add reaction text - Start - if (hitCount != 0 && originalDamage > 0 && getRandom(100) <= 35 && _mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[mobsterCounter] > 0) { - if (_mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[mobsterCounter] - 5 <= originalDamage) { + if (hitCount != 0 && originalDamage > 0 && getRandom(100) <= 35 && _mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] > 0) { + if (_mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] - 5 <= originalDamage) { addReactionText(kEfhReactionReels); - } else if (_mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[mobsterCounter] < hitPointsBefore / 8) { + } else if (_mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] < hitPointsBefore / 8) { addReactionText(kEfhReactionCriesOut); - } else if (_mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[mobsterCounter] < hitPointsBefore / 4) { + } else if (_mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] < hitPointsBefore / 4) { addReactionText(kEfhReactionFalters); - } else if (_mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[mobsterCounter] < hitPointsBefore / 2) { + } else if (_mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] < hitPointsBefore / 2) { addReactionText(kEfhReactionWinces); - } else if (_mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[mobsterCounter] < hitPointsBefore / 3) { + } else if (_mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] < hitPointsBefore / 3) { // CHECKME: Doesn't make any sense to check /3 after /2... I don't get it addReactionText(kEfhReactionScreams); } else if (hitPointsBefore / 8 >= originalDamage) { @@ -570,7 +570,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { // Action A - Add reaction text - End // Action A - Add armor absorb text - Start - if (var76 && hitCount && _mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[mobsterCounter] > 0) { + if (var76 && hitCount && _mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] > 0) { if (damagePointsAbsorbed <= 1) _messageToBePrinted += Common::String::format(" %s%s's armor absorbs 1 point!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); else @@ -600,15 +600,15 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { // Action A - Check item durability - End // Action A - Check effect - Start - if (_items[teamCharItemId]._specialEffect == 1 && _mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[mobsterCounter] > 0) { + if (_items[teamCharItemId]._specialEffect == 1 && _mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] > 0) { if (getRandom(100) < 35) { - _teamMonsterEffects[groupId]._effect[mobsterCounter] = 1; - _teamMonsterEffects[groupId]._duration[mobsterCounter] = getRandom(10); + _teamMonsterEffects[groupId]._effect[ctrMobsterId] = 1; + _teamMonsterEffects[groupId]._duration[ctrMobsterId] = getRandom(10); _messageToBePrinted += Common::String::format(" %s%s falls asleep!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); } - } else if (_items[teamCharItemId]._specialEffect == 2 && _mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[mobsterCounter] > 0) { - _teamMonsterEffects[groupId]._effect[mobsterCounter] = 2; - _teamMonsterEffects[groupId]._duration[mobsterCounter] = getRandom(10); + } else if (_items[teamCharItemId]._specialEffect == 2 && _mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] > 0) { + _teamMonsterEffects[groupId]._effect[ctrMobsterId] = 2; + _teamMonsterEffects[groupId]._duration[ctrMobsterId] = getRandom(10); _messageToBePrinted += Common::String::format(" %s%s is frozen!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); } // Action A - Check effect - End @@ -706,10 +706,10 @@ bool EfhEngine::isMonsterAlreadyFighting(int16 monsterId, int16 teamMonsterId) { void EfhEngine::resetTeamMonsterEffects() { debugC(6, kDebugFight, "resetTeamMonsterEffects"); - for (uint ctrMonsterId = 0; ctrMonsterId < 5; ++ctrMonsterId) { - for (uint ctrEffectId = 0; ctrEffectId < 9; ++ctrEffectId) { - _teamMonsterEffects[ctrMonsterId]._effect[ctrEffectId] = 0; - _teamMonsterEffects[ctrMonsterId]._duration[ctrEffectId] = 0; + for (uint ctrGroupId = 0; ctrGroupId < 5; ++ctrGroupId) { + for (uint ctrMobsterId = 0; ctrMobsterId < 9; ++ctrMobsterId) { + _teamMonsterEffects[ctrGroupId]._effect[ctrMobsterId] = 0; + _teamMonsterEffects[ctrGroupId]._duration[ctrMobsterId] = 0; } } } @@ -1554,26 +1554,26 @@ void EfhEngine::sub1BE9A(int16 monsterId) { debug("sub1BE9A %d", monsterId); // sub1BE9A - 1rst loop counter1_monsterId - Start - for (uint counter1 = 0; counter1 < 5; ++counter1) { - if (countMonsterGroupMembers(counter1)) + for (uint ctrGroupId = 0; ctrGroupId < 5; ++ctrGroupId) { + if (countMonsterGroupMembers(ctrGroupId)) continue; - for (uint counter2 = 0; counter2 < 9; ++counter2) { - _mapMonsters[_teamMonsterIdArray[counter1]]._hitPoints[counter2] = 0; - _teamMonsterEffects[counter1]._effect[counter2] = 0; - _teamMonsterEffects[counter1]._duration[counter2] = 0; + for (uint ctrMobster = 0; ctrMobster < 9; ++ctrMobster) { + _mapMonsters[_teamMonsterIdArray[ctrGroupId]]._hitPoints[ctrMobster] = 0; + _teamMonsterEffects[ctrGroupId]._effect[ctrMobster] = 0; + _teamMonsterEffects[ctrGroupId]._duration[ctrMobster] = 0; } - _teamMonsterIdArray[counter1] = -1; + _teamMonsterIdArray[ctrGroupId] = -1; // CHECKME: counter1 is not incrementing, which is very, very suspicious as we are copying over and over to the same destination // if the purpose is compact the array, it should be handle differently - for (uint counter2 = counter1 + 1; counter2 < 5; ++counter2) { - for (uint var8 = 0; var8 < 9; ++var8) { - _teamMonsterEffects[counter1]._effect[var8] = _teamMonsterEffects[counter2]._effect[var8]; - _teamMonsterEffects[counter1]._duration[var8] = _teamMonsterEffects[counter2]._duration[var8]; + for (uint counter2 = ctrGroupId + 1; counter2 < 5; ++counter2) { + for (uint ctrMobsterId = 0; ctrMobsterId < 9; ++ctrMobsterId) { + _teamMonsterEffects[ctrGroupId]._effect[ctrMobsterId] = _teamMonsterEffects[counter2]._effect[ctrMobsterId]; + _teamMonsterEffects[ctrGroupId]._duration[ctrMobsterId] = _teamMonsterEffects[counter2]._duration[ctrMobsterId]; } - _teamMonsterIdArray[counter1] = _teamMonsterIdArray[counter2]; + _teamMonsterIdArray[ctrGroupId] = _teamMonsterIdArray[counter2]; } } // sub1BE9A - 1rst loop counter1_monsterId - End @@ -1620,8 +1620,8 @@ void EfhEngine::sub1BE9A(int16 monsterId) { // The original at this point was doing a loop on counter1, which is not a good idea as // it was resetting the counter1 to 9 whatever its value before the loop. // I therefore decided to use another counter as it looks like an original misbehavior/bug. - for (uint ctrEffectId = 0; ctrEffectId < 9; ++ctrEffectId) { - _teamMonsterEffects[teamMonsterId]._effect[ctrEffectId] = 0; + for (uint ctrMobsterId = 0; ctrMobsterId < 9; ++ctrMobsterId) { + _teamMonsterEffects[teamMonsterId]._effect[ctrMobsterId] = 0; } if (++teamMonsterId >= 5) diff --git a/engines/efh/init.cpp b/engines/efh/init.cpp index 7efea57cc863..d34963244e63 100644 --- a/engines/efh/init.cpp +++ b/engines/efh/init.cpp @@ -145,9 +145,9 @@ uint8 MapMonster::getPronoun() { } void TeamMonsterEffect::init() { - for (int i = 0; i < 9; ++i) { - _effect[i] = 0; - _duration[i] = 0; + for (int ctrMobsterId = 0; ctrMobsterId < 9; ++ctrMobsterId) { + _effect[ctrMobsterId] = 0; + _duration[ctrMobsterId] = 0; } } diff --git a/engines/efh/menu.cpp b/engines/efh/menu.cpp index d25ae4f16d3a..ba3c89ceea6f 100644 --- a/engines/efh/menu.cpp +++ b/engines/efh/menu.cpp @@ -906,24 +906,24 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in int16 victims = 0; _messageToBePrinted += " The item emits a low droning hum..."; if (getRandom(100) < 50) { - for (uint ctrEffectId = 0; ctrEffectId < 9; ++ctrEffectId) { - if (isMonsterActive(teamMonsterId, ctrEffectId)) { + for (uint ctrMobsterId = 0; ctrMobsterId < 9; ++ctrMobsterId) { + if (isMonsterActive(teamMonsterId, ctrMobsterId)) { ++victims; - _teamMonsterEffects[teamMonsterId]._effect[ctrEffectId] = 1; - _teamMonsterEffects[teamMonsterId]._duration[ctrEffectId] = getRandom(8); + _teamMonsterEffects[teamMonsterId]._effect[ctrMobsterId] = 1; + _teamMonsterEffects[teamMonsterId]._duration[ctrMobsterId] = getRandom(8); } } } else { int16 NumberOfTargets = getRandom(9); - for (uint ctrEffectId = 0; ctrEffectId < 9; ++ctrEffectId) { + for (uint ctrMobsterId = 0; ctrMobsterId < 9; ++ctrMobsterId) { if (NumberOfTargets == 0) break; - if (isMonsterActive(teamMonsterId, ctrEffectId)) { + if (isMonsterActive(teamMonsterId, ctrMobsterId)) { ++victims; --NumberOfTargets; - _teamMonsterEffects[teamMonsterId]._effect[ctrEffectId] = 1; - _teamMonsterEffects[teamMonsterId]._duration[ctrEffectId] = getRandom(8); + _teamMonsterEffects[teamMonsterId]._effect[ctrMobsterId] = 1; + _teamMonsterEffects[teamMonsterId]._duration[ctrMobsterId] = getRandom(8); } } } @@ -954,15 +954,15 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in } } else { int16 varAC = getRandom(9); - for (uint ctrEffectId = 0; ctrEffectId < 9; ++ctrEffectId) { + for (uint ctrMobsterId = 0; ctrMobsterId < 9; ++ctrMobsterId) { if (varAC == 0) break; - if (isMonsterActive(teamMonsterId, ctrEffectId)) { + if (isMonsterActive(teamMonsterId, ctrMobsterId)) { ++victim; --varAC; - _teamMonsterEffects[teamMonsterId]._effect[ctrEffectId] = 2; - _teamMonsterEffects[teamMonsterId]._duration[ctrEffectId] = getRandom(8); + _teamMonsterEffects[teamMonsterId]._effect[ctrMobsterId] = 2; + _teamMonsterEffects[teamMonsterId]._duration[ctrMobsterId] = getRandom(8); } } } From d6650f6ca30ba0cd265760e90655813b8a74f373 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Thu, 12 Jan 2023 23:36:14 +0100 Subject: [PATCH 238/412] EFH: Validate addNewOpponents(), some renaming --- engines/efh/efh.h | 2 +- engines/efh/fight.cpp | 24 ++++++++++++------------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 08faff8d3c71..b1995d98ba81 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -401,7 +401,7 @@ class EfhEngine : public Engine { bool checkSpecialItemsOnCurrentPlace(int16 itemId); bool hasAdequateDefense(int16 monsterId, uint8 attackType); bool hasAdequateDefenseNPC(int16 charId, uint8 attackType); - void sub1BE9A(int16 monsterId); + void addNewOpponents(int16 monsterId); int16 getTeamMonsterAnimId(); // Files diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index d58492b598cd..8f690a77ad38 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -368,7 +368,7 @@ bool EfhEngine::handleFight(int16 monsterId) { } handleMapMonsterMoves(); - sub1BE9A(monsterId); + addNewOpponents(monsterId); } resetTeamMonsterIdArray(); @@ -1550,10 +1550,10 @@ bool EfhEngine::hasAdequateDefenseNPC(int16 charId, uint8 attackType) { } // The parameter isn't used in the original -void EfhEngine::sub1BE9A(int16 monsterId) { - debug("sub1BE9A %d", monsterId); +void EfhEngine::addNewOpponents(int16 monsterId) { + debugC(3, kDebugFight, "addNewOpponents %d", monsterId); - // sub1BE9A - 1rst loop counter1_monsterId - Start + // addNewOpponents - 1rst loop counter1_monsterId - Start for (uint ctrGroupId = 0; ctrGroupId < 5; ++ctrGroupId) { if (countMonsterGroupMembers(ctrGroupId)) continue; @@ -1566,7 +1566,7 @@ void EfhEngine::sub1BE9A(int16 monsterId) { _teamMonsterIdArray[ctrGroupId] = -1; - // CHECKME: counter1 is not incrementing, which is very, very suspicious as we are copying over and over to the same destination + // CHECKME: ctrGroupId is not incrementing, which is very, very suspicious as we are copying over and over to the same destination // if the purpose is compact the array, it should be handle differently for (uint counter2 = ctrGroupId + 1; counter2 < 5; ++counter2) { for (uint ctrMobsterId = 0; ctrMobsterId < 9; ++ctrMobsterId) { @@ -1576,7 +1576,7 @@ void EfhEngine::sub1BE9A(int16 monsterId) { _teamMonsterIdArray[ctrGroupId] = _teamMonsterIdArray[counter2]; } } - // sub1BE9A - 1rst loop counter1_monsterId - End + // addNewOpponents - 1rst loop counter1_monsterId - End int16 teamMonsterId = -1; for (uint counter1 = 0; counter1 < 5; ++counter1) { @@ -1587,7 +1587,7 @@ void EfhEngine::sub1BE9A(int16 monsterId) { } if (teamMonsterId != -1) { - // sub1BE9A - loop var2 - Start + // addNewOpponents - loop var2 - Start for (int var2 = 1; var2 < 3; ++var2) { if (teamMonsterId >= 5) break; @@ -1599,8 +1599,8 @@ void EfhEngine::sub1BE9A(int16 monsterId) { if (((_mapMonsters[ctrMapMonsterId]._possessivePronounSHL6 & 0x3F) == 0x3F && !isNpcATeamMember(_mapMonsters[ctrMapMonsterId]._npcId)) || (_mapMonsters[ctrMapMonsterId]._possessivePronounSHL6 & 0x3F) <= 0x3D) { if (checkIfMonsterOnSameLargeMapPlace(ctrMapMonsterId)) { bool monsterActiveFound = false; - for (uint ctrSubId = 0; ctrSubId < 9; ++ctrSubId) { - if (_mapMonsters[ctrMapMonsterId]._hitPoints[ctrSubId] > 0) { + for (uint ctrMobsterId = 0; ctrMobsterId < 9; ++ctrMobsterId) { + if (_mapMonsters[ctrMapMonsterId]._hitPoints[ctrMobsterId] > 0) { monsterActiveFound = true; break; } @@ -1630,20 +1630,20 @@ void EfhEngine::sub1BE9A(int16 monsterId) { } } } - // sub1BE9A - loop var2 - End + // addNewOpponents - loop var2 - End } if (teamMonsterId == -1 || teamMonsterId > 4) return; - // sub1BE9A - last loop counter1_monsterId - Start + // addNewOpponents - last loop counter1_monsterId - Start for (int16 ctrTeamMonsterId = teamMonsterId; ctrTeamMonsterId < 5; ++ctrTeamMonsterId) { _teamMonsterIdArray[ctrTeamMonsterId] = -1; for (uint ctrEffectId = 0; ctrEffectId < 9; ++ctrEffectId) { _teamMonsterEffects[ctrTeamMonsterId]._effect[ctrEffectId] = (int16)0x8000; } } - // sub1BE9A - last loop counter1_monsterId - End + // addNewOpponents - last loop counter1_monsterId - End } int16 EfhEngine::getTeamMonsterAnimId() { From 90e16512d529398d8566f119854fc189627d47a4 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Fri, 13 Jan 2023 00:53:39 +0100 Subject: [PATCH 239/412] EFH: Fix CppCheck warnings, add some comments, validate loadPlacesFile() --- engines/efh/efh.cpp | 8 ++++---- engines/efh/fight.cpp | 6 ++++-- engines/efh/files.cpp | 2 +- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 0ce8a10ee37e..119f8336795a 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -2029,10 +2029,10 @@ void EfhEngine::displayImp1Text(int16 textId) { int16 charCounter = 0; int16 stringIdx = 0; - bool textComplete = false; - bool maxReached = false; if (textId <= 0xFE) { + bool textComplete = false; + bool maxReached = false; // Clear temp text on the lower left part of the screen if (_tempTextPtr) { _tempTextPtr = nullptr; @@ -2265,8 +2265,8 @@ void EfhEngine::computeInitiatives() { debugC(6, kDebugEngine, "computeInitiatives"); for (int counter = 0; counter < 3; ++counter) { - if (_teamCharId[counter] != -1 && counter < _teamSize) { - _initiatives[counter]._id = counter + 1000; + if (counter < _teamSize && _teamCharId[counter] != -1) { + _initiatives[counter]._id = counter + 1000; // Magic value added to detect it's a member of the team _initiatives[counter]._initiative = _npcBuf[_teamCharId[counter]]._infoScore[3]; // "Agility" } else { _initiatives[counter]._id = -1; diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index 8f690a77ad38..c3c404439f36 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -280,11 +280,12 @@ bool EfhEngine::handleFight(int16 monsterId) { } else if (_npcBuf[_teamCharId[var7E]]._hitPoints < _npcBuf[_teamCharId[var7E]]._maxHP / 2) { addReactionText(kEfhReactionWinces); } else if (_npcBuf[_teamCharId[var7E]]._hitPoints < _npcBuf[_teamCharId[var7E]]._maxHP / 3) { - // CHECKME: Doesn't make any sense to check /3 after /2... I don't get it + // CHECKME: Doesn't make any sense to check /3 after /2... I don't get it. Looks like an original bug addReactionText(kEfhReactionScreams); } else if (_npcBuf[_teamCharId[var7E]]._maxHP / 8 >= originalDamage) { addReactionText(kEfhReactionChortles); } else if (originalDamage == 0 && getRandom(100) < 35) { + // CHECKME: "originalDamage == 0" is always false as it's checked beforehand. Looks like another original bug addReactionText(kEfhReactionLaughs); } } @@ -559,11 +560,12 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { } else if (_mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] < hitPointsBefore / 2) { addReactionText(kEfhReactionWinces); } else if (_mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] < hitPointsBefore / 3) { - // CHECKME: Doesn't make any sense to check /3 after /2... I don't get it + // CHECKME: Doesn't make any sense to check /3 after /2... I don't get it. Looks like an original bug addReactionText(kEfhReactionScreams); } else if (hitPointsBefore / 8 >= originalDamage) { addReactionText(kEfhReactionChortles); } else if (originalDamage == 0 && getRandom(100) < 35) { + // CHECKME: "originalDamage == 0" is always false as it's checked beforehand. Looks like another original bug addReactionText(kEfhReactionLaughs); } } diff --git a/engines/efh/files.cpp b/engines/efh/files.cpp index 1c53d35736e5..218c8208a14a 100644 --- a/engines/efh/files.cpp +++ b/engines/efh/files.cpp @@ -220,7 +220,7 @@ void EfhEngine::loadTechMapImp(int16 fileId) { } void EfhEngine::loadPlacesFile(uint16 fullPlaceId, bool forceReloadFl) { - debug("loadPlacesFile %d %s", fullPlaceId, forceReloadFl ? "True" : "False"); + debugC(2, kDebugEngine, "loadPlacesFile %d %s", fullPlaceId, forceReloadFl ? "True" : "False"); if (fullPlaceId == 0xFF) return; From 2ec85960ad891e1254aed7881226d217a0c5b32c Mon Sep 17 00:00:00 2001 From: Strangerke Date: Fri, 13 Jan 2023 09:03:24 +0100 Subject: [PATCH 240/412] EFH: Validate more functions, renaming --- engines/efh/efh.h | 4 +-- engines/efh/fight.cpp | 21 ++++++----- engines/efh/init.cpp | 2 +- engines/efh/menu.cpp | 84 +++++++++++++++++++++---------------------- 4 files changed, 57 insertions(+), 54 deletions(-) diff --git a/engines/efh/efh.h b/engines/efh/efh.h index b1995d98ba81..6b7ace5ca114 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -470,7 +470,7 @@ class EfhEngine : public Engine { int16 handleStatusMenu(int16 gameMode, int16 charId); void unequipItem(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine); void tryToggleEquipped(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine); - int16 useObject(int16 charId, int16 objectId, int16 teamMonsterId, int16 menuId, int16 curMenuLine, int16 argA); + int16 useObject(int16 charId, int16 objectId, int16 teamMonsterId, int16 menuId, int16 curMenuLine, int16 gameMode); // Savegames void synchronize(Common::Serializer &s); @@ -603,7 +603,7 @@ class EfhEngine : public Engine { int16 _menuDepth; int16 _menuItemCounter; int16 _teamPctVisible[3]; - int16 _word32482[3]; + int16 _teamPctDodgeMiss[3]; int16 _teamNextAttack[3]; int16 _word31780[3]; diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index c3c404439f36..274caafd58bf 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -112,7 +112,7 @@ bool EfhEngine::handleFight(int16 monsterId) { displayAnimFrames(varInt, true); for (int counter = 0; counter < _teamSize; ++counter) { _teamPctVisible[counter] = 100; - _word32482[counter] = 65; + _teamPctDodgeMiss[counter] = 65; } if (!sub1CB27()) { @@ -190,7 +190,7 @@ bool EfhEngine::handleFight(int16 monsterId) { int16 ennemyPronoun = kEncounters[_mapMonsters[varInt]._monsterRef]._nameArticle; int16 characterPronoun = _npcBuf[_teamCharId[var7E]].getPronoun(); varInt = _items[monsterWeaponItemId].field_13; - _word32482[var7E] += (varInt * 5); + _teamPctDodgeMiss[var7E] += (varInt * 5); int16 var62 = 0; int16 hitPoints = 0; int16 originalDamage = 0; @@ -198,7 +198,7 @@ bool EfhEngine::handleFight(int16 monsterId) { int16 var64 = _mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._npcId * _items[monsterWeaponItemId]._attacks; for (int var84 = 0; var84 < var64; ++var84) { // handleFight - Loop var84 on var64 (objectId) - Start - if (getRandom(100) > _word32482[var7E]) + if (getRandom(100) > _teamPctDodgeMiss[var7E]) continue; ++var62; @@ -627,9 +627,12 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { } void EfhEngine::handleFight_lastAction_D(int16 teamCharId) { - debug("handleFight_lastAction_D %d", teamCharId); + // Fight - Action 'D' - Defend + // In the original, this function is part of handleFight. + // It has been split for readability purposes. + debugC(3, kDebugFight, "handleFight_lastAction_D %d", teamCharId); - _word32482[teamCharId] -= 40; + _teamPctDodgeMiss[teamCharId] -= 40; _enemyNamePt2 = _npcBuf[_teamCharId[teamCharId]]._name; uint8 pronoun = _npcBuf[_teamCharId[teamCharId]].getPronoun(); @@ -644,10 +647,10 @@ void EfhEngine::handleFight_lastAction_D(int16 teamCharId) { } void EfhEngine::handleFight_lastAction_H(int16 teamCharId) { - debugC(3, kDebugFight, "handleFight_lastAction_H %d", teamCharId); - + // Fight - Action 'H' - Hide // In the original, this function is part of handleFight. // It has been split for readability purposes. + debugC(3, kDebugFight, "handleFight_lastAction_H %d", teamCharId); _teamPctVisible[teamCharId] -= 50; _enemyNamePt2 = _npcBuf[_teamCharId[teamCharId]]._name; @@ -663,11 +666,11 @@ void EfhEngine::handleFight_lastAction_H(int16 teamCharId) { } bool EfhEngine::handleFight_lastAction_U(int16 teamCharId) { - debug("handleFight_lastAction_U %d", teamCharId); - // Fight - Action 'U' - Use Item // In the original, this function is part of handleFight. // It has been split for readability purposes. + debugC(3, kDebugFight, "handleFight_lastAction_U %d", teamCharId); + int16 itemId = _npcBuf[_teamCharId[teamCharId]]._inventory[_word31780[teamCharId]]._ref; _enemyNamePt2 = _npcBuf[_teamCharId[teamCharId]]._name; _nameBuffer = _items[itemId]._name; diff --git a/engines/efh/init.cpp b/engines/efh/init.cpp index d34963244e63..99dfcca0681b 100644 --- a/engines/efh/init.cpp +++ b/engines/efh/init.cpp @@ -252,7 +252,7 @@ EfhEngine::EfhEngine(OSystem *syst, const ADGameDescription *gd) : Engine(syst), _teamCharStatus[i]._status = 0; _teamCharStatus[i]._duration = 0; _teamPctVisible[i] = 0; - _word32482[i] = 0; + _teamPctDodgeMiss[i] = 0; _teamNextAttack[i] = -1; _word31780[i] = 0; _teamLastAction[i] = 0; diff --git a/engines/efh/menu.cpp b/engines/efh/menu.cpp index ba3c89ceea6f..b1d9dcd7914f 100644 --- a/engines/efh/menu.cpp +++ b/engines/efh/menu.cpp @@ -889,8 +889,8 @@ void EfhEngine::tryToggleEquipped(int16 charId, int16 objectId, int16 windowId, } } -int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, int16 menuId, int16 curMenuLine, int16 argA) { - debug("useObject %d %d %d %d %d %d", charId, objectId, teamMonsterId, menuId, curMenuLine, argA); +int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, int16 menuId, int16 curMenuLine, int16 gameMode) { + debug("useObject %d %d %d %d %d %s", charId, objectId, teamMonsterId, menuId, curMenuLine, gameMode == 3 ? "Combat" : "Normal"); Common::String buffer1 = ""; @@ -900,7 +900,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in int16 itemId = _npcBuf[charId]._inventory[objectId]._ref; switch (_items[itemId]._specialEffect - 1) { case 0: // "Demonic Powers", "MindDomination", "Guilt Trip", "Sleep Grenade", "SleepGrenader" - if (argA == 2) { + if (gameMode == 2) { displayStringInSmallWindowWithBorder("The item emits a low droning hum...", false, charId, teamMonsterId, menuId, curMenuLine); } else { int16 victims = 0; @@ -939,7 +939,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in objectUsedFl = true; break; case 1: // "Chilling Touch", "Guilt", "Petrify Rod", "Elmer's Gun" - if (argA == 2) { + if (gameMode == 2) { displayStringInSmallWindowWithBorder("The item grows very cold for a moment...", false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += " The item emits a blue beam..."; @@ -980,7 +980,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in objectUsedFl = true; break; case 2: - if (argA == 2) { + if (gameMode == 2) { displayStringInSmallWindowWithBorder("A serene feeling passes through the air...", false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += " The combat pauses...as there is a moment of forgiveness..."; @@ -990,7 +990,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in objectUsedFl = true; break; case 4: // "Unholy Sinwave", "Holy Water" - if (argA == 2) { + if (gameMode == 2) { displayStringInSmallWindowWithBorder("A dark sense fills your soul...then fades!", false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += " A dark gray fiery whirlwind surrounds the poor victim...the power fades and death abounds!"; @@ -1014,7 +1014,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in objectUsedFl = true; break; case 5: // "Lucifer'sTouch", "Book of Death", "Holy Cross" - if (argA == 2) { + if (gameMode == 2) { displayStringInSmallWindowWithBorder("A dark sense fills your soul...then fades!", false, charId, teamMonsterId, menuId, curMenuLine); } else { if (getRandom(100) < 50) { @@ -1035,7 +1035,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in objectUsedFl = true; break; case 12: // "Terror Gaze", "Servitude Rod", "Despair Ankh", "ConfusionPrism", "Pipe of Peace", "Red Cape", "Peace Symbol", "Hell Badge" - if (argA == 2) { + if (gameMode == 2) { displayStringInSmallWindowWithBorder("There is no apparent affect!", false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += " The magic sparkles brilliant hues in the air!"; @@ -1044,31 +1044,31 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in objectUsedFl = true; break; case 14: { // "Feathered Cap" - int16 varAA; - if (argA == 2) { + int16 teamCharId; + if (gameMode == 2) { displayStringInSmallWindowWithBorder("Who will use the item?", false, charId, teamMonsterId, menuId, curMenuLine); - varAA = selectOtherCharFromTeam(); + teamCharId = selectOtherCharFromTeam(); } else { - varAA = teamMonsterId; + teamCharId = teamMonsterId; } - if (varAA != 0x1B) { + if (teamCharId != 0x1B) { // Escape code, which means the user cancelled the selection buffer1 = " The magic makes the user as quick and agile as a bird!"; - if (argA == 2) { + if (gameMode == 2) { displayStringInSmallWindowWithBorder(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; } - _word32482[varAA] -= 50; - if (_word32482[varAA] < 0) - _word32482[varAA] = 0; + _teamPctDodgeMiss[teamCharId] -= 50; + if (_teamPctDodgeMiss[teamCharId] < 0) + _teamPctDodgeMiss[teamCharId] = 0; } objectUsedFl = true; } break; case 15: { // "Regal Crown" int16 teamCharId; - if (argA == 2) { + if (gameMode == 2) { displayStringInSmallWindowWithBorder("Who will use the item?", false, charId, teamMonsterId, menuId, curMenuLine); teamCharId = selectOtherCharFromTeam(); } else { @@ -1077,7 +1077,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in if (teamCharId != 0x1B) { buffer1 = " The magic makes the user invisible!"; - if (argA == 2) { + if (gameMode == 2) { displayStringInSmallWindowWithBorder(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; @@ -1098,7 +1098,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in if (_tileFact[tileFactId]._field0 == 0) { totalPartyKill(); buffer1 = "The entire party vanishes in a flash... only to appear in stone !"; - if (argA == 2) { + if (gameMode == 2) { displayStringInSmallWindowWithBorder(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; @@ -1107,7 +1107,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in } else { if (tileFactId == 0 || tileFactId == 0x48) { buffer1 = "The entire party vanishes in a flash...but re-appears, as if nothing happened!"; - if (argA == 2) { + if (gameMode == 2) { displayStringInSmallWindowWithBorder(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; @@ -1115,7 +1115,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in } } else { buffer1 = "The entire party vanishes in a flash...only to appear elsewhere!"; - if (argA == 2) { + if (gameMode == 2) { displayStringInSmallWindowWithBorder(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; @@ -1133,7 +1133,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in if (_tileFact[tileFactId]._field0 == 0) { totalPartyKill(); buffer1 = "The entire party vanishes in a flash... only to appear in stone !"; - if (argA == 2) { + if (gameMode == 2) { displayStringInSmallWindowWithBorder(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; @@ -1142,7 +1142,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in } else { if (tileFactId == 0 || tileFactId == 0x48) { buffer1 = "The entire party vanishes in a flash...but re-appears, as if nothing happened!"; - if (argA == 2) { + if (gameMode == 2) { displayStringInSmallWindowWithBorder(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; @@ -1150,7 +1150,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in } } else { buffer1 = "The entire party vanishes in a flash...only to appear elsewhere!"; - if (argA == 2) { + if (gameMode == 2) { displayStringInSmallWindowWithBorder(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; @@ -1162,7 +1162,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in objectUsedFl = true; } break; case 18: - if (argA == 2) { + if (gameMode == 2) { displayStringInSmallWindowWithBorder("The item makes a loud noise!", false, charId, teamMonsterId, menuId, curMenuLine); } else { int16 teamCharId = teamMonsterId; @@ -1181,7 +1181,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in break; case 19: // "Junk" buffer1 = " * The item breaks!"; - if (argA == 2) { + if (gameMode == 2) { displayStringInSmallWindowWithBorder(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; @@ -1217,7 +1217,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in } } buffer1 += "'"; - if (argA == 2) { + if (gameMode == 2) { displayStringInSmallWindowWithBorder(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; @@ -1228,7 +1228,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in break; case 24: { int16 teamCharId; - if (argA == 2) { + if (gameMode == 2) { displayStringInSmallWindowWithBorder("Who will use this item?", false, charId, teamMonsterId, menuId, curMenuLine); teamCharId = selectOtherCharFromTeam(); } else @@ -1246,7 +1246,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in else buffer1 = Common::String::format("%s increased 1 point!", kSkillArray[varAE]); - if (argA == 2) { + if (gameMode == 2) { displayStringInSmallWindowWithBorder(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; @@ -1258,7 +1258,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in } break; case 25: { int16 teamCharId; - if (argA == 2) { + if (gameMode == 2) { displayStringInSmallWindowWithBorder("Who will use this item?", false, charId, teamMonsterId, menuId, curMenuLine); teamCharId = selectOtherCharFromTeam(); } else @@ -1276,7 +1276,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in else buffer1 = Common::String::format("%s lowered 1 point!", kSkillArray[varAE]); - if (argA == 2) { + if (gameMode == 2) { displayStringInSmallWindowWithBorder(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; @@ -1288,7 +1288,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in } break; case 26: // "Black Sphere" buffer1 = "The entire party collapses, dead!!!"; - if (argA == 2) { + if (gameMode == 2) { displayStringInSmallWindowWithBorder(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; @@ -1299,7 +1299,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in break; case 27: { // "Magic Pyramid", "Razor Blade" int16 teamCharId; - if (argA == 2) { + if (gameMode == 2) { displayStringInSmallWindowWithBorder("Who will use the item?", false, charId, teamMonsterId, menuId, curMenuLine); teamCharId = selectOtherCharFromTeam(); } else { @@ -1309,7 +1309,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in if (teamCharId != 0x1B) { _npcBuf[_teamCharId[teamCharId]]._hitPoints = 0; buffer1 = Common::String::format("%s collapses, dead!!!", _npcBuf[_teamCharId[teamCharId]]._name); - if (argA == 2) { + if (gameMode == 2) { displayStringInSmallWindowWithBorder(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; @@ -1320,7 +1320,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in objectUsedFl = true; } break; case 28: // "Bugle" - if (argA == 2) { + if (gameMode == 2) { displayStringInSmallWindowWithBorder("The item makes a loud noise!", false, charId, teamMonsterId, menuId, curMenuLine); } else { int16 teamCharId = teamMonsterId; @@ -1339,7 +1339,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in break; case 29: { // "Healing Spray", "Healing Elixir", "Curing Potion", "Magic Potion" int16 teamCharId; - if (argA == 2) { + if (gameMode == 2) { displayStringInSmallWindowWithBorder("Who will use the item?", false, charId, teamMonsterId, menuId, curMenuLine); teamCharId = selectOtherCharFromTeam(); } else { @@ -1358,7 +1358,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in buffer1 = Common::String::format("%s is healed 1 point!", _npcBuf[_teamCharId[teamCharId]]._name); } - if (argA == 2) { + if (gameMode == 2) { displayStringInSmallWindowWithBorder(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; @@ -1369,7 +1369,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in } break; case 30: { int16 teamCharId; - if (argA == 2) { + if (gameMode == 2) { displayStringInSmallWindowWithBorder("Who will use the item?", false, charId, teamMonsterId, menuId, curMenuLine); teamCharId = selectOtherCharFromTeam(); } else { @@ -1388,7 +1388,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in buffer1 = Common::String::format("%s is harmed for 1 point!", _npcBuf[_teamCharId[teamCharId]]._name); } - if (argA == 2) { + if (gameMode == 2) { displayStringInSmallWindowWithBorder(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += buffer1; @@ -1419,7 +1419,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in --usesLeft; if (usesLeft <= 0) { buffer1 = " * The item breaks!"; - if (argA == 2) { + if (gameMode == 2) { getLastCharAfterAnimCount(_guessAnimationAmount); displayStringInSmallWindowWithBorder(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); } else { @@ -1433,7 +1433,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in } } - if (argA == 2) { + if (gameMode == 2) { getLastCharAfterAnimCount(_guessAnimationAmount); displayWindowAndStatusMenu(charId, teamMonsterId, menuId, curMenuLine); } From 789917e1742e692384c99b06e33eb250bc10883a Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sat, 14 Jan 2023 14:05:36 +0100 Subject: [PATCH 241/412] EFH: Fix issues in getDeathTypeDescription, renaming --- engines/efh/efh.h | 2 +- engines/efh/fight.cpp | 40 +++++++++++++++++++--------------------- 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 6b7ace5ca114..4e0a067fd021 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -388,7 +388,7 @@ class EfhEngine : public Engine { void initFight(int16 monsterId); void resetTeamMonsterIdArray(); bool isTeamMemberStatusNormal(int16 id); - void getDeathTypeDescription(int16 attackerId, int16 victimId); + void getDeathTypeDescription(int16 victimId, int16 attackerId); int16 sub1C956(int16 charId, int16 unkFied18Val, bool arg4); bool sub1CB27(); void drawCombatScreen(int16 charId, bool whiteFl, bool drawFl); diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index 274caafd58bf..ed7e58b7e76e 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -736,16 +736,16 @@ bool EfhEngine::isTeamMemberStatusNormal(int16 teamMemberId) { return false; } -void EfhEngine::getDeathTypeDescription(int16 attackerId, int16 victimId) { - debug("getDeathTypeDescription %d %d", attackerId, victimId); +void EfhEngine::getDeathTypeDescription(int16 victimId, int16 attackerId) { + debugC(3, kDebugFight, "getDeathTypeDescription %d %d", victimId, attackerId); uint8 pronoun; - if (attackerId > 999) { - int16 charId = _teamCharId[attackerId - 1000]; + if (victimId >= 1000) { // Magic value for team members + int16 charId = _teamCharId[victimId - 1000]; pronoun = _npcBuf[charId].getPronoun(); } else { - int16 charId = _teamMonsterIdArray[attackerId]; + int16 charId = _teamMonsterIdArray[victimId]; pronoun = _mapMonsters[charId].getPronoun(); } @@ -755,27 +755,25 @@ void EfhEngine::getDeathTypeDescription(int16 attackerId, int16 victimId) { int16 deathType; if (getRandom(100) < 20) { deathType = 0; - } else { - if (victimId >= 1000) { - int16 charId = _teamCharId[victimId - 1000]; - if (charId == -1) - deathType = 0; - else { - int16 exclusiveItemId = getEquippedExclusiveType(charId, 9, true); - if (exclusiveItemId == 0x7FFF) - deathType = 0; - else - deathType = _items[exclusiveItemId]._attackType + 1; - } - } else if (_teamMonsterIdArray[victimId] == -1) + } else if (attackerId >= 1000) { + int16 charId = _teamCharId[attackerId - 1000]; + if (charId == -1) deathType = 0; else { - int16 itemId = _mapMonsters[_teamMonsterIdArray[victimId]]._weaponItemId; - deathType = _items[itemId]._attackType; + int16 exclusiveItemId = getEquippedExclusiveType(charId, 9, true); + if (exclusiveItemId == 0x7FFF) + deathType = 0; + else + deathType = _items[exclusiveItemId]._attackType + 1; } + } else if (_teamMonsterIdArray[attackerId] == -1) + deathType = 0; + else { + int16 itemId = _mapMonsters[_teamMonsterIdArray[attackerId]]._weaponItemId; + deathType = _items[itemId]._attackType + 1; } - int16 rndDescrForDeathType = getRandom((3)) - 1; + int16 rndDescrForDeathType = getRandom((3)) - 1; // [0..2] Common::String tmpStr = "DUDE IS TOAST!"; switch (deathType) { case 0: From ddb0cc8dbe6d972d4745a8d0dc2965be1af181b0 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sat, 14 Jan 2023 17:39:30 +0100 Subject: [PATCH 242/412] EFH: rename determineTeamTarget(), fix issues in it --- engines/efh/efh.h | 2 +- engines/efh/fight.cpp | 56 +++++++++++++++++++++---------------------- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 4e0a067fd021..e59f9890e009 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -389,7 +389,7 @@ class EfhEngine : public Engine { void resetTeamMonsterIdArray(); bool isTeamMemberStatusNormal(int16 id); void getDeathTypeDescription(int16 victimId, int16 attackerId); - int16 sub1C956(int16 charId, int16 unkFied18Val, bool arg4); + int16 determineTeamTarget(int16 charId, int16 unkFied18Val, bool checkDistanceFl); bool sub1CB27(); void drawCombatScreen(int16 charId, bool whiteFl, bool drawFl); void getXPAndSearchCorpse(int16 charId, Common::String namePt1, Common::String namePt2, int16 monsterId); diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index ed7e58b7e76e..bdcba0de6ffd 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -983,31 +983,32 @@ void EfhEngine::getDeathTypeDescription(int16 victimId, int16 attackerId) { _messageToBePrinted += tmpStr; } -int16 EfhEngine::sub1C956(int16 charId, int16 unkFied18Val, bool arg4) { - debug("sub1C956 %d %d %d", charId, unkFied18Val, arg4); +int16 EfhEngine::determineTeamTarget(int16 charId, int16 unkFied18Val, bool checkDistanceFl) { + debug("determineTeamTarget %d %d %d", charId, unkFied18Val, checkDistanceFl); - int16 varE = -1; + int16 retVal = -1; int16 curItemId = getEquippedExclusiveType(charId, unkFied18Val, true); - int16 range = 0; + int16 rangeType = 0; + int16 realRange = 0; if (curItemId != 0x7FFF) - range = _items[curItemId]._range; + rangeType = _items[curItemId]._range; - switch (range) { + switch (rangeType) { case 3: case 2: - ++range; + ++realRange; // no break on purpose case 1: - ++range; + ++realRange; // no break on purpose case 0: - ++range; + ++realRange; break; case 4: return 100; default: - return varE; + return retVal; } do { @@ -1020,26 +1021,25 @@ int16 EfhEngine::sub1C956(int16 charId, int16 unkFied18Val, bool arg4) { displayFctFullScreen(); } - if (_teamMonsterIdArray[1] == -1) - varE = 0; - else - varE = selectMonsterGroup(); - - if (!arg4) { - if (varE == 27) // Esc - varE = 0; - } else if (varE != 27) { - int16 monsterGroupDistance = computeMonsterGroupDistance(_teamMonsterIdArray[varE]); - if (monsterGroupDistance > range) { - varE = 27; + retVal = (_teamMonsterIdArray[1] == -1) ? 0 : selectMonsterGroup(); + + if (!checkDistanceFl) { + if (retVal == 27) // Esc + retVal = 0; + } else if (retVal != 27) { + int16 monsterGroupDistance = computeMonsterGroupDistance(_teamMonsterIdArray[retVal]); + if (monsterGroupDistance > realRange) { + retVal = 27; + displayBoxWithText("That Group Is Out Of Range!", 3, 1, false); + getLastCharAfterAnimCount(_guessAnimationAmount); } } - } while (varE == -1); + } while (retVal == -1); - if (varE == 27) - varE = -1; + if (retVal == 27) + retVal = -1; - return varE; + return retVal; } bool EfhEngine::sub1CB27() { @@ -1058,7 +1058,7 @@ bool EfhEngine::sub1CB27() { switch (handleAndMapInput(true)) { case Common::KEYCODE_a: // Attack _teamLastAction[charId] = 'A'; - _teamNextAttack[charId] = sub1C956(_teamCharId[charId], 9, true); + _teamNextAttack[charId] = determineTeamTarget(_teamCharId[charId], 9, true); if (_teamNextAttack[charId] == -1) _teamLastAction[charId] = 0; break; @@ -1096,7 +1096,7 @@ bool EfhEngine::sub1CB27() { case 10: case 12: case 13: - _teamNextAttack[charId] = sub1C956(_teamCharId[charId], 9, false); + _teamNextAttack[charId] = determineTeamTarget(_teamCharId[charId], 9, false); break; case 9: From e8fed6ff3bdddd981e2276583bb56c9f0e6e9cd9 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sat, 14 Jan 2023 23:30:47 +0100 Subject: [PATCH 243/412] EFH: Validate 4 more functions, fix a bug in chooseCharacterToReplace() --- engines/efh/efh.cpp | 6 +++--- engines/efh/fight.cpp | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 119f8336795a..2633022dfa28 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -1008,13 +1008,13 @@ bool EfhEngine::giveItemTo(int16 charId, int16 objectId, int16 fromCharId) { } int16 EfhEngine::chooseCharacterToReplace() { - debug("chooseCharacterToReplace"); + debugC(3, kDebugEngine, "chooseCharacterToReplace"); Common::KeyCode maxVal = (Common::KeyCode)(Common::KEYCODE_0 + _teamSize); Common::KeyCode input; for (;;) { input = waitForKey(); - if (input == Common::KEYCODE_ESCAPE || input == Common::KEYCODE_0 || (input > Common::KEYCODE_1 && input <= maxVal)) + if (input == Common::KEYCODE_ESCAPE || input == Common::KEYCODE_0 || (input > Common::KEYCODE_1 && input < maxVal)) break; } @@ -1025,7 +1025,7 @@ int16 EfhEngine::chooseCharacterToReplace() { } int16 EfhEngine::handleCharacterJoining() { - debug("handleCharacterJoining"); + debugC(3, kDebugEngine, "handleCharacterJoining"); for (uint counter = 0; counter < 3; ++counter) { if (_teamCharId[counter] == -1) { diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index bdcba0de6ffd..d5f7e7ddf1f2 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -135,7 +135,7 @@ bool EfhEngine::handleFight(int16 monsterId) { int16 monsterGroupIdOrMonsterId = _initiatives[counter]._id; if (monsterGroupIdOrMonsterId == -1) continue; - if (monsterGroupIdOrMonsterId > 999) { // Team Member + if (monsterGroupIdOrMonsterId >= 1000) { // Magic number which determines if it's a Team Member monsterGroupIdOrMonsterId -= 1000; if (!isTeamMemberStatusNormal(monsterGroupIdOrMonsterId)) { handleFight_checkEndEffect(monsterGroupIdOrMonsterId); @@ -379,7 +379,7 @@ bool EfhEngine::handleFight(int16 monsterId) { } void EfhEngine::handleFight_checkEndEffect(int16 charId) { - debug("handleFight_checkEndEffect %d", charId); + debugC(3, kDebugFight, "handleFight_checkEndEffect %d", charId); // In the original, this function is part of handleFight. // It has been split for readability purposes. @@ -984,7 +984,7 @@ void EfhEngine::getDeathTypeDescription(int16 victimId, int16 attackerId) { } int16 EfhEngine::determineTeamTarget(int16 charId, int16 unkFied18Val, bool checkDistanceFl) { - debug("determineTeamTarget %d %d %d", charId, unkFied18Val, checkDistanceFl); + debugC(3, kDebugFight, "determineTeamTarget %d %d %d", charId, unkFied18Val, checkDistanceFl); int16 retVal = -1; From b9424bd35d28ed9220cdc4def83607428bb6b699 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sun, 15 Jan 2023 09:28:12 +0100 Subject: [PATCH 244/412] EFH: Add safeguards in transitionMap() and setSpecialTechZone(), move selectMonsterGroup() to fight.cpp, validate some more functions and renaming --- engines/efh/efh.cpp | 68 ++++++++++++++---------------------------- engines/efh/efh.h | 4 +-- engines/efh/fight.cpp | 28 +++++++++++++++++ engines/efh/script.cpp | 2 +- 4 files changed, 53 insertions(+), 49 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 2633022dfa28..5044ff8dd7d1 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -1102,7 +1102,7 @@ void EfhEngine::displayMiddleLeftTempText(uint8 *impArray, bool flag) { } void EfhEngine::transitionMap(int16 centerX, int16 centerY) { - debug("transitionMap %d %d", centerX, centerY); + debugC(2, kDebugEngine, "transitionMap %d %d", centerX, centerY); _drawHeroOnMapFl = false; int16 minX = centerX - 11; @@ -1117,7 +1117,9 @@ void EfhEngine::transitionMap(int16 centerX, int16 centerY) { for (uint counterY = 0; counterY <= 23; ++counterY) { int16 curX = counterX + minX; int16 curY = counterY + minY; - _mapGameMap[curX][curY] = _curPlace[counterX][counterY]; + + if (curX < 64 && curY < 64) + _mapGameMap[curX][curY] = _curPlace[counterX][counterY]; } drawScreen(); } @@ -1126,7 +1128,9 @@ void EfhEngine::transitionMap(int16 centerX, int16 centerY) { for (uint counterY = 0; counterY <= 23; ++counterY) { int16 curX = counterX + minX; int16 curY = counterY + minY; - _mapGameMap[curX][curY] = _curPlace[counterX][counterY]; + + if (curX < 64 && curY < 64) + _mapGameMap[curX][curY] = _curPlace[counterX][counterY]; } drawScreen(); } @@ -1135,25 +1139,25 @@ void EfhEngine::transitionMap(int16 centerX, int16 centerY) { _drawHeroOnMapFl = true; } -void EfhEngine::sub2455E(int16 arg0, int16 arg2, int16 arg4) { - debug("sub2455E %d %d %d", arg0, arg2, arg4); +void EfhEngine::setSpecialTechZone(int16 unkId, int16 centerX, int16 centerY) { + debugC(2, kDebugEngine, "setSpecialTechZone %d %d %d", unkId, centerX, centerY); - uint8 varD = kByte2C7D0[arg0]; - int16 varC = arg2 - 11; - int16 varA = arg4 - 11; + if (unkId < 0 || unkId >= 60) + error("setSpecialTechZone - unexpected value for unkId: %d", unkId); - if (varC < 0) - varC = 0; + uint8 zoneValue = kByte2C7D0[unkId]; - if (varA < 0) - varA = 0; + // Added a CLIP as a safeguard to avoid any value larger than 64 + int16 minX = CLIP(centerX - 11, 0, 64); + int16 minY = CLIP(centerY - 11, 0, 64); - int16 var8 = varC + 23; - int16 var6 = varA + 23; - for (int16 var4 = varC; var4 <= var8; ++var4) { - for (int16 var2 = varA; var2 <= var6; ++var2) { - WRITE_LE_INT16(&_techDataArr[_techId][var2 + var4 * 64], varD); + int16 maxX = CLIP(minX + 23, 0, 64); + int16 maxY = CLIP(minY + 23,0, 64); + + for (int16 counterX = minX; counterX <= maxX; ++counterX) { + for (int16 counterY = minY; counterY <= maxY; ++counterY) { + _techDataArr[_techId][counterY + counterX * 64] = zoneValue; } } } @@ -2296,7 +2300,7 @@ void EfhEngine::computeInitiatives() { } void EfhEngine::redrawScreenForced() { - debug("redrawScreenForced"); + debugC(3, kDebugEngine,"redrawScreenForced"); for (uint counter = 0; counter < 2; ++counter) { drawScreen(); @@ -2305,34 +2309,6 @@ void EfhEngine::redrawScreenForced() { } } -int16 EfhEngine::selectMonsterGroup() { - debug("selectMonsterGroup"); - - int16 retVal = -1; - - while (retVal == -1) { - Common::KeyCode input = handleAndMapInput(true); - switch (input) { - case Common::KEYCODE_ESCAPE: - retVal = 27; - break; - case Common::KEYCODE_a: - case Common::KEYCODE_b: - case Common::KEYCODE_c: - case Common::KEYCODE_d: - case Common::KEYCODE_e: - retVal = input - Common::KEYCODE_a; - if (_teamMonsterIdArray[retVal] == -1) - retVal = -1; - break; - default: - break; - } - } - - return retVal; -} - void EfhEngine::sub1CAB6(int16 charId) { debug("sub1CAB6 %d", charId); diff --git a/engines/efh/efh.h b/engines/efh/efh.h index e59f9890e009..d96cf981885f 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -322,7 +322,7 @@ class EfhEngine : public Engine { void drawText(uint8 *impPtr, int16 posX, int16 posY, int16 maxX, int16 maxY, bool flag); void displayMiddleLeftTempText(uint8 *impArray, bool flag); void transitionMap(int16 centerX, int16 centerY); - void sub2455E(int16 arg0, int16 arg1, int16 arg2); + void setSpecialTechZone(int16 unkId, int16 arg1, int16 arg2); int16 findMapSpecialTileIndex(int16 posX, int16 posY); bool isPosOutOfMap(int16 mapPosX, int16 mapPosY); void goSouth(); @@ -360,7 +360,6 @@ class EfhEngine : public Engine { int8 checkTileStatus(int16 mapPosX, int16 mapPosY, bool arg4); void computeInitiatives(); void redrawScreenForced(); - int16 selectMonsterGroup(); void sub1CAB6(int16 charId); int16 countMonsterGroupMembers(int16 monsterGroup); void sub1D8C2(int16 charId, int16 damage); @@ -403,6 +402,7 @@ class EfhEngine : public Engine { bool hasAdequateDefenseNPC(int16 charId, uint8 attackType); void addNewOpponents(int16 monsterId); int16 getTeamMonsterAnimId(); + int16 selectMonsterGroup(); // Files int32 readFileToBuffer(Common::String &filename, uint8 *destBuffer); diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index d5f7e7ddf1f2..6f72af04ad9c 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -1671,4 +1671,32 @@ int16 EfhEngine::getTeamMonsterAnimId() { return retVal; } +int16 EfhEngine::selectMonsterGroup() { + debugC(3, kDebugFight, "selectMonsterGroup"); + + int16 retVal = -1; + + while (retVal == -1) { + Common::KeyCode input = handleAndMapInput(true); + switch (input) { + case Common::KEYCODE_ESCAPE: + retVal = 27; + break; + case Common::KEYCODE_a: + case Common::KEYCODE_b: + case Common::KEYCODE_c: + case Common::KEYCODE_d: + case Common::KEYCODE_e: + retVal = input - Common::KEYCODE_a; + if (_teamMonsterIdArray[retVal] == -1) + retVal = -1; + break; + default: + break; + } + } + + return retVal; +} + } // End of namespace Efh diff --git a/engines/efh/script.cpp b/engines/efh/script.cpp index ca57a000d01c..dfcb27bf0e09 100644 --- a/engines/efh/script.cpp +++ b/engines/efh/script.cpp @@ -324,7 +324,7 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos _word2C87A = true; loadPlacesFile(scriptNumberArray[0], false); transitionMap(scriptNumberArray[1], scriptNumberArray[2]); - sub2455E(scriptNumberArray[0], scriptNumberArray[1], scriptNumberArray[2]); + setSpecialTechZone(scriptNumberArray[0], scriptNumberArray[1], scriptNumberArray[2]); retVal = -1; } break; From adc85ef1859c400cb730707a6f63ee6991907224 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sun, 15 Jan 2023 10:58:10 +0100 Subject: [PATCH 245/412] EFH: More validations and renaming --- engines/efh/efh.cpp | 12 ------------ engines/efh/efh.h | 4 ++-- engines/efh/fight.cpp | 30 +++++++++++++++++++++--------- engines/efh/init.cpp | 2 +- engines/efh/menu.cpp | 4 ++-- 5 files changed, 26 insertions(+), 26 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 5044ff8dd7d1..f5e1e464b04e 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -2309,18 +2309,6 @@ void EfhEngine::redrawScreenForced() { } } -void EfhEngine::sub1CAB6(int16 charId) { - debug("sub1CAB6 %d", charId); - - for (uint counter = 0; counter < 2; ++counter) { - drawGameScreenAndTempText(false); - displayLowStatusScreen(false); - drawCombatScreen(charId, false, false); - if (counter == 0) - displayFctFullScreen(); - } -} - int16 EfhEngine::countMonsterGroupMembers(int16 monsterGroup) { debugC(9, kDebugEngine, "countMonsterGroupMembers %d", monsterGroup); diff --git a/engines/efh/efh.h b/engines/efh/efh.h index d96cf981885f..78780b31c5b7 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -360,7 +360,6 @@ class EfhEngine : public Engine { int8 checkTileStatus(int16 mapPosX, int16 mapPosY, bool arg4); void computeInitiatives(); void redrawScreenForced(); - void sub1CAB6(int16 charId); int16 countMonsterGroupMembers(int16 monsterGroup); void sub1D8C2(int16 charId, int16 damage); int16 getXPLevel(int32 xp); @@ -403,6 +402,7 @@ class EfhEngine : public Engine { void addNewOpponents(int16 monsterId); int16 getTeamMonsterAnimId(); int16 selectMonsterGroup(); + void redrawCombatScreenWithTempText(int16 charId); // Files int32 readFileToBuffer(Common::String &filename, uint8 *destBuffer); @@ -605,7 +605,7 @@ class EfhEngine : public Engine { int16 _teamPctVisible[3]; int16 _teamPctDodgeMiss[3]; int16 _teamNextAttack[3]; - int16 _word31780[3]; + int16 _teamLastInventoryUsed[3]; int16 _menuStatItemArr[15]; TeamMonsterEffect _teamMonsterEffects[5]; diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index 6f72af04ad9c..fe2addd77c94 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -671,7 +671,7 @@ bool EfhEngine::handleFight_lastAction_U(int16 teamCharId) { // It has been split for readability purposes. debugC(3, kDebugFight, "handleFight_lastAction_U %d", teamCharId); - int16 itemId = _npcBuf[_teamCharId[teamCharId]]._inventory[_word31780[teamCharId]]._ref; + int16 itemId = _npcBuf[_teamCharId[teamCharId]]._inventory[_teamLastInventoryUsed[teamCharId]]._ref; _enemyNamePt2 = _npcBuf[_teamCharId[teamCharId]]._name; _nameBuffer = _items[itemId]._name; int16 pronoun = _npcBuf[_teamCharId[teamCharId]].getPronoun(); @@ -681,7 +681,7 @@ bool EfhEngine::handleFight_lastAction_U(int16 teamCharId) { _enemyNamePt1 = ""; _messageToBePrinted = Common::String::format("%s%s uses %s %s! ", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPossessive[pronoun], _nameBuffer.c_str()); - bool retVal = useObject(_teamCharId[teamCharId], _word31780[teamCharId], _teamNextAttack[teamCharId], teamCharId, 0, 3); + bool retVal = useObject(_teamCharId[teamCharId], _teamLastInventoryUsed[teamCharId], _teamNextAttack[teamCharId], teamCharId, 0, 3); displayBoxWithText(_messageToBePrinted, 1, 2, true); return retVal; @@ -1074,15 +1074,15 @@ bool EfhEngine::sub1CB27() { } return true; case Common::KEYCODE_s: { // Status - int16 var8 = handleStatusMenu(2, _teamCharId[charId]); - sub1CAB6(_teamCharId[charId]); - if (var8 > 999) { - if (var8 == 0x7D00) + int16 lastInvId = handleStatusMenu(2, _teamCharId[charId]); + redrawCombatScreenWithTempText(_teamCharId[charId]); + if (lastInvId >= 999) { + if (lastInvId == 0x7D00) // Result of Equip, Give and Drop in combat mode(2) _teamLastAction[charId] = 'S'; } else { _teamLastAction[charId] = 'U'; - _word31780[charId] = var8; - int16 invEffect = _items[_npcBuf[_teamCharId[charId]]._inventory[var8]._ref]._specialEffect; + _teamLastInventoryUsed[charId] = lastInvId; + int16 invEffect = _items[_npcBuf[_teamCharId[charId]]._inventory[lastInvId]._ref]._specialEffect; switch (invEffect - 1) { case 0: case 1: @@ -1126,7 +1126,7 @@ bool EfhEngine::sub1CB27() { case 22: case 23: default: - _word31780[charId] = var8; + _teamLastInventoryUsed[charId] = lastInvId; _teamNextAttack[charId] = -1; break; } @@ -1699,4 +1699,16 @@ int16 EfhEngine::selectMonsterGroup() { return retVal; } +void EfhEngine::redrawCombatScreenWithTempText(int16 charId) { + debugC(3, kDebugFight, "redrawCombatScreenWithTempText %d", charId); + + for (uint counter = 0; counter < 2; ++counter) { + drawGameScreenAndTempText(false); + displayLowStatusScreen(false); + drawCombatScreen(charId, false, false); + if (counter == 0) + displayFctFullScreen(); + } +} + } // End of namespace Efh diff --git a/engines/efh/init.cpp b/engines/efh/init.cpp index 99dfcca0681b..f17d8eb67112 100644 --- a/engines/efh/init.cpp +++ b/engines/efh/init.cpp @@ -254,7 +254,7 @@ EfhEngine::EfhEngine(OSystem *syst, const ADGameDescription *gd) : Engine(syst), _teamPctVisible[i] = 0; _teamPctDodgeMiss[i] = 0; _teamNextAttack[i] = -1; - _word31780[i] = 0; + _teamLastInventoryUsed[i] = 0; _teamLastAction[i] = 0; } diff --git a/engines/efh/menu.cpp b/engines/efh/menu.cpp index b1d9dcd7914f..0661e0e7f87f 100644 --- a/engines/efh/menu.cpp +++ b/engines/efh/menu.cpp @@ -486,7 +486,7 @@ void EfhEngine::displayWindowAndStatusMenu(int16 charId, int16 windowId, int16 m } int16 EfhEngine::displayStringInSmallWindowWithBorder(Common::String str, bool delayFl, int16 charId, int16 windowId, int16 menuId, int16 curMenuLine) { - debug("displayStringInSmallWindowWithBorder %s %s %d %d %d %d", str.c_str(), delayFl ? "True" : "False", charId, windowId, menuId, curMenuLine); + debugC(3, kDebugEngine, "displayStringInSmallWindowWithBorder %s %s %d %d %d %d", str.c_str(), delayFl ? "True" : "False", charId, windowId, menuId, curMenuLine); int16 retVal = 0; @@ -500,7 +500,7 @@ int16 EfhEngine::displayStringInSmallWindowWithBorder(Common::String str, bool d retVal = script_parse(str, 28, 122, 105, 166, true); } // The original is only calling displayFctFullScreen when counter = 0, but it's related to the screen buffers which aren't used in ScummVM implementation - // Calling it once fix the almost unreadable text displayed otherwise. + // Calling it once fixes the (almost) unreadable text displayed otherwise. // Maybe a refactoring to remove those 0..1 loop would be useful at some point. displayFctFullScreen(); } From ba52ee0cc7cc5e46a386e22769b354e01a907221 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sun, 15 Jan 2023 14:10:33 +0100 Subject: [PATCH 246/412] EFH: rename handleDamageOnArmor() and getTeamAttackRoundPlans(), validate two functions --- engines/efh/efh.cpp | 8 ++++---- engines/efh/efh.h | 4 ++-- engines/efh/fight.cpp | 9 ++++----- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index f5e1e464b04e..8613b873f297 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -2321,8 +2321,8 @@ int16 EfhEngine::countMonsterGroupMembers(int16 monsterGroup) { return result; } -void EfhEngine::sub1D8C2(int16 charId, int16 damage) { - debug("sub1D8C2 %d %d", charId, damage); +void EfhEngine::handleDamageOnArmor(int16 charId, int16 damage) { + debugC(3, kDebugEngine, "handleDamageOnArmor %d %d", charId, damage); int16 destroyCounter = 0; int16 pronoun = _npcBuf[charId].getPronoun(); @@ -2347,12 +2347,12 @@ void EfhEngine::sub1D8C2(int16 charId, int16 damage) { removeObject(charId, objectId); if (destroyCounter == 0) { - destroyCounter = 1; _messageToBePrinted += Common::String::format(", but %s ", kPossessive[pronoun]) + buffer2; } else { - ++destroyCounter; _messageToBePrinted += Common::String(", ") + buffer2; } + + ++destroyCounter; } if (remainingDamage > 0) diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 78780b31c5b7..2b148a372994 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -361,7 +361,7 @@ class EfhEngine : public Engine { void computeInitiatives(); void redrawScreenForced(); int16 countMonsterGroupMembers(int16 monsterGroup); - void sub1D8C2(int16 charId, int16 damage); + void handleDamageOnArmor(int16 charId, int16 damage); int16 getXPLevel(int32 xp); bool isItemCursed(int16 itemId); bool hasObjectEquipped(int16 charId, int16 objectId); @@ -388,7 +388,7 @@ class EfhEngine : public Engine { bool isTeamMemberStatusNormal(int16 id); void getDeathTypeDescription(int16 victimId, int16 attackerId); int16 determineTeamTarget(int16 charId, int16 unkFied18Val, bool checkDistanceFl); - bool sub1CB27(); + bool getTeamAttackRoundPlans(); void drawCombatScreen(int16 charId, bool whiteFl, bool drawFl); void getXPAndSearchCorpse(int16 charId, Common::String namePt1, Common::String namePt2, int16 monsterId); bool characterSearchesMonsterCorpse(int16 charId, int16 monsterId); diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index fe2addd77c94..1c0c2110efa8 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -115,7 +115,7 @@ bool EfhEngine::handleFight(int16 monsterId) { _teamPctDodgeMiss[counter] = 65; } - if (!sub1CB27()) { + if (!getTeamAttackRoundPlans()) { resetTeamMonsterIdArray(); _ongoingFightFl = false; totalPartyKill(); @@ -299,7 +299,7 @@ bool EfhEngine::handleFight(int16 monsterId) { _messageToBePrinted += Common::String::format(" %s%s's armor absorbs %d points!", _characterNamePt1.c_str(), _characterNamePt2.c_str(), damagePointsAbsorbed); varInt = (originalDamage + damagePointsAbsorbed) / 10; - sub1D8C2(_teamCharId[var7E], varInt); + handleDamageOnArmor(_teamCharId[var7E], varInt); } // handleFight - Check armor - end @@ -1042,9 +1042,8 @@ int16 EfhEngine::determineTeamTarget(int16 charId, int16 unkFied18Val, bool chec return retVal; } -bool EfhEngine::sub1CB27() { - debugC(3, kDebugFight, "sub1CB27"); - warning("To be renamed: sub1CB27"); +bool EfhEngine::getTeamAttackRoundPlans() { + debugC(3, kDebugFight, "getTeamAttackRoundPlans"); bool retVal = false; for (int charId = 0; charId < _teamSize; ++charId) { From a0ae5cb427bfc0505e0e00cee7acd026c1523a5c Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sun, 15 Jan 2023 14:12:13 +0100 Subject: [PATCH 247/412] EFH: Move handleDamageOnArmor to fight.cpp --- engines/efh/efh.cpp | 52 ------------------------------------------- engines/efh/efh.h | 2 +- engines/efh/fight.cpp | 51 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 53 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 8613b873f297..49cca4b41896 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -2321,58 +2321,6 @@ int16 EfhEngine::countMonsterGroupMembers(int16 monsterGroup) { return result; } -void EfhEngine::handleDamageOnArmor(int16 charId, int16 damage) { - debugC(3, kDebugEngine, "handleDamageOnArmor %d %d", charId, damage); - - int16 destroyCounter = 0; - int16 pronoun = _npcBuf[charId].getPronoun(); - - if (pronoun > 2) { - pronoun = 2; - } - - int16 curDamage = CLIP(damage, 0, 50); - - for (uint objectId = 0; objectId < 10; ++objectId) { - if (_npcBuf[charId]._inventory[objectId]._ref == 0x7FFF || !_npcBuf[charId]._inventory[objectId].isEquipped() || _items[_npcBuf[charId]._inventory[objectId]._ref]._defense == 0) - continue; - - int16 remainingDamage = curDamage - _npcBuf[charId]._inventory[objectId]._curHitPoints; - // not in the original: this int16 is used to test if the result is negative. Otherwise _curHitPoints (uint8) turns it into a "large" positive value. - int16 newDurability = _npcBuf[charId]._inventory[objectId]._curHitPoints - curDamage; - _npcBuf[charId]._inventory[objectId]._curHitPoints = newDurability; - - if (newDurability <= 0) { - Common::String buffer2 = _items[_npcBuf[charId]._inventory[objectId]._ref]._name; - removeObject(charId, objectId); - - if (destroyCounter == 0) { - _messageToBePrinted += Common::String::format(", but %s ", kPossessive[pronoun]) + buffer2; - } else { - _messageToBePrinted += Common::String(", ") + buffer2; - } - - ++destroyCounter; - } - - if (remainingDamage > 0) - curDamage = remainingDamage; - // The original doesn't contain this Else clause. But logically, if the remainingDamage is less than 0, it doesn't make sense to keep damaging equipment with the previous damage. - // As it looks like an original bug, I just added the code to stop damaging equipped protections. - else - break; - } - - if (destroyCounter == 0) { - _messageToBePrinted += "!"; - } else if (destroyCounter > 1 || _messageToBePrinted.lastChar() == 's' || _messageToBePrinted.lastChar() == 'S') { - _messageToBePrinted += " are destroyed!"; - } else { - _messageToBePrinted += " is destroyed!"; - } -} - - int16 EfhEngine::getXPLevel(int32 xp) { debugC(6, kDebugEngine, "getXPLevel %ld", xp); diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 2b148a372994..94137f0bd4c3 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -361,7 +361,6 @@ class EfhEngine : public Engine { void computeInitiatives(); void redrawScreenForced(); int16 countMonsterGroupMembers(int16 monsterGroup); - void handleDamageOnArmor(int16 charId, int16 damage); int16 getXPLevel(int32 xp); bool isItemCursed(int16 itemId); bool hasObjectEquipped(int16 charId, int16 objectId); @@ -403,6 +402,7 @@ class EfhEngine : public Engine { int16 getTeamMonsterAnimId(); int16 selectMonsterGroup(); void redrawCombatScreenWithTempText(int16 charId); + void handleDamageOnArmor(int16 charId, int16 damage); // Files int32 readFileToBuffer(Common::String &filename, uint8 *destBuffer); diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index 1c0c2110efa8..e181e8a79016 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -1710,4 +1710,55 @@ void EfhEngine::redrawCombatScreenWithTempText(int16 charId) { } } +void EfhEngine::handleDamageOnArmor(int16 charId, int16 damage) { + debugC(3, kDebugFight, "handleDamageOnArmor %d %d", charId, damage); + + int16 destroyCounter = 0; + int16 pronoun = _npcBuf[charId].getPronoun(); + + if (pronoun > 2) { + pronoun = 2; + } + + int16 curDamage = CLIP(damage, 0, 50); + + for (uint objectId = 0; objectId < 10; ++objectId) { + if (_npcBuf[charId]._inventory[objectId]._ref == 0x7FFF || !_npcBuf[charId]._inventory[objectId].isEquipped() || _items[_npcBuf[charId]._inventory[objectId]._ref]._defense == 0) + continue; + + int16 remainingDamage = curDamage - _npcBuf[charId]._inventory[objectId]._curHitPoints; + // not in the original: this int16 is used to test if the result is negative. Otherwise _curHitPoints (uint8) turns it into a "large" positive value. + int16 newDurability = _npcBuf[charId]._inventory[objectId]._curHitPoints - curDamage; + _npcBuf[charId]._inventory[objectId]._curHitPoints = newDurability; + + if (newDurability <= 0) { + Common::String buffer2 = _items[_npcBuf[charId]._inventory[objectId]._ref]._name; + removeObject(charId, objectId); + + if (destroyCounter == 0) { + _messageToBePrinted += Common::String::format(", but %s ", kPossessive[pronoun]) + buffer2; + } else { + _messageToBePrinted += Common::String(", ") + buffer2; + } + + ++destroyCounter; + } + + if (remainingDamage > 0) + curDamage = remainingDamage; + // The original doesn't contain this Else clause. But logically, if the remainingDamage is less than 0, it doesn't make sense to keep damaging equipment with the previous damage. + // As it looks like an original bug, I just added the code to stop damaging equipped protections. + else + break; + } + + if (destroyCounter == 0) { + _messageToBePrinted += "!"; + } else if (destroyCounter > 1 || _messageToBePrinted.lastChar() == 's' || _messageToBePrinted.lastChar() == 'S') { + _messageToBePrinted += " are destroyed!"; + } else { + _messageToBePrinted += " is destroyed!"; + } +} + } // End of namespace Efh From 6e402815eff89e5b429f7e8d6fa375c27955be91 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sun, 15 Jan 2023 22:22:43 +0100 Subject: [PATCH 248/412] EFH: Validate 3 more functions --- engines/efh/efh.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 49cca4b41896..e0b3f312f38d 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -2381,7 +2381,7 @@ bool EfhEngine::isMonsterActive(int16 groupId, int16 id) { } int16 EfhEngine::getTileFactId(int16 mapPosX, int16 mapPosY) { - debug("getTileFactId %d-%d", mapPosX, mapPosY); + debugC(3, kDebugEngine, "getTileFactId %d-%d", mapPosX, mapPosY); int16 curTileInfo = getMapTileInfo(mapPosX, mapPosY); int16 imageSetId = _currentTileBankImageSetId[curTileInfo / 72] * 72; @@ -2391,13 +2391,13 @@ int16 EfhEngine::getTileFactId(int16 mapPosX, int16 mapPosY) { } void EfhEngine::setCharacterObjectToBroken(int16 charId, int16 objectId) { - debug("setCharacterObjectToBroken %d %d", charId, objectId); + debugC(3, kDebugEngine, "setCharacterObjectToBroken %d %d", charId, objectId); _npcBuf[charId]._inventory[objectId]._ref = 0x7FFF; } int16 EfhEngine::selectOtherCharFromTeam() { - debug("selectOtherCharFromTeam"); + debugC(3, kDebugEngine, "selectOtherCharFromTeam"); Common::KeyCode maxVal = (Common::KeyCode) (Common::KEYCODE_0 + _teamSize); Common::KeyCode input = Common::KEYCODE_INVALID; From 8f7bf6b26529861a124b1d43d4ed9f1b2a2b835e Mon Sep 17 00:00:00 2001 From: Strangerke Date: Mon, 16 Jan 2023 01:59:19 +0100 Subject: [PATCH 249/412] EFH: rewrite the pre-loading of "map" files, related refactoring --- engines/efh/efh.cpp | 313 +++++++++++++++++--------------------- engines/efh/efh.h | 15 +- engines/efh/fight.cpp | 88 +++++------ engines/efh/files.cpp | 54 ++++++- engines/efh/init.cpp | 69 ++++++++- engines/efh/menu.cpp | 16 +- engines/efh/savegames.cpp | 89 ++++------- engines/efh/script.cpp | 14 +- 8 files changed, 350 insertions(+), 308 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index e0b3f312f38d..73ff6b5e8a78 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -506,13 +506,13 @@ void EfhEngine::initMapMonsters() { debugC(3, kDebugEngine, "initMapMonsters"); for (uint monsterId = 0; monsterId < 64; ++monsterId) { - if (_mapMonsters[monsterId]._fullPlaceId == 0xFF) + if (_mapMonsters[_techId][monsterId]._fullPlaceId == 0xFF) continue; for (uint counter = 0; counter < 9; ++counter) - _mapMonsters[monsterId]._hitPoints[counter] = 0; + _mapMonsters[_techId][monsterId]._hitPoints[counter] = 0; - uint8 groupSize = _mapMonsters[monsterId]._groupSize; + uint8 groupSize = _mapMonsters[_techId][monsterId]._groupSize; if (groupSize == 0) groupSize = getRandom(10) - 1; @@ -521,60 +521,23 @@ void EfhEngine::initMapMonsters() { for (uint counter = 0; counter < groupSize; ++counter) { uint rand100 = getRandom(100); - uint16 pictureRef = kEncounters[_mapMonsters[monsterId]._monsterRef]._pictureRef; + uint16 pictureRef = kEncounters[_mapMonsters[_techId][monsterId]._monsterRef]._pictureRef; if (rand100 <= 25) { uint16 delta = getRandom(pictureRef / 2); - _mapMonsters[monsterId]._hitPoints[counter] = pictureRef - delta; + _mapMonsters[_techId][monsterId]._hitPoints[counter] = pictureRef - delta; } else if (rand100 <= 75) { - _mapMonsters[monsterId]._hitPoints[counter] = pictureRef; + _mapMonsters[_techId][monsterId]._hitPoints[counter] = pictureRef; } else { uint16 delta = getRandom(pictureRef / 2); - _mapMonsters[monsterId]._hitPoints[counter] = pictureRef + delta; + _mapMonsters[_techId][monsterId]._hitPoints[counter] = pictureRef + delta; } } } } void EfhEngine::loadMapArrays(int idx) { - debugC(6, kDebugEngine, "loadMapArrays %d", idx); - debug("TODO : rewrite the pre-loading of data and loadMapArrays in order to avoid to lose info when changing map"); - - uint8 *mapSpecialTilePtr = &_mapArr[idx][2]; - - for (int i = 0; i < 100; ++i) { - _mapSpecialTile[i]._placeId = mapSpecialTilePtr[9 * i]; - _mapSpecialTile[i]._posX = mapSpecialTilePtr[9 * i + 1]; - _mapSpecialTile[i]._posY = mapSpecialTilePtr[9 * i + 2]; - _mapSpecialTile[i]._field3 = mapSpecialTilePtr[9 * i + 3]; - _mapSpecialTile[i]._triggerId = mapSpecialTilePtr[9 * i + 4]; - _mapSpecialTile[i]._field5_textId = READ_LE_UINT16(&mapSpecialTilePtr[9 * i + 5]); - _mapSpecialTile[i]._field7_textId = READ_LE_UINT16(&mapSpecialTilePtr[9 * i + 7]); - } - - uint8 *mapMonstersPtr = &_mapArr[idx][902]; - - for (int i = 0; i < 64; ++i) { - _mapMonsters[i]._possessivePronounSHL6 = mapMonstersPtr[29 * i]; - _mapMonsters[i]._npcId = mapMonstersPtr[29 * i + 1]; - _mapMonsters[i]._fullPlaceId = mapMonstersPtr[29 * i + 2]; - _mapMonsters[i]._posX = mapMonstersPtr[29 * i + 3]; - _mapMonsters[i]._posY = mapMonstersPtr[29 * i + 4]; - _mapMonsters[i]._weaponItemId = mapMonstersPtr[29 * i + 5]; - _mapMonsters[i]._maxDamageAbsorption = mapMonstersPtr[29 * i + 6]; - _mapMonsters[i]._monsterRef = mapMonstersPtr[29 * i + 7]; - _mapMonsters[i]._additionalInfo = mapMonstersPtr[29 * i + 8]; - _mapMonsters[i]._talkTextId = mapMonstersPtr[29 * i + 9]; - _mapMonsters[i]._groupSize = mapMonstersPtr[29 * i + 10]; - for (int j = 0; j < 9; ++j) - _mapMonsters[i]._hitPoints[j] = READ_LE_INT16(&mapMonstersPtr[29 * i + 11 + j * 2]); - } - - uint8 *mapPtr = &_mapArr[idx][2758]; - for (int i = 0; i < 64; ++i) { - for (int j = 0; j < 64; ++j) - _mapGameMap[i][j] = *mapPtr++; - } + // No longer required as everything is in memory. } void EfhEngine::saveAnimImageSetId() { @@ -703,7 +666,7 @@ void EfhEngine::drawMap(bool largeMapFl, int16 mapPosX, int16 mapPosY, int16 map int16 drawPosX = 128; for (int16 counterX = minX; counterX <= maxX; ++counterX) { if (largeMapFl) { - int16 curTile = _mapGameMap[counterX][counterY]; + int16 curTile = _mapGameMaps[_techId][counterX][counterY]; displayRawDataAtPos(_imageSetSubFilesArray[curTile], drawPosX, drawPosY); } else { int16 curTile = _curPlace[counterX][counterY]; @@ -723,26 +686,26 @@ void EfhEngine::drawMap(bool largeMapFl, int16 mapPosX, int16 mapPosY, int16 map if (drawMonstersFl) { for (uint var16 = 0; var16 < 64; ++var16) { - if ((_largeMapFlag && _mapMonsters[var16]._fullPlaceId == 0xFE) || (!_largeMapFlag && _mapMonsters[var16]._fullPlaceId == _fullPlaceId)){ + if ((_largeMapFlag && _mapMonsters[_techId][var16]._fullPlaceId == 0xFE) || (!_largeMapFlag && _mapMonsters[_techId][var16]._fullPlaceId == _fullPlaceId)){ bool var4 = false; - int16 posX = _mapMonsters[var16]._posX; - int16 posY = _mapMonsters[var16]._posY; + int16 posX = _mapMonsters[_techId][var16]._posX; + int16 posY = _mapMonsters[_techId][var16]._posY; if (posX < minX || posX > maxX || posY < minY || posY > maxY) continue; for (uint counterY = 0; counterY < 9 && !var4; ++counterY) { - if (_mapMonsters[var16]._hitPoints[counterY] > 0) + if (_mapMonsters[_techId][var16]._hitPoints[counterY] > 0) var4 = true; } if (!var4) continue; - int16 var6 = 148 + kEncounters[_mapMonsters[var16]._monsterRef]._animId; - int16 var1 = _mapMonsters[var16]._possessivePronounSHL6 & 0x3F; + int16 var6 = 148 + kEncounters[_mapMonsters[_techId][var16]._monsterRef]._animId; + int16 var1 = _mapMonsters[_techId][var16]._possessivePronounSHL6 & 0x3F; - if (var1 == 0x3F && isNpcATeamMember(_mapMonsters[var16]._npcId)) + if (var1 == 0x3F && isNpcATeamMember(_mapMonsters[_techId][var16]._npcId)) continue; int16 drawPosX = 128 + (posX - minX) * 16; @@ -1119,7 +1082,7 @@ void EfhEngine::transitionMap(int16 centerX, int16 centerY) { int16 curY = counterY + minY; if (curX < 64 && curY < 64) - _mapGameMap[curX][curY] = _curPlace[counterX][counterY]; + _mapGameMaps[_techId][curX][curY] = _curPlace[counterX][counterY]; } drawScreen(); } @@ -1130,7 +1093,7 @@ void EfhEngine::transitionMap(int16 centerX, int16 centerY) { int16 curY = counterY + minY; if (curX < 64 && curY < 64) - _mapGameMap[curX][curY] = _curPlace[counterX][counterY]; + _mapGameMaps[_techId][curX][curY] = _curPlace[counterX][counterY]; } drawScreen(); } @@ -1168,7 +1131,7 @@ int16 EfhEngine::findMapSpecialTileIndex(int16 posX, int16 posY) { uint16 searchPlaceId = _largeMapFlag ? 0xFE : _fullPlaceId; for (uint counter = 0; counter < 100; ++counter) { - if (_mapSpecialTile[counter]._posX == posX && _mapSpecialTile[counter]._posY == posY && _mapSpecialTile[counter]._placeId == searchPlaceId) + if (_mapSpecialTiles[_techId][counter]._posX == posX && _mapSpecialTiles[_techId][counter]._posY == posY && _mapSpecialTiles[_techId][counter]._placeId == searchPlaceId) return counter; } @@ -1371,13 +1334,13 @@ void EfhEngine::computeMapAnimation() { continue; if (_largeMapFlag) { - uint8 curTile = _mapGameMap[counterX][counterY]; + uint8 curTile = _mapGameMaps[_techId][counterX][counterY]; if (curTile >= 1 && curTile <= 0xF) { if (getRandom(100) < 50) - _mapGameMap[counterX][counterY] += 0xC5; + _mapGameMaps[_techId][counterX][counterY] += 0xC5; } else if (curTile >= 0xC6 && curTile <= 0xD5) { if (getRandom(100) < 50) - _mapGameMap[counterX][counterY] -= 0xC5; + _mapGameMaps[_techId][counterX][counterY] -= 0xC5; } } else { uint8 curTile = _curPlace[counterX][counterY]; @@ -1414,10 +1377,10 @@ int8 EfhEngine::checkMonsterMoveCollisionAndTileTexture(int16 monsterId) { debugC(3, kDebugEngine,"checkMonsterMoveCollisionAndTileTexture %d", monsterId); int16 maxSize = _largeMapFlag ? 63 : 23; - if (_mapMonsters[monsterId]._posX < 0 || _mapMonsters[monsterId]._posY < 0 || _mapMonsters[monsterId]._posX > maxSize || _mapMonsters[monsterId]._posY > maxSize) + if (_mapMonsters[_techId][monsterId]._posX < 0 || _mapMonsters[_techId][monsterId]._posY < 0 || _mapMonsters[_techId][monsterId]._posX > maxSize || _mapMonsters[_techId][monsterId]._posY > maxSize) return 0; - if (_mapMonsters[monsterId]._posX == _mapPosX && _mapMonsters[monsterId]._posY == _mapPosY) + if (_mapMonsters[_techId][monsterId]._posX == _mapPosX && _mapMonsters[_techId][monsterId]._posY == _mapPosY) return 0; for (int counter = 0; counter < 64; ++counter) { @@ -1427,43 +1390,43 @@ int8 EfhEngine::checkMonsterMoveCollisionAndTileTexture(int16 monsterId) { if (!checkMapMonsterAvailability(counter)) continue; - if (_mapMonsters[monsterId]._fullPlaceId == _mapMonsters[counter]._fullPlaceId - && _mapMonsters[monsterId]._posX == _mapMonsters[counter]._posX - && _mapMonsters[monsterId]._posY == _mapMonsters[counter]._posY) + if (_mapMonsters[_techId][monsterId]._fullPlaceId == _mapMonsters[_techId][counter]._fullPlaceId + && _mapMonsters[_techId][monsterId]._posX == _mapMonsters[_techId][counter]._posX + && _mapMonsters[_techId][monsterId]._posY == _mapMonsters[_techId][counter]._posY) return 0; } - return checkTileStatus(_mapMonsters[monsterId]._posX, _mapMonsters[monsterId]._posY, false); + return checkTileStatus(_mapMonsters[_techId][monsterId]._posX, _mapMonsters[_techId][monsterId]._posY, false); } bool EfhEngine::moveMonsterAwayFromTeam(int16 monsterId) { debugC(6, kDebugEngine, "moveMonsterAwayFromTeam %d", monsterId); - if (_mapMonsters[monsterId]._posX < _mapPosX) { - --_mapMonsters[monsterId]._posX; - if (_mapMonsters[monsterId]._posY < _mapPosY) - --_mapMonsters[monsterId]._posY; - else if (_mapMonsters[monsterId]._posY > _mapPosY) - ++_mapMonsters[monsterId]._posY; + if (_mapMonsters[_techId][monsterId]._posX < _mapPosX) { + --_mapMonsters[_techId][monsterId]._posX; + if (_mapMonsters[_techId][monsterId]._posY < _mapPosY) + --_mapMonsters[_techId][monsterId]._posY; + else if (_mapMonsters[_techId][monsterId]._posY > _mapPosY) + ++_mapMonsters[_techId][monsterId]._posY; return true; } - if (_mapMonsters[monsterId]._posX > _mapPosX) { - ++_mapMonsters[monsterId]._posX; - if (_mapMonsters[monsterId]._posY < _mapPosY) - --_mapMonsters[monsterId]._posY; - else if (_mapMonsters[monsterId]._posY > _mapPosY) - ++_mapMonsters[monsterId]._posY; + if (_mapMonsters[_techId][monsterId]._posX > _mapPosX) { + ++_mapMonsters[_techId][monsterId]._posX; + if (_mapMonsters[_techId][monsterId]._posY < _mapPosY) + --_mapMonsters[_techId][monsterId]._posY; + else if (_mapMonsters[_techId][monsterId]._posY > _mapPosY) + ++_mapMonsters[_techId][monsterId]._posY; return true; } // Original checks for posX equality, which is the only possible option at this point => skipped - if (_mapMonsters[monsterId]._posY < _mapPosY) - --_mapMonsters[monsterId]._posY; - else if (_mapMonsters[monsterId]._posY > _mapPosY) - ++_mapMonsters[monsterId]._posY; + if (_mapMonsters[_techId][monsterId]._posY < _mapPosY) + --_mapMonsters[_techId][monsterId]._posY; + else if (_mapMonsters[_techId][monsterId]._posY > _mapPosY) + ++_mapMonsters[_techId][monsterId]._posY; else return false; @@ -1473,31 +1436,31 @@ bool EfhEngine::moveMonsterAwayFromTeam(int16 monsterId) { bool EfhEngine::moveMonsterTowardsTeam(int16 monsterId) { debugC(6, kDebugEngine, "moveMonsterTowardsTeam %d", monsterId); - if (_mapMonsters[monsterId]._posX < _mapPosX) { - ++_mapMonsters[monsterId]._posX; - if (_mapMonsters[monsterId]._posY < _mapPosY) - ++_mapMonsters[monsterId]._posY; - else if (_mapMonsters[monsterId]._posY > _mapPosY) - --_mapMonsters[monsterId]._posY; + if (_mapMonsters[_techId][monsterId]._posX < _mapPosX) { + ++_mapMonsters[_techId][monsterId]._posX; + if (_mapMonsters[_techId][monsterId]._posY < _mapPosY) + ++_mapMonsters[_techId][monsterId]._posY; + else if (_mapMonsters[_techId][monsterId]._posY > _mapPosY) + --_mapMonsters[_techId][monsterId]._posY; return true; } - if (_mapMonsters[monsterId]._posX > _mapPosX) { - --_mapMonsters[monsterId]._posX; - if (_mapMonsters[monsterId]._posY < _mapPosY) - ++_mapMonsters[monsterId]._posY; - else if (_mapMonsters[monsterId]._posY > _mapPosY) - --_mapMonsters[monsterId]._posY; + if (_mapMonsters[_techId][monsterId]._posX > _mapPosX) { + --_mapMonsters[_techId][monsterId]._posX; + if (_mapMonsters[_techId][monsterId]._posY < _mapPosY) + ++_mapMonsters[_techId][monsterId]._posY; + else if (_mapMonsters[_techId][monsterId]._posY > _mapPosY) + --_mapMonsters[_techId][monsterId]._posY; return true; } // Original checks for posX equality, which is the only possible option at this point => skipped - if (_mapMonsters[monsterId]._posY < _mapPosY) - ++_mapMonsters[monsterId]._posY; - else if (_mapMonsters[monsterId]._posY > _mapPosY) - --_mapMonsters[monsterId]._posY; + if (_mapMonsters[_techId][monsterId]._posY < _mapPosY) + ++_mapMonsters[_techId][monsterId]._posY; + else if (_mapMonsters[_techId][monsterId]._posY > _mapPosY) + --_mapMonsters[_techId][monsterId]._posY; else return false; @@ -1511,39 +1474,39 @@ bool EfhEngine::moveMonsterGroupOther(int16 monsterId, int16 direction) { switch (direction - 1) { case 0: - --_mapMonsters[monsterId]._posY; + --_mapMonsters[_techId][monsterId]._posY; retVal = true; break; case 1: - --_mapMonsters[monsterId]._posY; - ++_mapMonsters[monsterId]._posX; + --_mapMonsters[_techId][monsterId]._posY; + ++_mapMonsters[_techId][monsterId]._posX; retVal = true; break; case 2: - ++_mapMonsters[monsterId]._posX; + ++_mapMonsters[_techId][monsterId]._posX; retVal = true; break; case 3: - ++_mapMonsters[monsterId]._posX; - ++_mapMonsters[monsterId]._posY; + ++_mapMonsters[_techId][monsterId]._posX; + ++_mapMonsters[_techId][monsterId]._posY; retVal = true; break; case 4: - ++_mapMonsters[monsterId]._posY; + ++_mapMonsters[_techId][monsterId]._posY; retVal = true; break; case 5: - ++_mapMonsters[monsterId]._posY; - --_mapMonsters[monsterId]._posX; + ++_mapMonsters[_techId][monsterId]._posY; + --_mapMonsters[_techId][monsterId]._posX; retVal = true; break; case 6: - --_mapMonsters[monsterId]._posX; + --_mapMonsters[_techId][monsterId]._posX; retVal = true; break; case 7: - --_mapMonsters[monsterId]._posX; - --_mapMonsters[monsterId]._posY; + --_mapMonsters[_techId][monsterId]._posX; + --_mapMonsters[_techId][monsterId]._posY; retVal = true; break; default: @@ -1572,8 +1535,8 @@ bool EfhEngine::moveMonsterGroupRandom(int16 monsterId) { int16 EfhEngine::computeMonsterGroupDistance(int16 monsterId) { debugC(2, kDebugEngine, "computeMonsterGroupDistance %d", monsterId); - int16 monsterPosX = _mapMonsters[monsterId]._posX; - int16 monsterPosY = _mapMonsters[monsterId]._posY; + int16 monsterPosX = _mapMonsters[_techId][monsterId]._posX; + int16 monsterPosY = _mapMonsters[_techId][monsterId]._posY; int16 deltaX = monsterPosX - _mapPosX; int16 deltaY = monsterPosY - _mapPosY; @@ -1600,10 +1563,10 @@ bool EfhEngine::checkMonsterMovementType(int16 id, bool teamFlag) { if (teamFlag) monsterId = _teamMonsterIdArray[id]; - if ((_mapMonsters[monsterId]._additionalInfo & 0xF) >= 8) + if ((_mapMonsters[_techId][monsterId]._additionalInfo & 0xF) >= 8) return true; - if (_unk2C8AA != 0 && (_mapMonsters[monsterId]._additionalInfo & 0x80) != 0) + if (_unk2C8AA != 0 && (_mapMonsters[_techId][monsterId]._additionalInfo & 0x80) != 0) return true; return false; @@ -1616,7 +1579,7 @@ bool EfhEngine::checkTeamWeaponRange(int16 monsterId) { return true; for (uint counter = 0; counter < 5; ++counter) { - if (_teamMonsterIdArray[counter] == monsterId && checkMonsterMovementType(monsterId, false) && checkWeaponRange(monsterId, _mapMonsters[monsterId]._weaponItemId)) + if (_teamMonsterIdArray[counter] == monsterId && checkMonsterMovementType(monsterId, false) && checkWeaponRange(monsterId, _mapMonsters[_techId][monsterId]._weaponItemId)) return false; } @@ -1626,10 +1589,10 @@ bool EfhEngine::checkTeamWeaponRange(int16 monsterId) { bool EfhEngine::checkIfMonsterOnSameLargeMapPlace(int16 monsterId) { debugC(6, kDebugEngine, "checkIfMonsterOnSameLargeMapPlace %d", monsterId); - if (_largeMapFlag && _mapMonsters[monsterId]._fullPlaceId == 0xFE) + if (_largeMapFlag && _mapMonsters[_techId][monsterId]._fullPlaceId == 0xFE) return true; - if (!_largeMapFlag && _mapMonsters[monsterId]._fullPlaceId == _fullPlaceId) + if (!_largeMapFlag && _mapMonsters[_techId][monsterId]._fullPlaceId == _fullPlaceId) return true; return false; @@ -1638,7 +1601,7 @@ bool EfhEngine::checkIfMonsterOnSameLargeMapPlace(int16 monsterId) { bool EfhEngine::checkMonsterWeaponRange(int16 monsterId) { debugC(6, kDebugEngine, "checkMonsterWeaponRange %d", monsterId); - return checkWeaponRange(monsterId, _mapMonsters[monsterId]._weaponItemId); + return checkWeaponRange(monsterId, _mapMonsters[_techId][monsterId]._weaponItemId); } void EfhEngine::handleMapMonsterMoves() { @@ -1662,8 +1625,8 @@ void EfhEngine::handleMapMonsterMoves() { if (!checkIfMonsterOnSameLargeMapPlace(monsterId)) continue; - int16 previousPosX = _mapMonsters[monsterId]._posX; - int16 previousPosY = _mapMonsters[monsterId]._posY; + int16 previousPosX = _mapMonsters[_techId][monsterId]._posX; + int16 previousPosY = _mapMonsters[_techId][monsterId]._posY; if (previousPosX < minDisplayedMapX || previousPosX > maxDisplayedMapX || previousPosY < minDisplayedMapY || previousPosY > maxDisplayedMapY) continue; @@ -1671,12 +1634,12 @@ void EfhEngine::handleMapMonsterMoves() { bool monsterMovedFl = false; int16 lastRangeCheck = 0; - int8 monsterMoveType = _mapMonsters[monsterId]._additionalInfo & 0xF; // 0000 1111 + int8 monsterMoveType = _mapMonsters[_techId][monsterId]._additionalInfo & 0xF; // 0000 1111 - if (_unk2C8AA != 0 && (_mapMonsters[monsterId]._additionalInfo & 0x80)) // 1000 0000 + if (_unk2C8AA != 0 && (_mapMonsters[_techId][monsterId]._additionalInfo & 0x80)) // 1000 0000 monsterMoveType = 9; - int16 randomModPct = _mapMonsters[monsterId]._additionalInfo & 0x70; // 0111 0000 + int16 randomModPct = _mapMonsters[_techId][monsterId]._additionalInfo & 0x70; // 0111 0000 randomModPct >>= 4; // Max 7 (0111) int16 retryCounter = randomModPct; @@ -1788,13 +1751,13 @@ void EfhEngine::handleMapMonsterMoves() { int8 checkMoveFl = checkMonsterMoveCollisionAndTileTexture(monsterId); if (checkMoveFl == 0) { // Blocked - _mapMonsters[monsterId]._posX = previousPosX; - _mapMonsters[monsterId]._posY = previousPosY; + _mapMonsters[_techId][monsterId]._posX = previousPosX; + _mapMonsters[_techId][monsterId]._posY = previousPosY; monsterMovedFl = false; --retryCounter; } else if (checkMoveFl == 2) { // Wall - _mapMonsters[monsterId]._posX = previousPosX; - _mapMonsters[monsterId]._posY = previousPosY; + _mapMonsters[_techId][monsterId]._posX = previousPosX; + _mapMonsters[_techId][monsterId]._posY = previousPosY; } } @@ -1815,11 +1778,11 @@ void EfhEngine::handleMapMonsterMoves() { bool EfhEngine::checkMapMonsterAvailability(int16 monsterId) { debugC(6, kDebugEngine, "checkMapMonsterAvailability %d", monsterId); - if (_mapMonsters[monsterId]._fullPlaceId == 0xFF) + if (_mapMonsters[_techId][monsterId]._fullPlaceId == 0xFF) return false; for (uint counter = 0; counter < 9; ++counter) { - if (_mapMonsters[monsterId]._hitPoints[counter] > 0) + if (_mapMonsters[_techId][monsterId]._hitPoints[counter] > 0) return true; } @@ -1829,7 +1792,7 @@ bool EfhEngine::checkMapMonsterAvailability(int16 monsterId) { void EfhEngine::displayMonsterAnim(int16 monsterId) { debugC(6, kDebugEngine, "displayMonsterAnim %d", monsterId); - int16 animId = kEncounters[_mapMonsters[monsterId]._monsterRef]._animId; + int16 animId = kEncounters[_mapMonsters[_techId][monsterId]._monsterRef]._animId; displayAnimFrames(animId, true); } @@ -1841,7 +1804,7 @@ int16 EfhEngine::countAliveMonsters(int16 id) { int16 count = 0; for (uint counter = 0; counter < 9; ++counter) { - if (_mapMonsters[id]._hitPoints[counter] > 0) + if (_mapMonsters[_techId][id]._hitPoints[counter] > 0) ++count; } @@ -1860,7 +1823,7 @@ bool EfhEngine::checkMonsterGroupDistance1OrLess(int16 monsterId) { bool EfhEngine::handleTalk(int16 monsterId, int16 arg2, int16 itemId) { debugC(6, kDebugEngine, "handleTalk %d %d %d", monsterId, arg2, itemId); - if (_mapMonsters[monsterId]._fullPlaceId == 0xFF) + if (_mapMonsters[_techId][monsterId]._fullPlaceId == 0xFF) return false; if (countAliveMonsters(monsterId) < 1) @@ -1872,20 +1835,20 @@ bool EfhEngine::handleTalk(int16 monsterId, int16 arg2, int16 itemId) { if (!checkMonsterGroupDistance1OrLess(monsterId)) return false; - if ((_mapMonsters[monsterId]._possessivePronounSHL6 & 0x3F) != 0x3F) { - if (_mapMonsters[monsterId]._talkTextId == 0xFF || arg2 != 5) { + if ((_mapMonsters[_techId][monsterId]._possessivePronounSHL6 & 0x3F) != 0x3F) { + if (_mapMonsters[_techId][monsterId]._talkTextId == 0xFF || arg2 != 5) { return false; } displayMonsterAnim(monsterId); - displayImp1Text(_mapMonsters[monsterId]._talkTextId); + displayImp1Text(_mapMonsters[_techId][monsterId]._talkTextId); displayAnimFrames(0xFE, true); return true; } - if (isNpcATeamMember(_mapMonsters[monsterId]._npcId)) + if (isNpcATeamMember(_mapMonsters[_techId][monsterId]._npcId)) return false; - int16 npcId = _mapMonsters[monsterId]._npcId; + int16 npcId = _mapMonsters[_techId][monsterId]._npcId; switch (_npcBuf[npcId].field_10 - 0xEE) { case 0: if (arg2 == 4 && _npcBuf[npcId].field11_NpcId == itemId) { @@ -2154,35 +2117,35 @@ bool EfhEngine::sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemI if (imageSetId != -1 && *_imp2PtrArray[imageSetId] != 0x30) displayMiddleLeftTempText(_imp2PtrArray[imageSetId], true); } else if (arg8 == 0) { - if (_mapSpecialTile[tileId]._field3 == 0xFF) { - displayImp1Text(_mapSpecialTile[tileId]._field5_textId); + if (_mapSpecialTiles[_techId][tileId]._field3 == 0xFF) { + displayImp1Text(_mapSpecialTiles[_techId][tileId]._field5_textId); return true; } - if (_mapSpecialTile[tileId]._field3 == 0xFE) { + if (_mapSpecialTiles[_techId][tileId]._field3 == 0xFE) { for (int counter = 0; counter < _teamSize; ++counter) { if (_teamCharId[counter] == -1) continue; - if (_teamCharId[counter] == _mapSpecialTile[tileId]._triggerId) { - displayImp1Text(_mapSpecialTile[tileId]._field5_textId); + if (_teamCharId[counter] == _mapSpecialTiles[_techId][tileId]._triggerId) { + displayImp1Text(_mapSpecialTiles[_techId][tileId]._field5_textId); return true; } } - } else if (_mapSpecialTile[tileId]._field3 == 0xFD) { + } else if (_mapSpecialTiles[_techId][tileId]._field3 == 0xFD) { for (int counter = 0; counter < _teamSize; ++counter) { if (_teamCharId[counter] == -1) continue; for (uint var2 = 0; var2 < 10; ++var2) { - if (_npcBuf[_teamCharId[counter]]._inventory[var2]._ref == _mapSpecialTile[tileId]._triggerId) { - displayImp1Text(_mapSpecialTile[tileId]._field5_textId); + if (_npcBuf[_teamCharId[counter]]._inventory[var2]._ref == _mapSpecialTiles[_techId][tileId]._triggerId) { + displayImp1Text(_mapSpecialTiles[_techId][tileId]._field5_textId); return true; } } } // original makes a useless check on (_mapSpecialTile[tileId]._field3 > 0x7F) - } else if (_mapSpecialTile[tileId]._field3 <= 0x77) { - int16 var6 = _mapSpecialTile[tileId]._field3; + } else if (_mapSpecialTiles[_techId][tileId]._field3 <= 0x77) { + int16 var6 = _mapSpecialTiles[_techId][tileId]._field3; for (int counter = 0; counter < _teamSize; ++counter) { if (_teamCharId[counter] == -1) continue; @@ -2191,26 +2154,26 @@ bool EfhEngine::sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemI // CHECKME : the whole loop doesn't make much sense as it's using var6 instead of var2, plus _activeScore is an array of 15 bytes, not 0x77... // Also, 39 correspond to the size of activeScore + passiveScore + infoScore + the 2 remaining bytes of the struct warning("sub22293 - _activeScore[%d]", var6); - if (_npcBuf[_teamCharId[counter]]._activeScore[var6] >= _mapSpecialTile[tileId]._triggerId) { - displayImp1Text(_mapSpecialTile[tileId]._field5_textId); + if (_npcBuf[_teamCharId[counter]]._activeScore[var6] >= _mapSpecialTiles[_techId][tileId]._triggerId) { + displayImp1Text(_mapSpecialTiles[_techId][tileId]._field5_textId); return true; } } } } - } else if ((_mapSpecialTile[tileId]._field3 == 0xFA && arg8 == 1) || (_mapSpecialTile[tileId]._field3 == 0xFC && arg8 == 2) || (_mapSpecialTile[tileId]._field3 == 0xFB && arg8 == 3)) { - if (_mapSpecialTile[tileId]._triggerId == itemId) { - displayImp1Text(_mapSpecialTile[tileId]._field5_textId); + } else if ((_mapSpecialTiles[_techId][tileId]._field3 == 0xFA && arg8 == 1) || (_mapSpecialTiles[_techId][tileId]._field3 == 0xFC && arg8 == 2) || (_mapSpecialTiles[_techId][tileId]._field3 == 0xFB && arg8 == 3)) { + if (_mapSpecialTiles[_techId][tileId]._triggerId == itemId) { + displayImp1Text(_mapSpecialTiles[_techId][tileId]._field5_textId); return true; } } else if (arg8 == 4) { - int16 var6 = _mapSpecialTile[tileId]._field3; + int16 var6 = _mapSpecialTiles[_techId][tileId]._field3; if (var6 >= 0x78 && var6 <= 0xEF) { var6 -= 0x78; warning("sub22293 - _activeScore[%d]", var6); // The 2 checks on var6 are useless, as [0x78..0xEF] - 0x78 => [0x00..0x77] - if (var6 >= 0 && var6 <= 0x8B && var6 == itemId && _mapSpecialTile[tileId]._triggerId <= _npcBuf[charId]._activeScore[itemId]) { - displayImp1Text(_mapSpecialTile[tileId]._field5_textId); + if (var6 >= 0 && var6 <= 0x8B && var6 == itemId && _mapSpecialTiles[_techId][tileId]._triggerId <= _npcBuf[charId]._activeScore[itemId]) { + displayImp1Text(_mapSpecialTiles[_techId][tileId]._field5_textId); return true; } } @@ -2222,10 +2185,10 @@ bool EfhEngine::sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemI } // CHECKME: there's suspiciously no check on tileId - if ((arg8 == 4 && _mapSpecialTile[tileId]._field3 < 0xFA) || arg8 != 4) { - if (_mapSpecialTile[tileId]._field7_textId > 0xFE) + if ((arg8 == 4 && _mapSpecialTiles[_techId][tileId]._field3 < 0xFA) || arg8 != 4) { + if (_mapSpecialTiles[_techId][tileId]._field7_textId > 0xFE) return false; - displayImp1Text(_mapSpecialTile[tileId]._field7_textId); + displayImp1Text(_mapSpecialTiles[_techId][tileId]._field7_textId); return true; } @@ -2250,7 +2213,7 @@ int8 EfhEngine::checkTileStatus(int16 mapPosX, int16 mapPosY, bool arg4) { if (_tileFact[tileFactId]._tileId != 0xFF && !_dbgForceMonsterBlock) { if ((arg4) || (!arg4 && tileFactId != 128 && tileFactId != 121)) { if (_largeMapFlag) { - _mapGameMap[mapPosX][mapPosY] = _tileFact[tileFactId]._tileId; + _mapGameMaps[_techId][mapPosX][mapPosY] = _tileFact[tileFactId]._tileId; } else { _curPlace[mapPosX][mapPosY] = _tileFact[tileFactId]._tileId; } @@ -2284,7 +2247,7 @@ void EfhEngine::computeInitiatives() { _initiatives[counter + 3]._initiative = -1; } else { _initiatives[counter + 3]._id = counter; - _initiatives[counter + 3]._initiative = _mapMonsters[_teamMonsterIdArray[counter]]._npcId + getRandom(20); + _initiatives[counter + 3]._initiative = _mapMonsters[_techId][_teamMonsterIdArray[counter]]._npcId + getRandom(20); } } @@ -2368,14 +2331,14 @@ void EfhEngine::setMapMonsterAggressivenessAndMovementType(int16 id, uint8 mask, } mask &= 0x0F; - _mapMonsters[monsterId]._additionalInfo &= 0xF0; - _mapMonsters[monsterId]._additionalInfo |= mask; + _mapMonsters[_techId][monsterId]._additionalInfo &= 0xF0; + _mapMonsters[_techId][monsterId]._additionalInfo |= mask; } bool EfhEngine::isMonsterActive(int16 groupId, int16 id) { debugC(5, kDebugEngine, "isMonsterActive %d %d", groupId, id); - if (_mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[id] > 0 && _teamMonsterEffects[groupId]._effect[id] == 0) + if (_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[id] > 0 && _teamMonsterEffects[groupId]._effect[id] == 0) return true; return false; } @@ -2420,15 +2383,15 @@ bool EfhEngine::checkMonsterCollision() { if (!checkMapMonsterAvailability(monsterId)) continue; - if (!(_largeMapFlag && _mapMonsters[monsterId]._fullPlaceId == 0xFE) - && !(!_largeMapFlag && _mapMonsters[monsterId]._fullPlaceId == _fullPlaceId)) + if (!(_largeMapFlag && _mapMonsters[_techId][monsterId]._fullPlaceId == 0xFE) + && !(!_largeMapFlag && _mapMonsters[_techId][monsterId]._fullPlaceId == _fullPlaceId)) continue; - if ((_mapMonsters[monsterId]._possessivePronounSHL6 & 0x3F) > 0x3D - && ((_mapMonsters[monsterId]._possessivePronounSHL6 & 0x3F) != 0x3F || isNpcATeamMember(_mapMonsters[monsterId]._npcId))) + if ((_mapMonsters[_techId][monsterId]._possessivePronounSHL6 & 0x3F) > 0x3D + && ((_mapMonsters[_techId][monsterId]._possessivePronounSHL6 & 0x3F) != 0x3F || isNpcATeamMember(_mapMonsters[_techId][monsterId]._npcId))) continue; - if (_mapMonsters[monsterId]._posX != _mapPosX || _mapMonsters[monsterId]._posY != _mapPosY) + if (_mapMonsters[_techId][monsterId]._posX != _mapPosX || _mapMonsters[_techId][monsterId]._posY != _mapPosY) continue; _mapPosX = _oldMapPosX; @@ -2439,7 +2402,7 @@ bool EfhEngine::checkMonsterCollision() { int16 mobsterCount = 0; for (uint mobsterCounter = 0; mobsterCounter < 9; ++mobsterCounter) { - if (_mapMonsters[monsterId]._hitPoints[mobsterCounter]) + if (_mapMonsters[_techId][monsterId]._hitPoints[mobsterCounter]) ++mobsterCount; } @@ -2448,18 +2411,18 @@ bool EfhEngine::checkMonsterCollision() { do { for (uint displayCounter = 0; displayCounter < 2; ++displayCounter) { Common::String dest; - switch (_mapMonsters[monsterId]._possessivePronounSHL6 & 0x3F) { + switch (_mapMonsters[_techId][monsterId]._possessivePronounSHL6 & 0x3F) { case 0x3E: buffer = "(NOT DEFINED)"; dest = "(NOT DEFINED)"; break; case 0x3F: // Special character name - dest = _npcBuf[_mapMonsters[monsterId]._npcId]._name; + dest = _npcBuf[_mapMonsters[_techId][monsterId]._npcId]._name; buffer = Common::String("with ") + dest; break; default: - dest = kEncounters[_mapMonsters[monsterId]._monsterRef]._name; + dest = kEncounters[_mapMonsters[_techId][monsterId]._monsterRef]._name; if (mobsterCount > 1) dest += "s"; @@ -2544,8 +2507,10 @@ void EfhEngine::loadImageSetToTileBank(int16 tileBankId, int16 imageSetId) { _currentTileBankImageSetId[bankId] = setId; - if (bankId == 0 || bankId == 1) - _mapBitmapRefArr[_techId][bankId] = setId; + if (bankId == 0) + _mapBitmapRefArr[_techId]._setId1 = setId; + else if (bankId == 1) + _mapBitmapRefArr[_techId]._setId2 = setId; int16 ptrIndex = bankId * 72; loadImageSet(setId, _tileBank[bankId], &_imageSetSubFilesArray[ptrIndex], _hiResImageBuf); @@ -2628,7 +2593,7 @@ uint8 EfhEngine::getMapTileInfo(int16 mapPosX, int16 mapPosY) { debugC(3, kDebugEngine, "getMapTileInfo %d-%d", mapPosX, mapPosY); if (_largeMapFlag) - return _mapGameMap[mapPosX][mapPosY]; + return _mapGameMaps[_techId][mapPosX][mapPosY]; return _curPlace[mapPosX][mapPosY]; } diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 94137f0bd4c3..8d4f84b1e087 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -177,6 +177,7 @@ struct NPCStruct { void init(); uint8 getPronoun(); + void synchronize(Common::Serializer &s); }; struct FontDescr { @@ -537,10 +538,16 @@ class EfhEngine : public Engine { Common::String _attackBuffer; Common::String _messageToBePrinted; - uint8 *_mapBitmapRefArr[19]; - MapSpecialTileStruct _mapSpecialTile[100]; - MapMonster _mapMonsters[64]; - uint8 _mapGameMap[64][64]; + struct BitmapRef { + int8 _setId1; + int8 _setId2; + }; + + BitmapRef _mapBitmapRefArr[19]; + + MapSpecialTileStruct _mapSpecialTiles[19][100]; + MapMonster _mapMonsters[19][64]; + uint8 _mapGameMaps[19][64][64]; uint8 _defaultBoxColor; FontDescr _fontDescr; diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index e181e8a79016..e094730ac1e2 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -37,10 +37,10 @@ void EfhEngine::createOpponentList(int16 monsterTeamId) { break; for (uint monsterId = 0; monsterId < 64; ++monsterId) { - if (_mapMonsters[monsterId]._fullPlaceId == 0xFF) + if (_mapMonsters[_techId][monsterId]._fullPlaceId == 0xFF) continue; - if (((_mapMonsters[monsterId]._possessivePronounSHL6 & 0x3F) != 0x3F || isNpcATeamMember(_mapMonsters[monsterId]._npcId)) && (_mapMonsters[monsterId]._possessivePronounSHL6 & 0x3F) > 0x3D) + if (((_mapMonsters[_techId][monsterId]._possessivePronounSHL6 & 0x3F) != 0x3F || isNpcATeamMember(_mapMonsters[_techId][monsterId]._npcId)) && (_mapMonsters[_techId][monsterId]._possessivePronounSHL6 & 0x3F) > 0x3D) continue; if (!checkIfMonsterOnSameLargeMapPlace(monsterId)) @@ -48,7 +48,7 @@ void EfhEngine::createOpponentList(int16 monsterTeamId) { bool found = false; for (uint subId = 0; subId < 9; ++subId) { - if (_mapMonsters[monsterId]._hitPoints[subId] > 0) { + if (_mapMonsters[_techId][monsterId]._hitPoints[subId] > 0) { found = true; break; } @@ -161,7 +161,7 @@ bool EfhEngine::handleFight(int16 monsterId) { // handleFight - Loop on mobsterId - Start for (uint ctrMobsterId = 0; ctrMobsterId < 9; ++ctrMobsterId) { if (isMonsterActive(monsterGroupIdOrMonsterId, ctrMobsterId)) { - int16 monsterWeaponItemId = _mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._weaponItemId; + int16 monsterWeaponItemId = _mapMonsters[_techId][_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._weaponItemId; if (monsterWeaponItemId == 0xFF) monsterWeaponItemId = 0x3F; int16 teamMemberId = -1; @@ -187,7 +187,7 @@ bool EfhEngine::handleFight(int16 monsterId) { int16 var76 = getRandom(getEquipmentDefense(_teamCharId[var7E], false)); varInt = _teamMonsterIdArray[monsterGroupIdOrMonsterId]; - int16 ennemyPronoun = kEncounters[_mapMonsters[varInt]._monsterRef]._nameArticle; + int16 ennemyPronoun = kEncounters[_mapMonsters[_techId][varInt]._monsterRef]._nameArticle; int16 characterPronoun = _npcBuf[_teamCharId[var7E]].getPronoun(); varInt = _items[monsterWeaponItemId].field_13; _teamPctDodgeMiss[var7E] += (varInt * 5); @@ -195,7 +195,7 @@ bool EfhEngine::handleFight(int16 monsterId) { int16 hitPoints = 0; int16 originalDamage = 0; int16 damagePointsAbsorbed = 0; - int16 var64 = _mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._npcId * _items[monsterWeaponItemId]._attacks; + int16 var64 = _mapMonsters[_techId][_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._npcId * _items[monsterWeaponItemId]._attacks; for (int var84 = 0; var84 < var64; ++var84) { // handleFight - Loop var84 on var64 (objectId) - Start if (getRandom(100) > _teamPctDodgeMiss[var7E]) @@ -245,7 +245,7 @@ bool EfhEngine::handleFight(int16 monsterId) { else _enemyNamePt1 = ""; - _enemyNamePt2 = kEncounters[_mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._monsterRef]._name; + _enemyNamePt2 = kEncounters[_mapMonsters[_techId][_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._monsterRef]._name; _characterNamePt2 = _npcBuf[_teamCharId[var7E]]._name; _nameBuffer = _items[monsterWeaponItemId]._name; if (checkSpecialItemsOnCurrentPlace(monsterWeaponItemId)) { @@ -338,11 +338,11 @@ bool EfhEngine::handleFight(int16 monsterId) { } // handleFight - Loop on var7E - End } - } else if (_mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._hitPoints[ctrMobsterId] > 0 && _teamMonsterEffects[monsterGroupIdOrMonsterId]._effect[ctrMobsterId]) { + } else if (_mapMonsters[_techId][_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._hitPoints[ctrMobsterId] > 0 && _teamMonsterEffects[monsterGroupIdOrMonsterId]._effect[ctrMobsterId]) { --_teamMonsterEffects[monsterGroupIdOrMonsterId]._duration[ctrMobsterId]; if (_teamMonsterEffects[monsterGroupIdOrMonsterId]._duration[ctrMobsterId] <= 0) { - _enemyNamePt2 = kEncounters[_mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._monsterRef]._name; - int16 var70 = kEncounters[_mapMonsters[_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._monsterRef]._nameArticle; + _enemyNamePt2 = kEncounters[_mapMonsters[_techId][_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._monsterRef]._name; + int16 var70 = kEncounters[_mapMonsters[_techId][_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._monsterRef]._nameArticle; if (var70 == 2) _enemyNamePt1 = "The "; else @@ -463,12 +463,12 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { } else noticedFl = false; - int16 var76 = getRandom(_mapMonsters[_teamMonsterIdArray[groupId]]._maxDamageAbsorption); + int16 var76 = getRandom(_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._maxDamageAbsorption); int16 ennemyPronoun = _npcBuf[_teamCharId[teamCharId]].getPronoun(); int16 monsterId = _teamMonsterIdArray[groupId]; - int16 characterPronoun = kEncounters[_mapMonsters[monsterId]._monsterRef]._nameArticle; + int16 characterPronoun = kEncounters[_mapMonsters[_techId][monsterId]._monsterRef]._nameArticle; int16 charScore = getCharacterScore(_teamCharId[teamCharId], teamCharItemId); - int16 hitPointsBefore = _mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId]; + int16 hitPointsBefore = _mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId]; int16 hitCount = 0; int16 originalDamage = 0; int16 damagePointsAbsorbed = 0; @@ -501,7 +501,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { hitCount = 0; if (hitCount > 0) { - _mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] -= originalDamage; + _mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] -= originalDamage; if (hitCount > 1) { _attackBuffer = Common::String::format("%d times ", hitCount); } else { @@ -521,7 +521,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { _enemyNamePt1 = ""; } - _characterNamePt2 = kEncounters[_mapMonsters[_teamMonsterIdArray[groupId]]._monsterRef]._name; + _characterNamePt2 = kEncounters[_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._monsterRef]._name; _enemyNamePt2 = _npcBuf[_teamCharId[teamCharId]]._name; _nameBuffer = _items[teamCharItemId]._name; if (checkSpecialItemsOnCurrentPlace(teamCharItemId)) { @@ -532,7 +532,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s, but does no damage!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[verbId], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[ennemyPronoun], _nameBuffer.c_str()); } else if (hitPoints == 1) { _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s for 1 point", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[verbId], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[ennemyPronoun], _nameBuffer.c_str()); - if (_mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] <= 0) { + if (_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] <= 0) { getDeathTypeDescription(groupId, teamCharId + 1000); getXPAndSearchCorpse(_teamCharId[teamCharId], _enemyNamePt1, _enemyNamePt2, _teamMonsterIdArray[groupId]); } else { @@ -540,7 +540,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { } } else { _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s for %d points", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[verbId], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[ennemyPronoun], _nameBuffer.c_str(), hitPoints); - if (_mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] <= 0) { + if (_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] <= 0) { getDeathTypeDescription(groupId, teamCharId + 1000); getXPAndSearchCorpse(_teamCharId[teamCharId], _enemyNamePt1, _enemyNamePt2, _teamMonsterIdArray[groupId]); } else { @@ -550,16 +550,16 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { // Action A - Check damages - End // Action A - Add reaction text - Start - if (hitCount != 0 && originalDamage > 0 && getRandom(100) <= 35 && _mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] > 0) { - if (_mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] - 5 <= originalDamage) { + if (hitCount != 0 && originalDamage > 0 && getRandom(100) <= 35 && _mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] > 0) { + if (_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] - 5 <= originalDamage) { addReactionText(kEfhReactionReels); - } else if (_mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] < hitPointsBefore / 8) { + } else if (_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] < hitPointsBefore / 8) { addReactionText(kEfhReactionCriesOut); - } else if (_mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] < hitPointsBefore / 4) { + } else if (_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] < hitPointsBefore / 4) { addReactionText(kEfhReactionFalters); - } else if (_mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] < hitPointsBefore / 2) { + } else if (_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] < hitPointsBefore / 2) { addReactionText(kEfhReactionWinces); - } else if (_mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] < hitPointsBefore / 3) { + } else if (_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] < hitPointsBefore / 3) { // CHECKME: Doesn't make any sense to check /3 after /2... I don't get it. Looks like an original bug addReactionText(kEfhReactionScreams); } else if (hitPointsBefore / 8 >= originalDamage) { @@ -572,7 +572,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { // Action A - Add reaction text - End // Action A - Add armor absorb text - Start - if (var76 && hitCount && _mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] > 0) { + if (var76 && hitCount && _mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] > 0) { if (damagePointsAbsorbed <= 1) _messageToBePrinted += Common::String::format(" %s%s's armor absorbs 1 point!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); else @@ -602,13 +602,13 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { // Action A - Check item durability - End // Action A - Check effect - Start - if (_items[teamCharItemId]._specialEffect == 1 && _mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] > 0) { + if (_items[teamCharItemId]._specialEffect == 1 && _mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] > 0) { if (getRandom(100) < 35) { _teamMonsterEffects[groupId]._effect[ctrMobsterId] = 1; _teamMonsterEffects[groupId]._duration[ctrMobsterId] = getRandom(10); _messageToBePrinted += Common::String::format(" %s%s falls asleep!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); } - } else if (_items[teamCharItemId]._specialEffect == 2 && _mapMonsters[_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] > 0) { + } else if (_items[teamCharItemId]._specialEffect == 2 && _mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] > 0) { _teamMonsterEffects[groupId]._effect[ctrMobsterId] = 2; _teamMonsterEffects[groupId]._duration[ctrMobsterId] = getRandom(10); _messageToBePrinted += Common::String::format(" %s%s is frozen!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); @@ -746,7 +746,7 @@ void EfhEngine::getDeathTypeDescription(int16 victimId, int16 attackerId) { pronoun = _npcBuf[charId].getPronoun(); } else { int16 charId = _teamMonsterIdArray[victimId]; - pronoun = _mapMonsters[charId].getPronoun(); + pronoun = _mapMonsters[_techId][charId].getPronoun(); } if (pronoun > 2) @@ -769,7 +769,7 @@ void EfhEngine::getDeathTypeDescription(int16 victimId, int16 attackerId) { } else if (_teamMonsterIdArray[attackerId] == -1) deathType = 0; else { - int16 itemId = _mapMonsters[_teamMonsterIdArray[attackerId]]._weaponItemId; + int16 itemId = _mapMonsters[_techId][_teamMonsterIdArray[attackerId]]._weaponItemId; deathType = _items[itemId]._attackType + 1; } @@ -1170,7 +1170,7 @@ void EfhEngine::getXPAndSearchCorpse(int16 charId, Common::String namePt1, Commo debugC(3, kDebugFight, "getXPAndSearchCorpse %d %s%s %d", charId, namePt1.c_str(), namePt2.c_str(), monsterId); int16 oldXpLevel = getXPLevel(_npcBuf[charId]._xp); - _npcBuf[charId]._xp += kEncounters[_mapMonsters[monsterId]._monsterRef]._xpGiven; + _npcBuf[charId]._xp += kEncounters[_mapMonsters[_techId][monsterId]._monsterRef]._xpGiven; if (getXPLevel(_npcBuf[charId]._xp) > oldXpLevel) { generateSound(15); @@ -1189,7 +1189,7 @@ void EfhEngine::getXPAndSearchCorpse(int16 charId, Common::String namePt1, Commo _npcBuf[charId]._infoScore[4] += getRandom(3) - 1; } - _messageToBePrinted += Common::String::format(" %s%s gains %d experience", namePt1.c_str(), namePt2.c_str(), kEncounters[_mapMonsters[monsterId]._monsterRef]._xpGiven); + _messageToBePrinted += Common::String::format(" %s%s gains %d experience", namePt1.c_str(), namePt2.c_str(), kEncounters[_mapMonsters[_techId][monsterId]._monsterRef]._xpGiven); if (!characterSearchesMonsterCorpse(charId, monsterId)) _messageToBePrinted += "!"; } @@ -1198,11 +1198,11 @@ bool EfhEngine::characterSearchesMonsterCorpse(int16 charId, int16 monsterId) { debugC(3, kDebugFight, "characterSearchesMonsterCorpse %d %d", charId, monsterId); int16 rndVal = getRandom(100); - if (kEncounters[_mapMonsters[monsterId]._monsterRef]._dropOccurrencePct < rndVal) + if (kEncounters[_mapMonsters[_techId][monsterId]._monsterRef]._dropOccurrencePct < rndVal) return false; rndVal = getRandom(5) - 1; - int16 itemId = kEncounters[_mapMonsters[monsterId]._monsterRef]._dropItemId[rndVal]; + int16 itemId = kEncounters[_mapMonsters[_techId][monsterId]._monsterRef]._dropItemId[rndVal]; if (itemId == -1 || itemId == 0) return false; @@ -1348,16 +1348,16 @@ void EfhEngine::sub1C4CA(bool whiteFl) { Common::String buffer = Common::String::format("%c)", 'A' + counter); displayStringAtTextPos(buffer); setTextColorRed(); - int16 var1 = _mapMonsters[_teamMonsterIdArray[counter]]._possessivePronounSHL6 & 0x3F; + int16 var1 = _mapMonsters[_techId][_teamMonsterIdArray[counter]]._possessivePronounSHL6 & 0x3F; if (var1 <= 0x3D) { - buffer = Common::String::format("%d %s", mobsterCount, kEncounters[_mapMonsters[_teamMonsterIdArray[counter]]._monsterRef]._name); + buffer = Common::String::format("%d %s", mobsterCount, kEncounters[_mapMonsters[_techId][_teamMonsterIdArray[counter]]._monsterRef]._name); displayStringAtTextPos(buffer); if (mobsterCount > 1) displayStringAtTextPos("s"); } else if (var1 == 0x3E) { displayStringAtTextPos("(NOT DEFINED)"); } else if (var1 == 0x3F) { - Common::String stringToDisplay = _npcBuf[_mapMonsters[_teamMonsterIdArray[counter]]._npcId]._name; + Common::String stringToDisplay = _npcBuf[_mapMonsters[_techId][_teamMonsterIdArray[counter]]._npcId]._name; displayStringAtTextPos(stringToDisplay); } @@ -1410,12 +1410,12 @@ int16 EfhEngine::getWeakestMobster(int16 groupNumber) { if (!isMonsterActive(groupNumber, counter)) continue; - if (_mapMonsters[monsterId]._hitPoints[weakestMobsterId] > _mapMonsters[monsterId]._hitPoints[counter]) + if (_mapMonsters[_techId][monsterId]._hitPoints[weakestMobsterId] > _mapMonsters[_techId][monsterId]._hitPoints[counter]) weakestMobsterId = counter; } // Useless check, as the - if (_mapMonsters[monsterId]._hitPoints[weakestMobsterId] <= 0) + if (_mapMonsters[_techId][monsterId]._hitPoints[weakestMobsterId] <= 0) return -1; return weakestMobsterId; @@ -1524,7 +1524,7 @@ bool EfhEngine::checkSpecialItemsOnCurrentPlace(int16 itemId) { bool EfhEngine::hasAdequateDefense(int16 monsterId, uint8 attackType) { debugC(3, kDebugFight, "hasAdequateDefense %d %d", monsterId, attackType); - int16 itemId = _mapMonsters[monsterId]._weaponItemId; + int16 itemId = _mapMonsters[_techId][monsterId]._weaponItemId; if (_items[itemId]._specialEffect != 0) return false; @@ -1561,7 +1561,7 @@ void EfhEngine::addNewOpponents(int16 monsterId) { continue; for (uint ctrMobster = 0; ctrMobster < 9; ++ctrMobster) { - _mapMonsters[_teamMonsterIdArray[ctrGroupId]]._hitPoints[ctrMobster] = 0; + _mapMonsters[_techId][_teamMonsterIdArray[ctrGroupId]]._hitPoints[ctrMobster] = 0; _teamMonsterEffects[ctrGroupId]._effect[ctrMobster] = 0; _teamMonsterEffects[ctrGroupId]._duration[ctrMobster] = 0; } @@ -1595,14 +1595,14 @@ void EfhEngine::addNewOpponents(int16 monsterId) { break; for (uint ctrMapMonsterId = 0; ctrMapMonsterId < 64; ++ctrMapMonsterId) { - if (_mapMonsters[ctrMapMonsterId]._fullPlaceId == 0xFF) + if (_mapMonsters[_techId][ctrMapMonsterId]._fullPlaceId == 0xFF) continue; - if (((_mapMonsters[ctrMapMonsterId]._possessivePronounSHL6 & 0x3F) == 0x3F && !isNpcATeamMember(_mapMonsters[ctrMapMonsterId]._npcId)) || (_mapMonsters[ctrMapMonsterId]._possessivePronounSHL6 & 0x3F) <= 0x3D) { + if (((_mapMonsters[_techId][ctrMapMonsterId]._possessivePronounSHL6 & 0x3F) == 0x3F && !isNpcATeamMember(_mapMonsters[_techId][ctrMapMonsterId]._npcId)) || (_mapMonsters[_techId][ctrMapMonsterId]._possessivePronounSHL6 & 0x3F) <= 0x3D) { if (checkIfMonsterOnSameLargeMapPlace(ctrMapMonsterId)) { bool monsterActiveFound = false; for (uint ctrMobsterId = 0; ctrMobsterId < 9; ++ctrMobsterId) { - if (_mapMonsters[ctrMapMonsterId]._hitPoints[ctrMobsterId] > 0) { + if (_mapMonsters[_techId][ctrMapMonsterId]._hitPoints[ctrMobsterId] > 0) { monsterActiveFound = true; break; } @@ -1660,12 +1660,12 @@ int16 EfhEngine::getTeamMonsterAnimId() { if (!checkMonsterMovementType(monsterId, false)) continue; - retVal = kEncounters[_mapMonsters[monsterId]._monsterRef]._animId; + retVal = kEncounters[_mapMonsters[_techId][monsterId]._monsterRef]._animId; break; } if (retVal == 0xFF) - retVal = kEncounters[_mapMonsters[_teamMonsterIdArray[0]]._monsterRef]._animId; + retVal = kEncounters[_mapMonsters[_techId][_teamMonsterIdArray[0]]._monsterRef]._animId; return retVal; } diff --git a/engines/efh/files.cpp b/engines/efh/files.cpp index 218c8208a14a..9940cde059ab 100644 --- a/engines/efh/files.cpp +++ b/engines/efh/files.cpp @@ -211,8 +211,8 @@ void EfhEngine::loadTechMapImp(int16 fileId) { // The purpose is to properly load the misc map data in arrays in order to use them without being a pain afterwards loadMapArrays(_techId); - loadImageSetToTileBank(1, _mapBitmapRefArr[_techId][0] + 1); - loadImageSetToTileBank(2, _mapBitmapRefArr[_techId][1] + 1); + loadImageSetToTileBank(1, _mapBitmapRefArr[_techId]._setId1 + 1); + loadImageSetToTileBank(2, _mapBitmapRefArr[_techId]._setId2 + 1); initMapMonsters(); readImpFile(_techId, true); @@ -323,16 +323,54 @@ void EfhEngine::loadNPCS() { * This is required in order to implement a clean savegame feature */ void EfhEngine::preLoadMaps() { - for (int i = 0; i < 19; ++i) { - Common::String fileName = Common::String::format("tech.%d", i); + for (int idx = 0; idx < 19; ++idx) { + Common::String fileName = Common::String::format("tech.%d", idx); readFileToBuffer(fileName, _hiResImageBuf); - uncompressBuffer(_hiResImageBuf, _techDataArr[i]); + uncompressBuffer(_hiResImageBuf, _techDataArr[idx]); - fileName = Common::String::format("map.%d", i); + fileName = Common::String::format("map.%d", idx); readFileToBuffer(fileName, _hiResImageBuf); - uncompressBuffer(_hiResImageBuf, _mapArr[i]); + uncompressBuffer(_hiResImageBuf, _mapArr[idx]); + + _mapBitmapRefArr[idx]._setId1 = _mapArr[idx][0]; + _mapBitmapRefArr[idx]._setId2 = _mapArr[idx][1]; + + uint8 *mapSpecialTilePtr = &_mapArr[idx][2]; + + for (int i = 0; i < 100; ++i) { + _mapSpecialTiles[idx][i]._placeId = mapSpecialTilePtr[9 * i]; + _mapSpecialTiles[idx][i]._posX = mapSpecialTilePtr[9 * i + 1]; + _mapSpecialTiles[idx][i]._posY = mapSpecialTilePtr[9 * i + 2]; + _mapSpecialTiles[idx][i]._field3 = mapSpecialTilePtr[9 * i + 3]; + _mapSpecialTiles[idx][i]._triggerId = mapSpecialTilePtr[9 * i + 4]; + _mapSpecialTiles[idx][i]._field5_textId = READ_LE_UINT16(&mapSpecialTilePtr[9 * i + 5]); + _mapSpecialTiles[idx][i]._field7_textId = READ_LE_UINT16(&mapSpecialTilePtr[9 * i + 7]); + } + + uint8 *mapMonstersPtr = &_mapArr[idx][902]; + for (int i = 0; i < 64; ++i) { + _mapMonsters[idx][i]._possessivePronounSHL6 = mapMonstersPtr[29 * i]; + _mapMonsters[idx][i]._npcId = mapMonstersPtr[29 * i + 1]; + _mapMonsters[idx][i]._fullPlaceId = mapMonstersPtr[29 * i + 2]; + _mapMonsters[idx][i]._posX = mapMonstersPtr[29 * i + 3]; + _mapMonsters[idx][i]._posY = mapMonstersPtr[29 * i + 4]; + _mapMonsters[idx][i]._weaponItemId = mapMonstersPtr[29 * i + 5]; + _mapMonsters[idx][i]._maxDamageAbsorption = mapMonstersPtr[29 * i + 6]; + _mapMonsters[idx][i]._monsterRef = mapMonstersPtr[29 * i + 7]; + _mapMonsters[idx][i]._additionalInfo = mapMonstersPtr[29 * i + 8]; + _mapMonsters[idx][i]._talkTextId = mapMonstersPtr[29 * i + 9]; + _mapMonsters[idx][i]._groupSize = mapMonstersPtr[29 * i + 10]; + for (int j = 0; j < 9; ++j) + _mapMonsters[idx][i]._hitPoints[j] = READ_LE_INT16(&mapMonstersPtr[29 * i + 11 + j * 2]); + } + + uint8 *mapPtr = &_mapArr[idx][2758]; + for (int i = 0; i < 64; ++i) { + for (int j = 0; j < 64; ++j) + _mapGameMaps[idx][i][j] = *mapPtr++; + } + - _mapBitmapRefArr[i] = &_mapArr[i][0]; } } diff --git a/engines/efh/init.cpp b/engines/efh/init.cpp index f17d8eb67112..95ddff0a770e 100644 --- a/engines/efh/init.cpp +++ b/engines/efh/init.cpp @@ -140,6 +140,63 @@ uint8 NPCStruct::getPronoun() { return _possessivePronounSHL6 >> 6; } +void NPCStruct::synchronize(Common::Serializer &s) { + for (int idx = 0; idx < 11; ++idx) + s.syncAsByte(_name[idx]); + + s.syncAsByte(fieldB_textId); + s.syncAsByte(field_C); + s.syncAsByte(field_D); + s.syncAsByte(fieldE_textId); + s.syncAsByte(field_F); + s.syncAsByte(field_10); + s.syncAsByte(field11_NpcId); + s.syncAsSint16LE(field12_textId); + s.syncAsSint16LE(field14_textId); + s.syncAsSint32LE(_xp); + for (int idx = 0; idx < 15; ++idx) + s.syncAsByte(_activeScore[idx]); + + for (int idx = 0; idx < 11; ++idx) + s.syncAsByte(_passiveScore[idx]); + + for (int idx = 0; idx < 11; ++idx) + s.syncAsByte(_infoScore[idx]); + + s.syncAsByte(field_3F); + s.syncAsByte(field_40); + for (int idx = 0; idx < 10; ++idx) { + s.syncAsSint16LE(_inventory[idx]._ref); + s.syncAsByte(_inventory[idx]._stat1); + s.syncAsByte(_inventory[idx]._curHitPoints); + } + s.syncAsByte(_possessivePronounSHL6); + s.syncAsByte(_speed); + s.syncAsByte(field_6B); + s.syncAsByte(field_6C); + s.syncAsByte(field_6D); + s.syncAsByte(_defaultDefenseItemId); + s.syncAsByte(field_6F); + s.syncAsByte(field_70); + s.syncAsByte(field_71); + s.syncAsByte(field_72); + s.syncAsByte(field_73); + s.syncAsSint16LE(_hitPoints); + s.syncAsSint16LE(_maxHP); + s.syncAsByte(field_78); + s.syncAsSint16LE(field_79); + s.syncAsSint16LE(field_7B); + s.syncAsByte(field_7D); + s.syncAsByte(field_7E); + s.syncAsByte(field_7F); + s.syncAsByte(field_80); + s.syncAsByte(field_81); + s.syncAsByte(field_82); + s.syncAsByte(field_83); + s.syncAsByte(field_84); + s.syncAsByte(field_85); +} + uint8 MapMonster::getPronoun() { return _possessivePronounSHL6 >> 6; } @@ -182,8 +239,10 @@ EfhEngine::EfhEngine(OSystem *syst, const ADGameDescription *gd) : Engine(syst), _videoMode = 0; _graphicsStruct = nullptr; - for (int i = 0; i < 19; ++i) - _mapBitmapRefArr[i] = nullptr; + for (int i = 0; i < 19; ++i) { + _mapBitmapRefArr[i]._setId1 = 0; + _mapBitmapRefArr[i]._setId2 = 0; + } _defaultBoxColor = 0; @@ -229,7 +288,7 @@ EfhEngine::EfhEngine(OSystem *syst, const ADGameDescription *gd) : Engine(syst), for (int i = 0; i < 100; ++i) { _imp1PtrArray[i] = nullptr; - _mapSpecialTile[i].init(); + _mapSpecialTiles[_techId][i].init(); } for (int i = 0; i < 432; ++i) @@ -320,9 +379,9 @@ EfhEngine::EfhEngine(OSystem *syst, const ADGameDescription *gd) : Engine(syst), for (int i = 0; i < 19; ++i) { memset(_techDataArr[i], 0, ARRAYSIZE(_techDataArr[i])); memset(_mapArr[i], 0, ARRAYSIZE(_mapArr[i])); + memset(_mapMonsters[i], 0, ARRAYSIZE(_mapMonsters[i])); + memset(_mapGameMaps[i], 0, ARRAYSIZE(_mapGameMaps[i])); } - memset(_mapMonsters, 0, ARRAYSIZE(_mapMonsters)); - memset(_mapGameMap, 0, ARRAYSIZE(_mapGameMap)); memset(_imageSetSubFilesArray, 0, ARRAYSIZE(_imageSetSubFilesArray)); _regenCounter = 0; diff --git a/engines/efh/menu.cpp b/engines/efh/menu.cpp index 0661e0e7f87f..bfe6368794a8 100644 --- a/engines/efh/menu.cpp +++ b/engines/efh/menu.cpp @@ -929,9 +929,9 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in } // The original was duplicating this code in each branch of the previous random check. if (victims > 1) { - buffer1 = Common::String::format("%d %ss fall asleep!", victims, kEncounters[_mapMonsters[_teamMonsterIdArray[teamMonsterId]]._monsterRef]._name); + buffer1 = Common::String::format("%d %ss fall asleep!", victims, kEncounters[_mapMonsters[_techId][_teamMonsterIdArray[teamMonsterId]]._monsterRef]._name); } else { - buffer1 = Common::String::format("%d %s falls asleep!", victims, kEncounters[_mapMonsters[_teamMonsterIdArray[teamMonsterId]]._monsterRef]._name); + buffer1 = Common::String::format("%d %s falls asleep!", victims, kEncounters[_mapMonsters[_techId][_teamMonsterIdArray[teamMonsterId]]._monsterRef]._name); } _messageToBePrinted += buffer1; } @@ -969,9 +969,9 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in // : This part is only present in the original in the case < 50, but for me // it's missing in the other case as there's an effect (frozen enemies) but no feedback to the player if (victim > 1) { - buffer1 = Common::String::format("%d %ss are frozen in place!", victim, kEncounters[_mapMonsters[_teamMonsterIdArray[teamMonsterId]]._monsterRef]._name); + buffer1 = Common::String::format("%d %ss are frozen in place!", victim, kEncounters[_mapMonsters[_techId][_teamMonsterIdArray[teamMonsterId]]._monsterRef]._name); } else { - buffer1 = Common::String::format("%d %s is frozen in place!", victim, kEncounters[_mapMonsters[_teamMonsterIdArray[teamMonsterId]]._monsterRef]._name); + buffer1 = Common::String::format("%d %s is frozen in place!", victim, kEncounters[_mapMonsters[_techId][_teamMonsterIdArray[teamMonsterId]]._monsterRef]._name); } _messageToBePrinted += buffer1; // @@ -997,14 +997,14 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in if (getRandom(100) < 50) { for (uint counter = 0; counter < 9; ++counter) { if (getRandom(100) < 50) { - _mapMonsters[_teamMonsterIdArray[teamMonsterId]]._hitPoints[counter] = 0; + _mapMonsters[_techId][_teamMonsterIdArray[teamMonsterId]]._hitPoints[counter] = 0; } } } else { for (uint counter = 0; counter < 9; ++counter) { if (isMonsterActive(teamMonsterId, counter)) { if (getRandom(100) < 50) { - _mapMonsters[_teamMonsterIdArray[teamMonsterId]]._hitPoints[counter] = 0; + _mapMonsters[_techId][_teamMonsterIdArray[teamMonsterId]]._hitPoints[counter] = 0; } break; } @@ -1020,13 +1020,13 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in if (getRandom(100) < 50) { _messageToBePrinted += " A dark fiery whirlwind surrounds the poor victim...the power fades and all targeted die!"; for (uint counter = 0; counter < 9; ++counter) { - _mapMonsters[_teamMonsterIdArray[teamMonsterId]]._hitPoints[counter] = 0; + _mapMonsters[_techId][_teamMonsterIdArray[teamMonsterId]]._hitPoints[counter] = 0; } } else { _messageToBePrinted += " A dark fiery whirlwind surrounds the poor victim...the power fades and one victim dies!"; for (uint counter = 0; counter < 9; ++counter) { if (isMonsterActive(teamMonsterId, counter)) { - _mapMonsters[_teamMonsterIdArray[teamMonsterId]]._hitPoints[counter] = 0; + _mapMonsters[_techId][_teamMonsterIdArray[teamMonsterId]]._hitPoints[counter] = 0; } } } diff --git a/engines/efh/savegames.cpp b/engines/efh/savegames.cpp index ed64a0c5a235..c832e4702501 100644 --- a/engines/efh/savegames.cpp +++ b/engines/efh/savegames.cpp @@ -151,11 +151,37 @@ void EfhEngine::synchronize(Common::Serializer &s) { for (int j = 0; j < size; ++j) s.syncAsByte(_techDataArr[i][j]); + s.syncAsByte(_mapBitmapRefArr[i]._setId1); + s.syncAsByte(_mapBitmapRefArr[i]._setId2); + for (int idx = 0; idx < 100; ++idx) { + s.syncAsByte(_mapSpecialTiles[i][idx]._placeId); + s.syncAsByte(_mapSpecialTiles[i][idx]._posX); + s.syncAsByte(_mapSpecialTiles[i][idx]._posY); + s.syncAsByte(_mapSpecialTiles[i][idx]._field3); + s.syncAsByte(_mapSpecialTiles[i][idx]._triggerId); + s.syncAsUint16LE(_mapSpecialTiles[i][idx]._field5_textId); + s.syncAsUint16LE(_mapSpecialTiles[i][idx]._field7_textId); + } + + for (int idx = 0; idx < 64; ++idx) { + s.syncAsByte(_mapMonsters[i][idx]._possessivePronounSHL6); + s.syncAsByte(_mapMonsters[i][idx]._npcId); + s.syncAsByte(_mapMonsters[i][idx]._fullPlaceId); + s.syncAsByte(_mapMonsters[i][idx]._posX); + s.syncAsByte(_mapMonsters[i][idx]._posY); + s.syncAsByte(_mapMonsters[i][idx]._weaponItemId); + s.syncAsByte(_mapMonsters[i][idx]._maxDamageAbsorption); + s.syncAsByte(_mapMonsters[i][idx]._monsterRef); + s.syncAsByte(_mapMonsters[i][idx]._additionalInfo); + s.syncAsByte(_mapMonsters[i][idx]._talkTextId); + s.syncAsByte(_mapMonsters[i][idx]._groupSize); + for (int j = 0; j < 9; ++j) + s.syncAsSint16LE(_mapMonsters[i][idx]._hitPoints[j]); + } + size = ARRAYSIZE(_mapArr[i]); - for (int j = 0; j < size; ++j) + for (int j = 2758; j < size; ++j) s.syncAsByte(_mapArr[i][j]); - - _mapBitmapRefArr[i] = &_mapArr[i][0]; } // Dialog flags @@ -164,62 +190,9 @@ void EfhEngine::synchronize(Common::Serializer &s) { // NPCs for (int i = 0; i < 99; ++i) { - for (int idx = 0; idx < 11; ++idx) - s.syncAsByte(_npcBuf[i]._name[idx]); - - s.syncAsByte(_npcBuf[i].fieldB_textId); - s.syncAsByte(_npcBuf[i].field_C); - s.syncAsByte(_npcBuf[i].field_D); - s.syncAsByte(_npcBuf[i].fieldE_textId); - s.syncAsByte(_npcBuf[i].field_F); - s.syncAsByte(_npcBuf[i].field_10); - s.syncAsByte(_npcBuf[i].field11_NpcId); - s.syncAsSint16LE(_npcBuf[i].field12_textId); - s.syncAsSint16LE(_npcBuf[i].field14_textId); - s.syncAsSint32LE(_npcBuf[i]._xp); - for (int idx = 0; idx < 15; ++idx) - s.syncAsByte(_npcBuf[i]._activeScore[idx]); - - for (int idx = 0; idx < 11; ++idx) - s.syncAsByte(_npcBuf[i]._passiveScore[idx]); - - for (int idx = 0; idx < 11; ++idx) - s.syncAsByte(_npcBuf[i]._infoScore[idx]); - - s.syncAsByte(_npcBuf[i].field_3F); - s.syncAsByte(_npcBuf[i].field_40); - for (int idx = 0; idx < 10; ++idx) { - s.syncAsSint16LE(_npcBuf[i]._inventory[idx]._ref); - s.syncAsByte(_npcBuf[i]._inventory[idx]._stat1); - s.syncAsByte(_npcBuf[i]._inventory[idx]._curHitPoints); - } - s.syncAsByte(_npcBuf[i]._possessivePronounSHL6); - s.syncAsByte(_npcBuf[i]._speed); - s.syncAsByte(_npcBuf[i].field_6B); - s.syncAsByte(_npcBuf[i].field_6C); - s.syncAsByte(_npcBuf[i].field_6D); - s.syncAsByte(_npcBuf[i]._defaultDefenseItemId); - s.syncAsByte(_npcBuf[i].field_6F); - s.syncAsByte(_npcBuf[i].field_70); - s.syncAsByte(_npcBuf[i].field_71); - s.syncAsByte(_npcBuf[i].field_72); - s.syncAsByte(_npcBuf[i].field_73); - s.syncAsSint16LE(_npcBuf[i]._hitPoints); - s.syncAsSint16LE(_npcBuf[i]._maxHP); - s.syncAsByte(_npcBuf[i].field_78); - s.syncAsSint16LE(_npcBuf[i].field_79); - s.syncAsSint16LE(_npcBuf[i].field_7B); - s.syncAsByte(_npcBuf[i].field_7D); - s.syncAsByte(_npcBuf[i].field_7E); - s.syncAsByte(_npcBuf[i].field_7F); - s.syncAsByte(_npcBuf[i].field_80); - s.syncAsByte(_npcBuf[i].field_81); - s.syncAsByte(_npcBuf[i].field_82); - s.syncAsByte(_npcBuf[i].field_83); - s.syncAsByte(_npcBuf[i].field_84); - s.syncAsByte(_npcBuf[i].field_85); + _npcBuf[i].synchronize(s); } - + s.syncAsByte(_saveAuthorized); } diff --git a/engines/efh/script.cpp b/engines/efh/script.cpp index dfcb27bf0e09..2eb19348c935 100644 --- a/engines/efh/script.cpp +++ b/engines/efh/script.cpp @@ -315,7 +315,7 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos if (scriptExecuteFlag) { int16 tileId = findMapSpecialTileIndex(_mapPosX, _mapPosY); if (tileId != -1) - _mapSpecialTile[tileId]._posX = 0xFF; + _mapSpecialTiles[_techId][tileId]._posX = 0xFF; } break; case 0x13: @@ -402,7 +402,7 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos int16 tileId = findMapSpecialTileIndex(_mapPosX, _mapPosY); if (tileId != -1) { // Disable special tile - _mapSpecialTile[tileId]._posX = 0xFF; + _mapSpecialTiles[_techId][tileId]._posX = 0xFF; } _redrawNeededFl = true; } @@ -411,7 +411,7 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos buffer = script_readNumberArray(buffer, 3, scriptNumberArray); if (scriptExecuteFlag) { if (_largeMapFlag) { - _mapGameMap[scriptNumberArray[0]][scriptNumberArray[1]] = scriptNumberArray[2] & 0xFF; + _mapGameMaps[_techId][scriptNumberArray[0]][scriptNumberArray[1]] = scriptNumberArray[2] & 0xFF; } else { _curPlace[scriptNumberArray[0]][scriptNumberArray[1]] = scriptNumberArray[2] & 0xFF; } @@ -423,7 +423,7 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos int16 tileId = findMapSpecialTileIndex(scriptNumberArray[0], scriptNumberArray[1]); if (tileId != -1) { // Disable tile - _mapSpecialTile[tileId]._posX = 0xFF; + _mapSpecialTiles[_techId][tileId]._posX = 0xFF; } } break; @@ -433,10 +433,10 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos int16 tileId = findMapSpecialTileIndex(scriptNumberArray[0], scriptNumberArray[1]); if (tileId != -1) { // Disable tile - _mapSpecialTile[tileId]._posX = 0xFF; + _mapSpecialTiles[_techId][tileId]._posX = 0xFF; } - _mapSpecialTile[scriptNumberArray[2]]._posX = scriptNumberArray[0]; - _mapSpecialTile[scriptNumberArray[2]]._posY = scriptNumberArray[1]; + _mapSpecialTiles[_techId][scriptNumberArray[2]]._posX = scriptNumberArray[0]; + _mapSpecialTiles[_techId][scriptNumberArray[2]]._posY = scriptNumberArray[1]; } break; case 0x1C: From 7b1e1c7362e750fa5b4d386ca0c70de34e188904 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Mon, 16 Jan 2023 08:47:03 +0100 Subject: [PATCH 250/412] EFH: Fix missing bit in savegames --- engines/efh/savegames.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/engines/efh/savegames.cpp b/engines/efh/savegames.cpp index c832e4702501..6e43acc9d797 100644 --- a/engines/efh/savegames.cpp +++ b/engines/efh/savegames.cpp @@ -179,9 +179,10 @@ void EfhEngine::synchronize(Common::Serializer &s) { s.syncAsSint16LE(_mapMonsters[i][idx]._hitPoints[j]); } - size = ARRAYSIZE(_mapArr[i]); - for (int j = 2758; j < size; ++j) - s.syncAsByte(_mapArr[i][j]); + for (int x = 0; x < 64; ++x) { + for (int y = 0; y < 64; ++y) + s.syncAsByte(_mapGameMaps[i][x][y]); + } } // Dialog flags From f997af97023e8e0b1848e375a8c5918743909523 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Mon, 16 Jan 2023 23:09:05 +0100 Subject: [PATCH 251/412] EFH: Fix (hopefully) several Clang warnings --- engines/efh/efh.cpp | 6 +++--- engines/efh/efh.h | 2 +- engines/efh/fight.cpp | 2 +- engines/efh/menu.cpp | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 73ff6b5e8a78..21c361071464 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -2284,10 +2284,10 @@ int16 EfhEngine::countMonsterGroupMembers(int16 monsterGroup) { return result; } -int16 EfhEngine::getXPLevel(int32 xp) { - debugC(6, kDebugEngine, "getXPLevel %ld", xp); +uint16 EfhEngine::getXPLevel(uint32 xp) { + debugC(6, kDebugEngine, "getXPLevel %u", xp); - int16 level = 0; + uint16 level = 0; int16 nextLevelXP = 1500; int32 wrkXp = xp; diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 8d4f84b1e087..a927afaeda77 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -362,7 +362,7 @@ class EfhEngine : public Engine { void computeInitiatives(); void redrawScreenForced(); int16 countMonsterGroupMembers(int16 monsterGroup); - int16 getXPLevel(int32 xp); + uint16 getXPLevel(uint32 xp); bool isItemCursed(int16 itemId); bool hasObjectEquipped(int16 charId, int16 objectId); void setMapMonsterAggressivenessAndMovementType(int16 id, uint8 mask, bool groupFl); diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index e094730ac1e2..726b80d503ba 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -1169,7 +1169,7 @@ void EfhEngine::drawCombatScreen(int16 charId, bool whiteFl, bool drawFl) { void EfhEngine::getXPAndSearchCorpse(int16 charId, Common::String namePt1, Common::String namePt2, int16 monsterId) { debugC(3, kDebugFight, "getXPAndSearchCorpse %d %s%s %d", charId, namePt1.c_str(), namePt2.c_str(), monsterId); - int16 oldXpLevel = getXPLevel(_npcBuf[charId]._xp); + uint16 oldXpLevel = getXPLevel(_npcBuf[charId]._xp); _npcBuf[charId]._xp += kEncounters[_mapMonsters[_techId][monsterId]._monsterRef]._xpGiven; if (getXPLevel(_npcBuf[charId]._xp) > oldXpLevel) { diff --git a/engines/efh/menu.cpp b/engines/efh/menu.cpp index bfe6368794a8..194ae4f56077 100644 --- a/engines/efh/menu.cpp +++ b/engines/efh/menu.cpp @@ -284,7 +284,7 @@ void EfhEngine::displayCharacterSummary(int16 curMenuLine, int16 npcId) { buffer1 = Common::String::format("Level: %d", getXPLevel(_npcBuf[npcId]._xp)); setTextPos(146, 36); displayStringAtTextPos(buffer1); - buffer1 = Common::String::format("XP: %lu", _npcBuf[npcId]._xp); + buffer1 = Common::String::format("XP: %u", _npcBuf[npcId]._xp); setTextPos(227, 36); displayStringAtTextPos(buffer1); buffer1 = Common::String::format("Speed: %d", _npcBuf[npcId]._speed); From e501c8a8c85b951d508433334728b2f4397133c2 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Tue, 17 Jan 2023 07:17:41 +0100 Subject: [PATCH 252/412] EFH: Remove saveEfhGame, directly call the appropriate dialog --- engines/efh/efh.cpp | 24 +++++++----------------- engines/efh/efh.h | 1 - engines/efh/menu.cpp | 3 +-- 3 files changed, 8 insertions(+), 20 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 21c361071464..19ebf33846de 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -173,15 +173,13 @@ Common::Error EfhEngine::run() { if (input == Common::KEYCODE_y) { displayMenuAnswerString("-> Yes <-", 24, 296, 169); getInput(2); - saveEfhGame(); - clearBottomTextZone_2(0); - displayLowStatusScreen(true); + saveGameDialog(); } else { displayMenuAnswerString("-> No!!! <-", 24, 296, 169); getInput(2); - clearBottomTextZone_2(0); - displayLowStatusScreen(true); } + clearBottomTextZone_2(0); + displayLowStatusScreen(true); } break; @@ -196,16 +194,13 @@ Common::Error EfhEngine::run() { if (input == Common::KEYCODE_y) { displayMenuAnswerString("-> Yes <-", 24, 296, 169); getInput(2); -// loadEfhGame(); - saveEfhGame(); - clearBottomTextZone_2(0); - displayLowStatusScreen(true); + loadGameDialog(); } else { displayMenuAnswerString("-> No!!! <-", 24, 296, 169); getInput(2); - clearBottomTextZone_2(0); - displayLowStatusScreen(true); } + clearBottomTextZone_2(0); + displayLowStatusScreen(true); } break; default: @@ -291,7 +286,7 @@ void EfhEngine::songDelay(int delay) { } void EfhEngine::playNote(int frequencyIndex, int totalDelay) { - debug("playNote %d %ld", frequencyIndex, totalDelay); + debug("playNote %d %d", frequencyIndex, totalDelay); } Common::KeyCode EfhEngine::playSong(uint8 *buffer) { @@ -2584,11 +2579,6 @@ void EfhEngine::loadEfhGame() { loadPlacesFile(_fullPlaceId, true); } -void EfhEngine::saveEfhGame() { - warning("STUB - saveEfhGame"); - openMainMenuDialog(); -} - uint8 EfhEngine::getMapTileInfo(int16 mapPosX, int16 mapPosY) { debugC(3, kDebugEngine, "getMapTileInfo %d-%d", mapPosX, mapPosY); diff --git a/engines/efh/efh.h b/engines/efh/efh.h index a927afaeda77..16c6624689f8 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -300,7 +300,6 @@ class EfhEngine : public Engine { void restoreAnimImageSetId(); void checkProtection(); void loadEfhGame(); - void saveEfhGame(); void copyCurrentPlaceToBuffer(int16 id); uint8 getMapTileInfo(int16 mapPosX, int16 mapPosY); void writeTechAndMapFiles(); diff --git a/engines/efh/menu.cpp b/engines/efh/menu.cpp index 194ae4f56077..9fefb458b090 100644 --- a/engines/efh/menu.cpp +++ b/engines/efh/menu.cpp @@ -126,11 +126,10 @@ bool EfhEngine::handleDeathMenu() { Common::KeyCode input = waitForKey(); switch (input) { case Common::KEYCODE_l: - // SaveEfhGame opens the GUI save/load screen. It's not possible to save at this point (_saveAuthorizd is false). // If the user actually loads a savegame, it'll get _saveAuthorized from the savegame (always true) and will set 'found' to true. // If 'found' remains false, it means the user cancelled the loading and still needs to take a decision // Original is calling loadEfhGame() because there's only one savegame, so it's not ambiguous - saveEfhGame(); + loadGameDialog(); found = _saveAuthorized; break; case Common::KEYCODE_q: From 0b9d9b1446a5306831e5f66c5b83a6b8432d618d Mon Sep 17 00:00:00 2001 From: Strangerke Date: Tue, 17 Jan 2023 23:44:08 +0100 Subject: [PATCH 253/412] EFH: Rename displayEncounterInfo() --- engines/efh/efh.h | 2 +- engines/efh/fight.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 16c6624689f8..ff002c889bef 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -392,7 +392,7 @@ class EfhEngine : public Engine { void getXPAndSearchCorpse(int16 charId, Common::String namePt1, Common::String namePt2, int16 monsterId); bool characterSearchesMonsterCorpse(int16 charId, int16 monsterId); void addReactionText(int16 id); - void sub1C4CA(bool WhiteFl); + void displayEncounterInfo(bool WhiteFl); int16 getWeakestMobster(int16 groupNumber); int16 getCharacterScore(int16 charId, int16 itemId); bool checkSpecialItemsOnCurrentPlace(int16 itemId); diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index 726b80d503ba..9f2acd720b08 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -1156,7 +1156,7 @@ void EfhEngine::drawCombatScreen(int16 charId, bool whiteFl, bool drawFl) { drawColoredRect(200, 112, 278, 132, 0); displayCenteredString("'T' for Terrain", 128, 303, 117); displayBoxWithText("", 1, 0, false); - sub1C4CA(whiteFl); + displayEncounterInfo(whiteFl); displayCombatMenu(charId); displayLowStatusScreen(false); } @@ -1329,8 +1329,8 @@ void EfhEngine::addReactionText(int16 id) { } } -void EfhEngine::sub1C4CA(bool whiteFl) { - debugC(5, kDebugFight, "sub1C4CA %s", whiteFl ? "True" : "False"); +void EfhEngine::displayEncounterInfo(bool whiteFl) { + debugC(5, kDebugFight, "displayEncounterInfo %s", whiteFl ? "True" : "False"); int16 textPosY = 20; for (uint counter = 0; counter < 5; ++counter) { From 03746ad3227f09d054d78fa16e6e160a1eea8801 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Wed, 18 Jan 2023 23:52:03 +0100 Subject: [PATCH 254/412] EFH: some renaming in handleFight_lastAction_A, invert some if statement to reduce code depth --- engines/efh/fight.cpp | 349 +++++++++++++++++++++--------------------- 1 file changed, 176 insertions(+), 173 deletions(-) diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index 9f2acd720b08..8842f7dfd740 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -425,203 +425,206 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { int16 teamCharItemId = getEquippedExclusiveType(_teamCharId[teamCharId], 9, true); if (teamCharItemId == 0x7FFF) teamCharItemId = 0x3F; - int16 monsterGroupNumber = _teamNextAttack[teamCharId]; - if (monsterGroupNumber == 0x64) - monsterGroupNumber = 0; + int16 minMonsterGroupId = _teamNextAttack[teamCharId]; + if (minMonsterGroupId == 0x64) + minMonsterGroupId = 0; - if (monsterGroupNumber == -1) + if (minMonsterGroupId == -1) return; - int16 var58; + + int16 maxMonsterGroupId; if (_items[teamCharItemId]._range == 4) - var58 = 5; + maxMonsterGroupId = 5; else - var58 = monsterGroupNumber + 1; + maxMonsterGroupId = minMonsterGroupId + 1; - int16 var54; - int16 teamMemberId; + int16 minTeamMemberId; + int16 maxTeamMemberId; if (_items[teamCharItemId]._range < 3) { - teamMemberId = getWeakestMobster(monsterGroupNumber); - var54 = teamMemberId + 1; + minTeamMemberId = getWeakestMobster(minMonsterGroupId); + maxTeamMemberId = minTeamMemberId + 1; } else { - teamMemberId = 0; - var54 = 9; + minTeamMemberId = 0; + maxTeamMemberId = 9; } - if (teamMemberId != -1) { - bool var6E = true; - for (int16 groupId = monsterGroupNumber; groupId < var58; ++groupId) { - if (_teamMonsterIdArray[groupId] == -1) - continue; + if (minTeamMemberId == -1) + return; - for (int16 ctrMobsterId = teamMemberId; ctrMobsterId < var54; ++ctrMobsterId) { - if (isMonsterActive(groupId, ctrMobsterId) && var6E) { - bool noticedFl; - if (!checkMonsterMovementType(groupId, true)) { - setMapMonsterAggressivenessAndMovementType(groupId, 9, true); - _unk2C8AA += 500; - noticedFl = true; - } else - noticedFl = false; - - int16 var76 = getRandom(_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._maxDamageAbsorption); - int16 ennemyPronoun = _npcBuf[_teamCharId[teamCharId]].getPronoun(); - int16 monsterId = _teamMonsterIdArray[groupId]; - int16 characterPronoun = kEncounters[_mapMonsters[_techId][monsterId]._monsterRef]._nameArticle; - int16 charScore = getCharacterScore(_teamCharId[teamCharId], teamCharItemId); - int16 hitPointsBefore = _mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId]; - int16 hitCount = 0; - int16 originalDamage = 0; - int16 damagePointsAbsorbed = 0; - int16 attackSpeed = _items[teamCharItemId]._attacks * _npcBuf[_teamCharId[teamCharId]]._speed; - - // Action A - Loop var84 - Start - for (int var84 = 0; var84 < attackSpeed; ++var84) { - if (getRandom(100) < charScore) { - ++hitCount; - if (!hasAdequateDefense(_teamMonsterIdArray[groupId], _items[teamCharItemId]._attackType)) { - int16 var7C = getRandom(_items[teamCharItemId]._damage); - int16 varInt = var7C - var76; - if (varInt > 0) { - originalDamage += varInt; - damagePointsAbsorbed += var76; - } else { - damagePointsAbsorbed += var7C; - } - } + bool var6E = true; + for (int16 groupId = minMonsterGroupId; groupId < maxMonsterGroupId; ++groupId) { + if (_teamMonsterIdArray[groupId] == -1) + continue; + + for (int16 ctrMobsterId = minTeamMemberId; ctrMobsterId < maxTeamMemberId; ++ctrMobsterId) { + if (!isMonsterActive(groupId, ctrMobsterId) || !var6E) + return; + + bool noticedFl; + if (!checkMonsterMovementType(groupId, true)) { + setMapMonsterAggressivenessAndMovementType(groupId, 9, true); + _unk2C8AA += 500; + noticedFl = true; + } else + noticedFl = false; + + int16 randomDamageAbsorbed = getRandom(_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._maxDamageAbsorption); + int16 ennemyPronoun = _npcBuf[_teamCharId[teamCharId]].getPronoun(); + int16 monsterId = _teamMonsterIdArray[groupId]; + int16 characterPronoun = kEncounters[_mapMonsters[_techId][monsterId]._monsterRef]._nameArticle; + int16 charScore = getCharacterScore(_teamCharId[teamCharId], teamCharItemId); + int16 hitPointsBefore = _mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId]; + int16 hitCount = 0; + int16 originalDamage = 0; + int16 damagePointsAbsorbed = 0; + int16 attackSpeed = _items[teamCharItemId]._attacks * _npcBuf[_teamCharId[teamCharId]]._speed; + + // Action A - Loop var84 - Start + for (int var84 = 0; var84 < attackSpeed; ++var84) { + if (getRandom(100) < charScore) { + ++hitCount; + if (!hasAdequateDefense(_teamMonsterIdArray[groupId], _items[teamCharItemId]._attackType)) { + int16 var7C = getRandom(_items[teamCharItemId]._damage); + int16 varInt = var7C - randomDamageAbsorbed; + if (varInt > 0) { + originalDamage += varInt; + damagePointsAbsorbed += randomDamageAbsorbed; + } else { + damagePointsAbsorbed += var7C; } } - // Action A - Loop var84 - End + } + } + // Action A - Loop var84 - End - if (originalDamage < 0) - originalDamage = 0; + if (originalDamage < 0) + originalDamage = 0; - int16 hitPoints = originalDamage + damagePointsAbsorbed; + int16 hitPoints = originalDamage + damagePointsAbsorbed; - if (!checkSpecialItemsOnCurrentPlace(teamCharItemId)) - hitCount = 0; + if (!checkSpecialItemsOnCurrentPlace(teamCharItemId)) + hitCount = 0; - if (hitCount > 0) { - _mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] -= originalDamage; - if (hitCount > 1) { - _attackBuffer = Common::String::format("%d times ", hitCount); - } else { - _attackBuffer = ""; - } - } - int16 verbId = (3 * _items[teamCharItemId]._attackType + 1) + getRandom(3) - 1; - if (characterPronoun == 2) { - _characterNamePt1 = "The "; + if (hitCount > 0) { + _mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] -= originalDamage; + if (hitCount > 1) { + _attackBuffer = Common::String::format("%d times ", hitCount); + } else { + _attackBuffer = ""; + } + } + int16 verbId = (3 * _items[teamCharItemId]._attackType + 1) + getRandom(3) - 1; + if (characterPronoun == 2) { + _characterNamePt1 = "The "; + } else { + _characterNamePt1 = ""; + } + + if (ennemyPronoun == 2) { + _enemyNamePt1 = "The "; + } else { + _enemyNamePt1 = ""; + } + + _characterNamePt2 = kEncounters[_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._monsterRef]._name; + _enemyNamePt2 = _npcBuf[_teamCharId[teamCharId]]._name; + _nameBuffer = _items[teamCharItemId]._name; + if (checkSpecialItemsOnCurrentPlace(teamCharItemId)) { + // Action A - Check damages - Start + if (hitCount == 0) { + _messageToBePrinted = Common::String::format("%s%s %s at %s%s with %s %s, but misses!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[verbId], _characterNamePt1.c_str(), _characterNamePt2.c_str(), kPossessive[ennemyPronoun], _nameBuffer.c_str()); + } else if (hitPoints <= 0) { + _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s, but does no damage!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[verbId], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[ennemyPronoun], _nameBuffer.c_str()); + } else if (hitPoints == 1) { + _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s for 1 point", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[verbId], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[ennemyPronoun], _nameBuffer.c_str()); + if (_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] <= 0) { + getDeathTypeDescription(groupId, teamCharId + 1000); + getXPAndSearchCorpse(_teamCharId[teamCharId], _enemyNamePt1, _enemyNamePt2, _teamMonsterIdArray[groupId]); } else { - _characterNamePt1 = ""; + _messageToBePrinted += "!"; } - - if (ennemyPronoun == 2) { - _enemyNamePt1 = "The "; + } else { + _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s for %d points", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[verbId], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[ennemyPronoun], _nameBuffer.c_str(), hitPoints); + if (_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] <= 0) { + getDeathTypeDescription(groupId, teamCharId + 1000); + getXPAndSearchCorpse(_teamCharId[teamCharId], _enemyNamePt1, _enemyNamePt2, _teamMonsterIdArray[groupId]); } else { - _enemyNamePt1 = ""; + _messageToBePrinted += "!"; } - - _characterNamePt2 = kEncounters[_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._monsterRef]._name; - _enemyNamePt2 = _npcBuf[_teamCharId[teamCharId]]._name; - _nameBuffer = _items[teamCharItemId]._name; - if (checkSpecialItemsOnCurrentPlace(teamCharItemId)) { - // Action A - Check damages - Start - if (hitCount == 0) { - _messageToBePrinted = Common::String::format("%s%s %s at %s%s with %s %s, but misses!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[verbId], _characterNamePt1.c_str(), _characterNamePt2.c_str(), kPossessive[ennemyPronoun], _nameBuffer.c_str()); - } else if (hitPoints <= 0) { - _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s, but does no damage!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[verbId], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[ennemyPronoun], _nameBuffer.c_str()); - } else if (hitPoints == 1) { - _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s for 1 point", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[verbId], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[ennemyPronoun], _nameBuffer.c_str()); - if (_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] <= 0) { - getDeathTypeDescription(groupId, teamCharId + 1000); - getXPAndSearchCorpse(_teamCharId[teamCharId], _enemyNamePt1, _enemyNamePt2, _teamMonsterIdArray[groupId]); - } else { - _messageToBePrinted += "!"; - } - } else { - _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s for %d points", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[verbId], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[ennemyPronoun], _nameBuffer.c_str(), hitPoints); - if (_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] <= 0) { - getDeathTypeDescription(groupId, teamCharId + 1000); - getXPAndSearchCorpse(_teamCharId[teamCharId], _enemyNamePt1, _enemyNamePt2, _teamMonsterIdArray[groupId]); - } else { - _messageToBePrinted += "!"; - } - } - // Action A - Check damages - End - - // Action A - Add reaction text - Start - if (hitCount != 0 && originalDamage > 0 && getRandom(100) <= 35 && _mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] > 0) { - if (_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] - 5 <= originalDamage) { - addReactionText(kEfhReactionReels); - } else if (_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] < hitPointsBefore / 8) { - addReactionText(kEfhReactionCriesOut); - } else if (_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] < hitPointsBefore / 4) { - addReactionText(kEfhReactionFalters); - } else if (_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] < hitPointsBefore / 2) { - addReactionText(kEfhReactionWinces); - } else if (_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] < hitPointsBefore / 3) { - // CHECKME: Doesn't make any sense to check /3 after /2... I don't get it. Looks like an original bug - addReactionText(kEfhReactionScreams); - } else if (hitPointsBefore / 8 >= originalDamage) { - addReactionText(kEfhReactionChortles); - } else if (originalDamage == 0 && getRandom(100) < 35) { - // CHECKME: "originalDamage == 0" is always false as it's checked beforehand. Looks like another original bug - addReactionText(kEfhReactionLaughs); - } - } - // Action A - Add reaction text - End - - // Action A - Add armor absorb text - Start - if (var76 && hitCount && _mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] > 0) { - if (damagePointsAbsorbed <= 1) - _messageToBePrinted += Common::String::format(" %s%s's armor absorbs 1 point!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); - else - _messageToBePrinted += Common::String::format(" %s%s's armor absorbs %d points!", _characterNamePt1.c_str(), _characterNamePt2.c_str(), damagePointsAbsorbed); - } - // Action A - Add armor absorb text - End - - if (noticedFl) - _messageToBePrinted += Common::String(" Your actions do not go un-noticed..."); - - // Action A - Check item durability - Start - int16 npcId = _teamCharId[teamCharId]; - - // get equipped inventory slot with exclusiveType == 9 - uint16 exclusiveInventoryId = getEquippedExclusiveType(npcId, 9, false); - if (exclusiveInventoryId != 0x7FFF && _npcBuf[npcId]._inventory[exclusiveInventoryId].getUsesLeft() != 0x7F) { - int16 usesLeft = _npcBuf[npcId]._inventory[exclusiveInventoryId].getUsesLeft(); - --usesLeft; - if (usesLeft <= 0) { - _messageToBePrinted += Common::String::format(" * %s%s's %s breaks!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), _nameBuffer.c_str()); - setCharacterObjectToBroken(npcId, exclusiveInventoryId); - var6E = false; - } else { - _npcBuf[npcId]._inventory[exclusiveInventoryId]._stat1 = (_npcBuf[npcId]._inventory[exclusiveInventoryId]._stat1 & 80) + usesLeft; - } - } - // Action A - Check item durability - End - - // Action A - Check effect - Start - if (_items[teamCharItemId]._specialEffect == 1 && _mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] > 0) { - if (getRandom(100) < 35) { - _teamMonsterEffects[groupId]._effect[ctrMobsterId] = 1; - _teamMonsterEffects[groupId]._duration[ctrMobsterId] = getRandom(10); - _messageToBePrinted += Common::String::format(" %s%s falls asleep!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); - } - } else if (_items[teamCharItemId]._specialEffect == 2 && _mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] > 0) { - _teamMonsterEffects[groupId]._effect[ctrMobsterId] = 2; - _teamMonsterEffects[groupId]._duration[ctrMobsterId] = getRandom(10); - _messageToBePrinted += Common::String::format(" %s%s is frozen!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); - } - // Action A - Check effect - End + } + // Action A - Check damages - End + + // Action A - Add reaction text - Start + if (hitCount != 0 && originalDamage > 0 && getRandom(100) <= 35 && _mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] > 0) { + if (_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] - 5 <= originalDamage) { + addReactionText(kEfhReactionReels); + } else if (_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] < hitPointsBefore / 8) { + addReactionText(kEfhReactionCriesOut); + } else if (_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] < hitPointsBefore / 4) { + addReactionText(kEfhReactionFalters); + } else if (_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] < hitPointsBefore / 2) { + addReactionText(kEfhReactionWinces); + } else if (_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] < hitPointsBefore / 3) { + // CHECKME: Doesn't make any sense to check /3 after /2... I don't get it. Looks like an original bug + addReactionText(kEfhReactionScreams); + } else if (hitPointsBefore / 8 >= originalDamage) { + addReactionText(kEfhReactionChortles); + } else if (originalDamage == 0 && getRandom(100) < 35) { + // CHECKME: "originalDamage == 0" is always false as it's checked beforehand. Looks like another original bug + addReactionText(kEfhReactionLaughs); + } + } + // Action A - Add reaction text - End + + // Action A - Add armor absorb text - Start + if (randomDamageAbsorbed && hitCount && _mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] > 0) { + if (damagePointsAbsorbed <= 1) + _messageToBePrinted += Common::String::format(" %s%s's armor absorbs 1 point!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); + else + _messageToBePrinted += Common::String::format(" %s%s's armor absorbs %d points!", _characterNamePt1.c_str(), _characterNamePt2.c_str(), damagePointsAbsorbed); + } + // Action A - Add armor absorb text - End + + if (noticedFl) + _messageToBePrinted += Common::String(" Your actions do not go un-noticed..."); + + // Action A - Check item durability - Start + int16 npcId = _teamCharId[teamCharId]; + + // get equipped inventory slot with exclusiveType == 9 + uint16 exclusiveInventoryId = getEquippedExclusiveType(npcId, 9, false); + if (exclusiveInventoryId != 0x7FFF && _npcBuf[npcId]._inventory[exclusiveInventoryId].getUsesLeft() != 0x7F) { + int16 usesLeft = _npcBuf[npcId]._inventory[exclusiveInventoryId].getUsesLeft(); + --usesLeft; + if (usesLeft <= 0) { + _messageToBePrinted += Common::String::format(" * %s%s's %s breaks!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), _nameBuffer.c_str()); + setCharacterObjectToBroken(npcId, exclusiveInventoryId); + var6E = false; } else { - _messageToBePrinted = Common::String::format("%s%s tries to use %s %s, but it doesn't work!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPossessive[ennemyPronoun], _nameBuffer.c_str()); + _npcBuf[npcId]._inventory[exclusiveInventoryId]._stat1 = (_npcBuf[npcId]._inventory[exclusiveInventoryId]._stat1 & 80) + usesLeft; } - - genericGenerateSound(_items[teamCharItemId]._attackType, hitCount); - displayBoxWithText(_messageToBePrinted, 1, 2, true); } + // Action A - Check item durability - End + + // Action A - Check effect - Start + if (_items[teamCharItemId]._specialEffect == 1 && _mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] > 0) { + if (getRandom(100) < 35) { + _teamMonsterEffects[groupId]._effect[ctrMobsterId] = 1; + _teamMonsterEffects[groupId]._duration[ctrMobsterId] = getRandom(10); + _messageToBePrinted += Common::String::format(" %s%s falls asleep!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); + } + } else if (_items[teamCharItemId]._specialEffect == 2 && _mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] > 0) { + _teamMonsterEffects[groupId]._effect[ctrMobsterId] = 2; + _teamMonsterEffects[groupId]._duration[ctrMobsterId] = getRandom(10); + _messageToBePrinted += Common::String::format(" %s%s is frozen!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); + } + // Action A - Check effect - End + } else { + _messageToBePrinted = Common::String::format("%s%s tries to use %s %s, but it doesn't work!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPossessive[ennemyPronoun], _nameBuffer.c_str()); } + + genericGenerateSound(_items[teamCharItemId]._attackType, hitCount); + displayBoxWithText(_messageToBePrinted, 1, 2, true); } } } From a95b4960e049df3bb5ea4314c20023da4350294e Mon Sep 17 00:00:00 2001 From: Strangerke Date: Fri, 20 Jan 2023 00:30:17 +0100 Subject: [PATCH 255/412] EFH: Split handleFight_MobstersAttack out of handleFight() --- engines/efh/efh.h | 2 +- engines/efh/fight.cpp | 423 +++++++++++++++++++++--------------------- 2 files changed, 215 insertions(+), 210 deletions(-) diff --git a/engines/efh/efh.h b/engines/efh/efh.h index ff002c889bef..03e91a7c5169 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -378,6 +378,7 @@ class EfhEngine : public Engine { void handleFight_lastAction_D(int16 teamCharId); void handleFight_lastAction_H(int16 teamCharId); bool handleFight_lastAction_U(int16 teamCharId); + void handleFight_MobstersAttack(int groupId); bool isTPK(); bool isMonsterAlreadyFighting(int16 monsterId, int16 teamMonsterId); void createOpponentList(int16 monsterTeamId); @@ -620,7 +621,6 @@ class EfhEngine : public Engine { int16 _regenCounter; }; - } // End of namespace Efh #endif diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index 8842f7dfd740..e3fe6a93aae5 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -108,8 +108,7 @@ bool EfhEngine::handleFight(int16 monsterId) { return true; } - int16 varInt = getTeamMonsterAnimId(); - displayAnimFrames(varInt, true); + displayAnimFrames(getTeamMonsterAnimId(), true); for (int counter = 0; counter < _teamSize; ++counter) { _teamPctVisible[counter] = 100; _teamPctDodgeMiss[counter] = 65; @@ -158,213 +157,7 @@ bool EfhEngine::handleFight(int16 monsterId) { } } } else if (checkMonsterMovementType(monsterGroupIdOrMonsterId, true)) { - // handleFight - Loop on mobsterId - Start - for (uint ctrMobsterId = 0; ctrMobsterId < 9; ++ctrMobsterId) { - if (isMonsterActive(monsterGroupIdOrMonsterId, ctrMobsterId)) { - int16 monsterWeaponItemId = _mapMonsters[_techId][_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._weaponItemId; - if (monsterWeaponItemId == 0xFF) - monsterWeaponItemId = 0x3F; - int16 teamMemberId = -1; - int16 var54; - if (_items[monsterWeaponItemId]._range < 3) { - for (uint var84 = 0; var84 < 10; ++var84) { - teamMemberId = getRandom(_teamSize) - 1; - if (checkWeaponRange(_teamMonsterIdArray[monsterGroupIdOrMonsterId], monsterWeaponItemId) && isTeamMemberStatusNormal(teamMemberId) && getRandom(100) < _teamPctVisible[teamMemberId]) { - break; - } - teamMemberId = -1; - } - var54 = teamMemberId + 1; - } else { - teamMemberId = 0; - var54 = _teamSize; - } - if (teamMemberId != -1) { - // handleFight - Loop on var7E - Start - for (int16 var7E = teamMemberId; var7E < var54; ++var7E) { - if (_teamCharId[var7E] == -1 || !isTeamMemberStatusNormal(var7E)) - continue; - - int16 var76 = getRandom(getEquipmentDefense(_teamCharId[var7E], false)); - varInt = _teamMonsterIdArray[monsterGroupIdOrMonsterId]; - int16 ennemyPronoun = kEncounters[_mapMonsters[_techId][varInt]._monsterRef]._nameArticle; - int16 characterPronoun = _npcBuf[_teamCharId[var7E]].getPronoun(); - varInt = _items[monsterWeaponItemId].field_13; - _teamPctDodgeMiss[var7E] += (varInt * 5); - int16 var62 = 0; - int16 hitPoints = 0; - int16 originalDamage = 0; - int16 damagePointsAbsorbed = 0; - int16 var64 = _mapMonsters[_techId][_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._npcId * _items[monsterWeaponItemId]._attacks; - for (int var84 = 0; var84 < var64; ++var84) { - // handleFight - Loop var84 on var64 (objectId) - Start - if (getRandom(100) > _teamPctDodgeMiss[var7E]) - continue; - - ++var62; - - if (hasAdequateDefenseNPC(_teamCharId[var7E], _items[monsterWeaponItemId]._attackType)) - continue; - - int16 var7C = getRandom(_items[monsterWeaponItemId]._damage); - varInt = var7C - var76; - - if (varInt > 0) { - damagePointsAbsorbed += var76; - originalDamage += varInt; - } else { - damagePointsAbsorbed += var7C; - } - // handleFight - Loop var84 on var64 (objectId) - End - } - - if (originalDamage < 0) - originalDamage = 0; - - hitPoints = originalDamage + damagePointsAbsorbed; - if (!checkSpecialItemsOnCurrentPlace(monsterWeaponItemId)) - var62 = 0; - - if (var62 > 0) { - _npcBuf[_teamCharId[var7E]]._hitPoints -= originalDamage; - if (var62 > 1) - _attackBuffer = Common::String::format("%d times ", var62); - else - _attackBuffer = ""; - } - - int16 var68 = _items[monsterWeaponItemId]._attackType + 1; - int16 var6A = getRandom(3); - if (characterPronoun == 2) - _characterNamePt1 = "The "; - else - _characterNamePt1 = ""; - - if (ennemyPronoun == 2) - _enemyNamePt1 = "The "; - else - _enemyNamePt1 = ""; - - _enemyNamePt2 = kEncounters[_mapMonsters[_techId][_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._monsterRef]._name; - _characterNamePt2 = _npcBuf[_teamCharId[var7E]]._name; - _nameBuffer = _items[monsterWeaponItemId]._name; - if (checkSpecialItemsOnCurrentPlace(monsterWeaponItemId)) { - // handleFight - check damages - Start - if (var62 == 0) { - _messageToBePrinted = Common::String::format("%s%s %s at %s%s with %s %s, but misses!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1.c_str(), _characterNamePt2.c_str(), kPossessive[ennemyPronoun], _nameBuffer.c_str()); - } else if (hitPoints <= 0) { - _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s, but does no damage!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[ennemyPronoun], _nameBuffer.c_str()); - } else if (hitPoints == 1) { - _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s for 1 point", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[ennemyPronoun], _nameBuffer.c_str()); - if (_npcBuf[_teamCharId[var7E]]._hitPoints <= 0) - getDeathTypeDescription(var7E + 1000, monsterGroupIdOrMonsterId); - else - _messageToBePrinted += "!"; - } else { - _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s for %d points", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[ennemyPronoun], _nameBuffer.c_str(), hitPoints); - if (_npcBuf[_teamCharId[var7E]]._hitPoints <= 0) - getDeathTypeDescription(var7E + 1000, monsterGroupIdOrMonsterId); - else - _messageToBePrinted += "!"; - } - // handleFight - check damages - End - - // handleFight - Add reaction text - start - if (var62 != 0 && originalDamage > 0 && getRandom(100) <= 35 && _npcBuf[_teamCharId[var7E]]._hitPoints > 0) { - if (_npcBuf[_teamCharId[var7E]]._hitPoints - 5 <= originalDamage) { - addReactionText(kEfhReactionReels); - } else if (_npcBuf[_teamCharId[var7E]]._hitPoints < _npcBuf[_teamCharId[var7E]]._maxHP / 8) { - addReactionText(kEfhReactionCriesOut); - } else if (_npcBuf[_teamCharId[var7E]]._hitPoints < _npcBuf[_teamCharId[var7E]]._maxHP / 4) { - addReactionText(kEfhReactionFalters); - } else if (_npcBuf[_teamCharId[var7E]]._hitPoints < _npcBuf[_teamCharId[var7E]]._maxHP / 2) { - addReactionText(kEfhReactionWinces); - } else if (_npcBuf[_teamCharId[var7E]]._hitPoints < _npcBuf[_teamCharId[var7E]]._maxHP / 3) { - // CHECKME: Doesn't make any sense to check /3 after /2... I don't get it. Looks like an original bug - addReactionText(kEfhReactionScreams); - } else if (_npcBuf[_teamCharId[var7E]]._maxHP / 8 >= originalDamage) { - addReactionText(kEfhReactionChortles); - } else if (originalDamage == 0 && getRandom(100) < 35) { - // CHECKME: "originalDamage == 0" is always false as it's checked beforehand. Looks like another original bug - addReactionText(kEfhReactionLaughs); - } - } - // handleFight - Add reaction text - end - - // handleFight - Check armor - start - if (var76 != 0 && var62 != 0 && _npcBuf[_teamCharId[var7E]]._hitPoints > 0) { - if (damagePointsAbsorbed <= 1) - _messageToBePrinted += Common::String::format(" %s%s's armor absorbs 1 point!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); - else - _messageToBePrinted += Common::String::format(" %s%s's armor absorbs %d points!", _characterNamePt1.c_str(), _characterNamePt2.c_str(), damagePointsAbsorbed); - - varInt = (originalDamage + damagePointsAbsorbed) / 10; - handleDamageOnArmor(_teamCharId[var7E], varInt); - } - // handleFight - Check armor - end - - // handleFight - Check effect - start - switch (_items[monsterWeaponItemId]._specialEffect) { - case 1: - if (getRandom(100) < 20) { - _teamCharStatus[var7E]._status = 1; - _teamCharStatus[var7E]._duration = getRandom(10); - _messageToBePrinted += Common::String::format(" %s%s falls asleep!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); - } - break; - case 2: - if (getRandom(100) < 20) { - _teamCharStatus[var7E]._status = 2; - _teamCharStatus[var7E]._duration = getRandom(10); - _messageToBePrinted += Common::String::format(" %s%s is frozen!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); - } - break; - case 5: - case 6: - if (getRandom(100) < 20) { - _messageToBePrinted += Common::String::format(" %s%s's life energy is gone!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); - _npcBuf[_teamCharId[var7E]]._hitPoints = 0; - } - break; - default: - break; - } - // handleFight - Check effect - end - } else { - _messageToBePrinted = Common::String::format("%s%s tries to use %s %s, but it doesn't work!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPossessive[ennemyPronoun], _nameBuffer.c_str()); - } - genericGenerateSound(_items[monsterWeaponItemId]._attackType, var62); - displayBoxWithText(_messageToBePrinted, 1, 2, true); - } - // handleFight - Loop on var7E - End - } - } else if (_mapMonsters[_techId][_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._hitPoints[ctrMobsterId] > 0 && _teamMonsterEffects[monsterGroupIdOrMonsterId]._effect[ctrMobsterId]) { - --_teamMonsterEffects[monsterGroupIdOrMonsterId]._duration[ctrMobsterId]; - if (_teamMonsterEffects[monsterGroupIdOrMonsterId]._duration[ctrMobsterId] <= 0) { - _enemyNamePt2 = kEncounters[_mapMonsters[_techId][_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._monsterRef]._name; - int16 var70 = kEncounters[_mapMonsters[_techId][_teamMonsterIdArray[monsterGroupIdOrMonsterId]]._monsterRef]._nameArticle; - if (var70 == 2) - _enemyNamePt1 = "The "; - else - _enemyNamePt1 = ""; - - switch (_teamMonsterEffects[monsterGroupIdOrMonsterId]._effect[ctrMobsterId]) { - case 1: - _messageToBePrinted = Common::String::format("%s%s wakes up!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str()); - break; - case 2: - _messageToBePrinted = Common::String::format("%s%s thaws out!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str()); - break; - default: - _messageToBePrinted = Common::String::format("%s%s recovers!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str()); - break; - } - _teamMonsterEffects[monsterGroupIdOrMonsterId]._effect[ctrMobsterId] = 0; - displayBoxWithText(_messageToBePrinted, 1, 2, true); - } - } - } - // handleFight - Loop on mobsterId - End + handleFight_MobstersAttack(monsterGroupIdOrMonsterId); } } @@ -690,6 +483,218 @@ bool EfhEngine::handleFight_lastAction_U(int16 teamCharId) { return retVal; } +void EfhEngine::handleFight_MobstersAttack(int groupId) { + // In the original, this function is part of handleFight. + // It has been split for readability purposes. + debug("handleFight_MobstersAttack %d", groupId); + + // handleFight - Loop on mobsterId - Start + for (uint ctrMobsterId = 0; ctrMobsterId < 9; ++ctrMobsterId) { + if (isMonsterActive(groupId, ctrMobsterId)) { + int16 monsterWeaponItemId = _mapMonsters[_techId][_teamMonsterIdArray[groupId]]._weaponItemId; + if (monsterWeaponItemId == 0xFF) + monsterWeaponItemId = 0x3F; + int16 minTeamMemberId = -1; + int16 maxTeamMemberId; + if (_items[monsterWeaponItemId]._range < 3) { + for (uint attackTry = 0; attackTry < 10; ++attackTry) { + minTeamMemberId = getRandom(_teamSize) - 1; + if (checkWeaponRange(_teamMonsterIdArray[groupId], monsterWeaponItemId) && isTeamMemberStatusNormal(minTeamMemberId) && getRandom(100) < _teamPctVisible[minTeamMemberId]) { + break; + } + minTeamMemberId = -1; + } + maxTeamMemberId = minTeamMemberId + 1; + } else { + minTeamMemberId = 0; + maxTeamMemberId = _teamSize; + } + + if (minTeamMemberId == -1) + continue; + + // handleFight - Loop on var7E - Start + for (int16 targetId = minTeamMemberId; targetId < maxTeamMemberId; ++targetId) { + if (_teamCharId[targetId] == -1 || !isTeamMemberStatusNormal(targetId)) + continue; + + int16 randomeDefense = getRandom(getEquipmentDefense(_teamCharId[targetId], false)); + int16 ennemyPronoun = kEncounters[_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._monsterRef]._nameArticle; + int16 characterPronoun = _npcBuf[_teamCharId[targetId]].getPronoun(); + _teamPctDodgeMiss[targetId] += (_items[monsterWeaponItemId].field_13 * 5); + int16 hitCount = 0; + int16 originalDamage = 0; + int16 damagePointsAbsorbed = 0; + int16 var64 = _mapMonsters[_techId][_teamMonsterIdArray[groupId]]._npcId * _items[monsterWeaponItemId]._attacks; + for (int var84 = 0; var84 < var64; ++var84) { + // handleFight - Loop var84 on var64 (objectId) - Start + if (getRandom(100) > _teamPctDodgeMiss[targetId]) + continue; + + ++hitCount; + + if (hasAdequateDefenseNPC(_teamCharId[targetId], _items[monsterWeaponItemId]._attackType)) + continue; + + int16 var7C = getRandom(_items[monsterWeaponItemId]._damage); + int varInt = var7C - randomeDefense; + + if (varInt > 0) { + damagePointsAbsorbed += randomeDefense; + originalDamage += varInt; + } else { + damagePointsAbsorbed += var7C; + } + // handleFight - Loop var84 on var64 (objectId) - End + } + + if (originalDamage < 0) + originalDamage = 0; + + int16 hitPoints = originalDamage + damagePointsAbsorbed; + if (!checkSpecialItemsOnCurrentPlace(monsterWeaponItemId)) + hitCount = 0; + + if (hitCount > 0) { + _npcBuf[_teamCharId[targetId]]._hitPoints -= originalDamage; + if (hitCount > 1) + _attackBuffer = Common::String::format("%d times ", hitCount); + else + _attackBuffer = ""; + } + + int16 var68 = _items[monsterWeaponItemId]._attackType + 1; + int16 var6A = getRandom(3); + if (characterPronoun == 2) + _characterNamePt1 = "The "; + else + _characterNamePt1 = ""; + + if (ennemyPronoun == 2) + _enemyNamePt1 = "The "; + else + _enemyNamePt1 = ""; + + _enemyNamePt2 = kEncounters[_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._monsterRef]._name; + _characterNamePt2 = _npcBuf[_teamCharId[targetId]]._name; + _nameBuffer = _items[monsterWeaponItemId]._name; + if (checkSpecialItemsOnCurrentPlace(monsterWeaponItemId)) { + // handleFight - check damages - Start + if (hitCount == 0) { + _messageToBePrinted = Common::String::format("%s%s %s at %s%s with %s %s, but misses!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1.c_str(), _characterNamePt2.c_str(), kPossessive[ennemyPronoun], _nameBuffer.c_str()); + } else if (hitPoints <= 0) { + _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s, but does no damage!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[ennemyPronoun], _nameBuffer.c_str()); + } else if (hitPoints == 1) { + _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s for 1 point", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[ennemyPronoun], _nameBuffer.c_str()); + if (_npcBuf[_teamCharId[targetId]]._hitPoints <= 0) + getDeathTypeDescription(targetId + 1000, groupId); + else + _messageToBePrinted += "!"; + } else { + _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s for %d points", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[ennemyPronoun], _nameBuffer.c_str(), hitPoints); + if (_npcBuf[_teamCharId[targetId]]._hitPoints <= 0) + getDeathTypeDescription(targetId + 1000, groupId); + else + _messageToBePrinted += "!"; + } + // handleFight - check damages - End + + // handleFight - Add reaction text - start + if (hitCount != 0 && originalDamage > 0 && getRandom(100) <= 35 && _npcBuf[_teamCharId[targetId]]._hitPoints > 0) { + if (_npcBuf[_teamCharId[targetId]]._hitPoints - 5 <= originalDamage) { + addReactionText(kEfhReactionReels); + } else if (_npcBuf[_teamCharId[targetId]]._hitPoints < _npcBuf[_teamCharId[targetId]]._maxHP / 8) { + addReactionText(kEfhReactionCriesOut); + } else if (_npcBuf[_teamCharId[targetId]]._hitPoints < _npcBuf[_teamCharId[targetId]]._maxHP / 4) { + addReactionText(kEfhReactionFalters); + } else if (_npcBuf[_teamCharId[targetId]]._hitPoints < _npcBuf[_teamCharId[targetId]]._maxHP / 2) { + addReactionText(kEfhReactionWinces); + } else if (_npcBuf[_teamCharId[targetId]]._hitPoints < _npcBuf[_teamCharId[targetId]]._maxHP / 3) { + // CHECKME: Doesn't make any sense to check /3 after /2... I don't get it. Looks like an original bug + addReactionText(kEfhReactionScreams); + } else if (_npcBuf[_teamCharId[targetId]]._maxHP / 8 >= originalDamage) { + addReactionText(kEfhReactionChortles); + } else if (originalDamage == 0 && getRandom(100) < 35) { + // CHECKME: "originalDamage == 0" is always false as it's checked beforehand. Looks like another original bug + addReactionText(kEfhReactionLaughs); + } + } + // handleFight - Add reaction text - end + + // handleFight - Check armor - start + if (randomeDefense != 0 && hitCount != 0 && _npcBuf[_teamCharId[targetId]]._hitPoints > 0) { + if (damagePointsAbsorbed <= 1) + _messageToBePrinted += Common::String::format(" %s%s's armor absorbs 1 point!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); + else + _messageToBePrinted += Common::String::format(" %s%s's armor absorbs %d points!", _characterNamePt1.c_str(), _characterNamePt2.c_str(), damagePointsAbsorbed); + + int armorDamage = (originalDamage + damagePointsAbsorbed) / 10; + handleDamageOnArmor(_teamCharId[targetId], armorDamage); + } + // handleFight - Check armor - end + + // handleFight - Check effect - start + switch (_items[monsterWeaponItemId]._specialEffect) { + case 1: + if (getRandom(100) < 20) { + _teamCharStatus[targetId]._status = 1; + _teamCharStatus[targetId]._duration = getRandom(10); + _messageToBePrinted += Common::String::format(" %s%s falls asleep!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); + } + break; + case 2: + if (getRandom(100) < 20) { + _teamCharStatus[targetId]._status = 2; + _teamCharStatus[targetId]._duration = getRandom(10); + _messageToBePrinted += Common::String::format(" %s%s is frozen!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); + } + break; + case 5: + case 6: + if (getRandom(100) < 20) { + _messageToBePrinted += Common::String::format(" %s%s's life energy is gone!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); + _npcBuf[_teamCharId[targetId]]._hitPoints = 0; + } + break; + default: + break; + } + // handleFight - Check effect - end + } else { + _messageToBePrinted = Common::String::format("%s%s tries to use %s %s, but it doesn't work!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPossessive[ennemyPronoun], _nameBuffer.c_str()); + } + genericGenerateSound(_items[monsterWeaponItemId]._attackType, hitCount); + displayBoxWithText(_messageToBePrinted, 1, 2, true); + } + // handleFight - Loop on var7E - End + } else if (_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] > 0 && _teamMonsterEffects[groupId]._effect[ctrMobsterId] > 0) { + --_teamMonsterEffects[groupId]._duration[ctrMobsterId]; + if (_teamMonsterEffects[groupId]._duration[ctrMobsterId] <= 0) { + _enemyNamePt2 = kEncounters[_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._monsterRef]._name; + if (kEncounters[_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._monsterRef]._nameArticle == 2) + _enemyNamePt1 = "The "; + else + _enemyNamePt1 = ""; + + switch (_teamMonsterEffects[groupId]._effect[ctrMobsterId]) { + case 1: + _messageToBePrinted = Common::String::format("%s%s wakes up!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str()); + break; + case 2: + _messageToBePrinted = Common::String::format("%s%s thaws out!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str()); + break; + default: + _messageToBePrinted = Common::String::format("%s%s recovers!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str()); + break; + } + _teamMonsterEffects[groupId]._effect[ctrMobsterId] = 0; + displayBoxWithText(_messageToBePrinted, 1, 2, true); + } + } + } + // handleFight - Loop on mobsterId - End +} + bool EfhEngine::isTPK() { debugC(6, kDebugFight, "isTPK"); From 6179bb75adbd56cd637b3653d64b29ea32d5ac80 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Fri, 20 Jan 2023 13:55:13 +0100 Subject: [PATCH 256/412] EFH: Rename last SUB function --- engines/efh/efh.cpp | 10 +++++----- engines/efh/efh.h | 2 +- engines/efh/menu.cpp | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 19ebf33846de..0379bad92092 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -2103,8 +2103,8 @@ void EfhEngine::displayImp1Text(int16 textId) { displayAnimFrames(0xFE, true); } -bool EfhEngine::sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemId, int16 arg8, int16 imageSetId) { - debugC(3, kDebugEngine, "sub22293 %d-%d %d %d %d %d", mapPosX, mapPosY, charId, itemId, arg8, imageSetId); +bool EfhEngine::handleInteractionText(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemId, int16 arg8, int16 imageSetId) { + debugC(3, kDebugEngine, "handleInteractionText %d-%d %d %d %d %d", mapPosX, mapPosY, charId, itemId, arg8, imageSetId); int16 tileId = findMapSpecialTileIndex(mapPosX, mapPosY); @@ -2148,7 +2148,7 @@ bool EfhEngine::sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemI for (uint var2 = 0; var2 < 39; ++var2) { // CHECKME : the whole loop doesn't make much sense as it's using var6 instead of var2, plus _activeScore is an array of 15 bytes, not 0x77... // Also, 39 correspond to the size of activeScore + passiveScore + infoScore + the 2 remaining bytes of the struct - warning("sub22293 - _activeScore[%d]", var6); + warning("handleInteractionText - _activeScore[%d]", var6); if (_npcBuf[_teamCharId[counter]]._activeScore[var6] >= _mapSpecialTiles[_techId][tileId]._triggerId) { displayImp1Text(_mapSpecialTiles[_techId][tileId]._field5_textId); return true; @@ -2165,7 +2165,7 @@ bool EfhEngine::sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemI int16 var6 = _mapSpecialTiles[_techId][tileId]._field3; if (var6 >= 0x78 && var6 <= 0xEF) { var6 -= 0x78; - warning("sub22293 - _activeScore[%d]", var6); + warning("handleInteractionText - _activeScore[%d]", var6); // The 2 checks on var6 are useless, as [0x78..0xEF] - 0x78 => [0x00..0x77] if (var6 >= 0 && var6 <= 0x8B && var6 == itemId && _mapSpecialTiles[_techId][tileId]._triggerId <= _npcBuf[charId]._activeScore[itemId]) { displayImp1Text(_mapSpecialTiles[_techId][tileId]._field5_textId); @@ -2198,7 +2198,7 @@ int8 EfhEngine::checkTileStatus(int16 mapPosX, int16 mapPosY, bool arg4) { tileFactId += curTileInfo % 72; if (arg4) { - sub22293(mapPosX, mapPosY, -1, 0x7FFF, 0, tileFactId); + handleInteractionText(mapPosX, mapPosY, -1, 0x7FFF, 0, tileFactId); } if (_word2C880) { diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 03e91a7c5169..2fd42f5d9303 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -356,7 +356,7 @@ class EfhEngine : public Engine { bool handleTalk(int16 monsterId, int16 arg2, int16 itemId); void startTalkMenu(int16 monsterId); void displayImp1Text(int16 textId); - bool sub22293(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemId, int16 arg8, int16 imageSetId); + bool handleInteractionText(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemId, int16 arg8, int16 imageSetId); int8 checkTileStatus(int16 mapPosX, int16 mapPosY, bool arg4); void computeInitiatives(); void redrawScreenForced(); diff --git a/engines/efh/menu.cpp b/engines/efh/menu.cpp index 9fefb458b090..c7bcc2cd675b 100644 --- a/engines/efh/menu.cpp +++ b/engines/efh/menu.cpp @@ -694,7 +694,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { return objectId; } - if (sub22293(_mapPosX, _mapPosY, charId, itemId, 2, -1)) { + if (handleInteractionText(_mapPosX, _mapPosY, charId, itemId, 2, -1)) { _statusMenuActive = false; return -1; } @@ -717,7 +717,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { displayStringInSmallWindowWithBorder("Not a Combat Option !", true, charId, windowId, menuId, curMenuLine); } else { removeObject(charId, objectId); - if (sub22293(_mapPosX, _mapPosY, charId, itemId, 3, -1)) { + if (handleInteractionText(_mapPosX, _mapPosY, charId, itemId, 3, -1)) { _statusMenuActive = false; return -1; } @@ -807,7 +807,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { return 0x7D00; } - if (sub22293(_mapPosX, _mapPosY, charId, itemId, 1, -1)) { + if (handleInteractionText(_mapPosX, _mapPosY, charId, itemId, 1, -1)) { _statusMenuActive = false; return -1; } @@ -820,7 +820,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { objectId = _menuStatItemArr[selectedLine]; if (gameMode == 2) { displayStringInSmallWindowWithBorder("Not a Combat Option!", true, charId, windowId, menuId, curMenuLine); - } else if (sub22293(_mapPosX, _mapPosY, charId, objectId, 4, -1)) { + } else if (handleInteractionText(_mapPosX, _mapPosY, charId, objectId, 4, -1)) { _statusMenuActive = false; return -1; } From 04f3b5ff724c9cb3f443edfdff21fd01aab4eb9b Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sat, 21 Jan 2023 01:01:43 +0100 Subject: [PATCH 257/412] EFH: Some work on song parsing --- engines/efh/constants.h | 2 +- engines/efh/efh.cpp | 70 ++++++++++++++++++++--------------------- 2 files changed, 35 insertions(+), 37 deletions(-) diff --git a/engines/efh/constants.h b/engines/efh/constants.h index 2cc2f3916a3b..a0ba37c442ac 100644 --- a/engines/efh/constants.h +++ b/engines/efh/constants.h @@ -62,7 +62,7 @@ struct Encounter { uint8 _nameArticle; }; -#define kDefaultNoteDuration 616; +#define kDefaultNoteDuration 616 extern const uint8 kFontWidthArray[96]; extern const uint8 kFontExtraLinesArray[96]; diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 0379bad92092..a86bc992d637 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -271,17 +271,10 @@ void EfhEngine::initialize() { void EfhEngine::songDelay(int delay) { debug("songDelay %ld", delay); - int remainingDelay = delay * kDefaultNoteDuration; - Common::KeyCode input = Common::KEYCODE_INVALID; - Common::Event event; - while (input == Common::KEYCODE_INVALID && remainingDelay > 0 && !shouldQuit()) { - _system->delayMillis(20); - remainingDelay -= 20; - - _system->getEventManager()->pollEvent(event); - if (event.type == Common::EVENT_KEYUP) { - input = event.kbd.keycode; - } + int remainingDelay = delay; + while (remainingDelay > 0 && !shouldQuit()) { + remainingDelay -= 10; + _system->delayMillis(10); } } @@ -292,41 +285,46 @@ void EfhEngine::playNote(int frequencyIndex, int totalDelay) { Common::KeyCode EfhEngine::playSong(uint8 *buffer) { debug("playSong"); - return Common::KEYCODE_INVALID; - Common::KeyCode inputChar = Common::KEYCODE_INVALID; - int32 totalDelay = 0; + int totalDelay = 0; + int8 stopFl; uint8 varC = *buffer++; - int8 stopFl = *buffer & 0x3F; - while (stopFl != 0) { - int32 delay = stopFl * varC * 0x2200 / 1000; - if (*buffer > 0x7F) - delay /= 2; - if (*buffer & 0x40) - delay = (delay * 2) / 3; - int8 frequencyIndex = *++buffer & 0xF; - ++buffer; - - if (frequencyIndex > 0x7F) - totalDelay += delay; - else if (frequencyIndex == 0) - songDelay(delay); - else { - playNote(frequencyIndex, totalDelay + delay); - totalDelay = 0; + Common::Event event; + do { + stopFl = *buffer & 0x3F; + if (stopFl != 0) { + int delay = stopFl * varC * 0x2200 / 1000; + + if (*buffer > 0x7F) + delay /= 2; + + if (*buffer & 0x40) + delay = (delay * 2) / 3; + + ++buffer; + uint8 frequencyIndex = *buffer; + ++buffer; + + if (frequencyIndex > 0x7F) + totalDelay += delay; + else if (frequencyIndex == 0) + songDelay(delay); + else { + playNote(frequencyIndex, totalDelay + delay); + totalDelay = 0; + } } songDelay(10); - Common::Event event; _system->getEventManager()->pollEvent(event); if (event.type == Common::EVENT_KEYUP) { inputChar = event.kbd.keycode; + // Hack, sometimes there's a ghost event after the 2nd note + if (inputChar == Common::KEYCODE_ESCAPE || inputChar == Common::KEYCODE_RETURN) + stopFl = 0; } - - if (inputChar != Common::KEYCODE_INVALID) - stopFl = 0; - } + } while (stopFl != 0); return inputChar; } From 577fbde5ba1a0513e43f7c722af0b00111fbdae0 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sat, 21 Jan 2023 02:09:56 +0100 Subject: [PATCH 258/412] EFH: ... Music implementation! 0_o --- engines/efh/efh.cpp | 11 +++++++++++ engines/efh/efh.h | 5 +++++ 2 files changed, 16 insertions(+) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index a86bc992d637..f6b5ef1b4713 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -280,11 +280,18 @@ void EfhEngine::songDelay(int delay) { void EfhEngine::playNote(int frequencyIndex, int totalDelay) { debug("playNote %d %d", frequencyIndex, totalDelay); + _speakerStream->play(Audio::PCSpeaker::kWaveFormSquare, 0x1234DD / kSoundFrequency [frequencyIndex], -1); + songDelay(totalDelay); + _speakerStream->stop(); } Common::KeyCode EfhEngine::playSong(uint8 *buffer) { debug("playSong"); + _speakerStream = new Audio::PCSpeaker(_mixer->getOutputRate()); + _mixer->playStream(Audio::Mixer::kSFXSoundType, &_speakerHandle, + _speakerStream, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true); + Common::KeyCode inputChar = Common::KEYCODE_INVALID; int totalDelay = 0; @@ -326,6 +333,10 @@ Common::KeyCode EfhEngine::playSong(uint8 *buffer) { } } while (stopFl != 0); + _mixer->stopHandle(_speakerHandle); + delete _speakerStream; + _speakerStream = nullptr; + return inputChar; } diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 2fd42f5d9303..7e8034d81cda 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -22,6 +22,8 @@ #ifndef EFH_H #define EFH_H +#include "audio/softsynth/pcspk.h" +#include "audio/mixer.h" #include "common/file.h" #include "common/rect.h" #include "common/events.h" @@ -619,6 +621,9 @@ class EfhEngine : public Engine { InitiativeStruct _initiatives[8]; int16 _regenCounter; + + Audio::PCSpeaker *_speakerStream; + Audio::SoundHandle _speakerHandle; }; } // End of namespace Efh From af35f1c3bd69844aef471a5884fa53c7ff63c09a Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sat, 21 Jan 2023 09:58:19 +0100 Subject: [PATCH 259/412] EFH: Sync volume settings, add a purge of keyboard events to stop exiting the splash screen accidentally --- engines/efh/efh.cpp | 14 +++++--------- engines/efh/efh.h | 2 -- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index f6b5ef1b4713..e21ac4423a02 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -54,12 +54,6 @@ EfhEngine::~EfhEngine() { delete _vgaGraphicsStruct2; } -void EfhEngine::syncSoundSettings() { - Engine::syncSoundSettings(); - - warning("TODO: _sound->syncVolume();"); -} - Common::Error EfhEngine::run() { debug("run"); @@ -70,11 +64,13 @@ Common::Error EfhEngine::run() { _mainSurface->create(320, 200, Graphics::PixelFormat::createFormatCLUT8()); initPalette(); -/* + // Setup mixer syncSoundSettings(); - _soundHandler->init(); -*/ + + // Sometimes a ghost key event stops the intro, so we ass a short delay and purge the keyboard events + _system->delayMillis(100); + _system->getEventManager()->purgeKeyboardEvents(); initEngine(); drawGameScreenAndTempText(true); diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 7e8034d81cda..42acf5829051 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -256,8 +256,6 @@ class EfhEngine : public Engine { const ADGameDescription *_gameDescription; - void syncSoundSettings() override; - // metaengine.cpp void initGame(const ADGameDescription *gd); uint32 getFeatures() const; From a25e1b09c96785de70c3e47b9ddb3f7b03bf1cc5 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sun, 22 Jan 2023 15:46:47 +0100 Subject: [PATCH 260/412] EFH: Improve delay length in title music --- engines/efh/efh.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index e21ac4423a02..d14c0582eaeb 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -199,6 +199,16 @@ Common::Error EfhEngine::run() { displayLowStatusScreen(true); } break; + // debug cases to test sound + case Common::KEYCODE_1: + generateSound(13); + break; + case Common::KEYCODE_2: + generateSound(14); + break; + case Common::KEYCODE_3: + generateSound(15); + break; default: if (retVal != Common::KEYCODE_INVALID) warning("Main Loop: Unhandled input %d", retVal); @@ -267,10 +277,10 @@ void EfhEngine::initialize() { void EfhEngine::songDelay(int delay) { debug("songDelay %ld", delay); - int remainingDelay = delay; + int remainingDelay = delay / 2; while (remainingDelay > 0 && !shouldQuit()) { - remainingDelay -= 10; - _system->delayMillis(10); + remainingDelay -= 3; + _system->delayMillis(3); } } From f52852512e4122ee707088dc35e1dcbd94fb171e Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sun, 22 Jan 2023 15:48:29 +0100 Subject: [PATCH 261/412] EFH: Implementation of generateSound2 (based on assembly, no idea about how it should sound like on real hardware) --- engines/efh/efh.h | 3 +- engines/efh/fight.cpp | 1 + engines/efh/sound.cpp | 64 +++++++++++++++++++++++++++++++++++++++++-- engines/efh/utils.cpp | 4 +++ 4 files changed, 68 insertions(+), 4 deletions(-) diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 42acf5829051..f731e100a280 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -483,7 +483,7 @@ class EfhEngine : public Engine { // Sound void generateSound1(int arg0, int arg2, int duration); - void generateSound2(int startFreq, int endFreq, int arg4); + void generateSound2(int startFreq, int endFreq, int speed); void generateSound3(); void generateSound4(int arg0); void generateSound5(int arg0); @@ -504,6 +504,7 @@ class EfhEngine : public Engine { Common::KeyCode getInputBlocking(); void setNumLock(); bool getValidationFromUser(); + uint32 ROR(uint32 val, uint8 shiftVal); uint8 _videoMode; uint8 _bufferCharBM[128]; diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index e3fe6a93aae5..c15910b8e14f 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -525,6 +525,7 @@ void EfhEngine::handleFight_MobstersAttack(int groupId) { int16 hitCount = 0; int16 originalDamage = 0; int16 damagePointsAbsorbed = 0; + int16 var64 = _mapMonsters[_techId][_teamMonsterIdArray[groupId]]._npcId * _items[monsterWeaponItemId]._attacks; for (int var84 = 0; var84 < var64; ++var84) { // handleFight - Loop var84 on var64 (objectId) - Start diff --git a/engines/efh/sound.cpp b/engines/efh/sound.cpp index 8da1fa700789..7f66d5861633 100644 --- a/engines/efh/sound.cpp +++ b/engines/efh/sound.cpp @@ -25,12 +25,68 @@ namespace Efh { void EfhEngine::generateSound1(int arg0, int arg2, int duration) { warning("STUB: generateSound1 %d %d %d", arg0, arg2, duration); + + if (arg0 < 19) + arg0 = 19; + + if (arg2 < 19) + arg2 = 19; + + uint32 var2 = 0; + _speakerStream = new Audio::PCSpeaker(_mixer->getOutputRate()); + _mixer->playStream(Audio::Mixer::kSFXSoundType, &_speakerHandle, + _speakerStream, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true); + + _speakerStream->play(Audio::PCSpeaker::kWaveFormSquare, 0x1234DE / arg2, -1); + songDelay(10); + _speakerStream->stop(); + + for (int i = 0; i < duration; ++i) { + var2 = ROR(var2 + 0x9248, 3); + uint32 val = var2 * (arg2 - arg0); + + + } + + + _mixer->stopHandle(_speakerHandle); + delete _speakerStream; + _speakerStream = nullptr; } -void EfhEngine::generateSound2(int startFreq, int endFreq, int arg4) { - warning("STUB: generateSound2 %d %d %d", startFreq, endFreq, arg4); +void EfhEngine::generateSound2(int startFreq, int endFreq, int speed) { + warning("STUB: generateSound2 %d %d %d", startFreq, endFreq, speed); + + if (startFreq < 19) + startFreq = 19; + + if (endFreq < 19) + endFreq = 19; + + int delta; + if (startFreq > endFreq) + delta = -5; + else + delta = 5; + + _speakerStream = new Audio::PCSpeaker(_mixer->getOutputRate()); + _mixer->playStream(Audio::Mixer::kSFXSoundType, &_speakerHandle, + _speakerStream, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true); + + int curFreq = startFreq; + + do { + _speakerStream->play(Audio::PCSpeaker::kWaveFormSquare, curFreq, -1); + songDelay(speed / 10); + _speakerStream->stop(); + curFreq += delta; + } while (curFreq < endFreq && !shouldQuit()); + + + _mixer->stopHandle(_speakerHandle); + delete _speakerStream; + _speakerStream = nullptr; - // Arg4 doesn't seem to be used. } void EfhEngine::generateSound3() { @@ -46,6 +102,8 @@ void EfhEngine::generateSound5(int arg0) { } void EfhEngine::generateSound(int16 soundType) { + warning("generateSound %d", soundType); + switch (soundType) { case 5: generateSound3(); diff --git a/engines/efh/utils.cpp b/engines/efh/utils.cpp index 78a01fe96d1d..e10b99c5462d 100644 --- a/engines/efh/utils.cpp +++ b/engines/efh/utils.cpp @@ -295,4 +295,8 @@ bool EfhEngine::getValidationFromUser() { return false; } +uint32 EfhEngine::ROR(uint32 val, uint8 shiftVal) { + return val >> shiftVal | val << (32 - shiftVal); +} + } // End of namespace Efh From 16cc90a9731758bd2c03ec17f407447437632d66 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sun, 22 Jan 2023 18:12:55 +0100 Subject: [PATCH 262/412] EFH: Implement generateSound3 --- engines/efh/efh.cpp | 5 ++++- engines/efh/sound.cpp | 19 +++++++++++++++++-- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index d14c0582eaeb..ce8c3a7e6017 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -209,6 +209,9 @@ Common::Error EfhEngine::run() { case Common::KEYCODE_3: generateSound(15); break; + case Common::KEYCODE_4: + generateSound(5); + break; default: if (retVal != Common::KEYCODE_INVALID) warning("Main Loop: Unhandled input %d", retVal); @@ -286,7 +289,7 @@ void EfhEngine::songDelay(int delay) { void EfhEngine::playNote(int frequencyIndex, int totalDelay) { debug("playNote %d %d", frequencyIndex, totalDelay); - _speakerStream->play(Audio::PCSpeaker::kWaveFormSquare, 0x1234DD / kSoundFrequency [frequencyIndex], -1); + _speakerStream->play(Audio::PCSpeaker::kWaveFormSquare, 0x1234DD / kSoundFrequency[frequencyIndex], -1); songDelay(totalDelay); _speakerStream->stop(); } diff --git a/engines/efh/sound.cpp b/engines/efh/sound.cpp index 7f66d5861633..1d9da78d281f 100644 --- a/engines/efh/sound.cpp +++ b/engines/efh/sound.cpp @@ -55,7 +55,7 @@ void EfhEngine::generateSound1(int arg0, int arg2, int duration) { } void EfhEngine::generateSound2(int startFreq, int endFreq, int speed) { - warning("STUB: generateSound2 %d %d %d", startFreq, endFreq, speed); + debugC(3, kDebugEngine, "generateSound2 %d %d %d", startFreq, endFreq, speed); if (startFreq < 19) startFreq = 19; @@ -64,6 +64,7 @@ void EfhEngine::generateSound2(int startFreq, int endFreq, int speed) { endFreq = 19; int delta; + // The original is using -/+1 but it takes ages even with speed / 10, so I switched to -/+5 if (startFreq > endFreq) delta = -5; else @@ -77,6 +78,8 @@ void EfhEngine::generateSound2(int startFreq, int endFreq, int speed) { do { _speakerStream->play(Audio::PCSpeaker::kWaveFormSquare, curFreq, -1); + // The original is just looping, making the sound improperly timed as the length of a loop is directly related to the speed of the CPU + // Dividing by 10 is just a guess based on how it sounds. I suspect it may be still too much songDelay(speed / 10); _speakerStream->stop(); curFreq += delta; @@ -90,7 +93,19 @@ void EfhEngine::generateSound2(int startFreq, int endFreq, int speed) { } void EfhEngine::generateSound3() { - warning("STUB: generateSound3"); + debugC(3, kDebugEngine, "generateSound3"); + _speakerStream = new Audio::PCSpeaker(_mixer->getOutputRate()); + _mixer->playStream(Audio::Mixer::kSFXSoundType, &_speakerHandle, + _speakerStream, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true); + + _speakerStream->play(Audio::PCSpeaker::kWaveFormSquare, 88, -1); + // The original makes me think the delay is so short it's not possible to hear. So that delay is guessed (and short) + songDelay(30); + _speakerStream->stop(); + + _mixer->stopHandle(_speakerHandle); + delete _speakerStream; + _speakerStream = nullptr; } void EfhEngine::generateSound4(int arg0) { From 6fa1582bfae0901b652572ac110d79f2de786f7e Mon Sep 17 00:00:00 2001 From: Strangerke Date: Mon, 23 Jan 2023 22:03:56 +0100 Subject: [PATCH 263/412] EFH: Add the last sound generation functions --- engines/efh/efh.cpp | 6 ++++++ engines/efh/efh.h | 6 +++--- engines/efh/sound.cpp | 47 +++++++++++++++++++++++++++---------------- 3 files changed, 39 insertions(+), 20 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index ce8c3a7e6017..dcf184e4a330 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -212,6 +212,12 @@ Common::Error EfhEngine::run() { case Common::KEYCODE_4: generateSound(5); break; + case Common::KEYCODE_5: + generateSound(10); + break; + case Common::KEYCODE_6: + generateSound1(20, 888, 3000); + break; default: if (retVal != Common::KEYCODE_INVALID) warning("Main Loop: Unhandled input %d", retVal); diff --git a/engines/efh/efh.h b/engines/efh/efh.h index f731e100a280..a27c739ca93c 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -482,11 +482,11 @@ class EfhEngine : public Engine { int16 script_parse(Common::String str, int16 posX, int16 posY, int16 maxX, int16 maxY, bool scriptExecuteFlag); // Sound - void generateSound1(int arg0, int arg2, int duration); + void generateSound1(int lowFreq, int highFreq, int duration); void generateSound2(int startFreq, int endFreq, int speed); void generateSound3(); - void generateSound4(int arg0); - void generateSound5(int arg0); + void generateSound4(int repeat); + void generateSound5(int repeat); void generateSound(int16 soundType); void genericGenerateSound(int16 soundType, int16 repeatCount); diff --git a/engines/efh/sound.cpp b/engines/efh/sound.cpp index 1d9da78d281f..17b32332f980 100644 --- a/engines/efh/sound.cpp +++ b/engines/efh/sound.cpp @@ -23,29 +23,34 @@ namespace Efh { -void EfhEngine::generateSound1(int arg0, int arg2, int duration) { - warning("STUB: generateSound1 %d %d %d", arg0, arg2, duration); +void EfhEngine::generateSound1(int lowFreq, int highFreq, int duration) { + debugC(3, kDebugEngine, "generateSound1 %d %d %d - suspicious code", lowFreq, highFreq, duration); - if (arg0 < 19) - arg0 = 19; + if (lowFreq < 19) + lowFreq = 19; - if (arg2 < 19) - arg2 = 19; + if (highFreq < 19) + highFreq = 19; + + uint16 var2 = 0; + duration /= 20; - uint32 var2 = 0; _speakerStream = new Audio::PCSpeaker(_mixer->getOutputRate()); _mixer->playStream(Audio::Mixer::kSFXSoundType, &_speakerHandle, _speakerStream, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true); - _speakerStream->play(Audio::PCSpeaker::kWaveFormSquare, 0x1234DE / arg2, -1); + _speakerStream->play(Audio::PCSpeaker::kWaveFormSquare, highFreq, -1); songDelay(10); - _speakerStream->stop(); + _speakerStream->stop(); + for (int i = 0; i < duration; ++i) { var2 = ROR(var2 + 0x9248, 3); - uint32 val = var2 * (arg2 - arg0); - + int val = (var2 * (highFreq - lowFreq)) >> 16; + _speakerStream->play(Audio::PCSpeaker::kWaveFormSquare, lowFreq + val, -1); + songDelay(10); + _speakerStream->stop(); } @@ -108,16 +113,22 @@ void EfhEngine::generateSound3() { _speakerStream = nullptr; } -void EfhEngine::generateSound4(int arg0) { - warning("STUB: generateSound4 %d", arg0); +void EfhEngine::generateSound4(int repeat) { + debugC(3, kDebugEngine, "generateSound4 %d", repeat); + for (int i = 0; i < repeat; ++i) + //It looks identical, so I'm reusing generateSound1 + generateSound1(256, 4096, 10); } -void EfhEngine::generateSound5(int arg0) { - warning("STUB: generateSound5 %d", arg0); +void EfhEngine::generateSound5(int repeat) { + debugC(3, kDebugEngine, "generateSound5 %d", repeat); + for (int i = 0; i < repeat; ++i) + //It looks identical, so I'm reusing generateSound2 + generateSound2(256, 4096, 10); } void EfhEngine::generateSound(int16 soundType) { - warning("generateSound %d", soundType); + debugC(3, kDebugEngine, "generateSound %d", soundType); switch (soundType) { case 5: @@ -146,12 +157,14 @@ void EfhEngine::generateSound(int16 soundType) { generateSound4(1); break; default: - // Not implemented because not used by the engine + debug("generateSound %d - Not implemented because not used by the engine", soundType); break; } } void EfhEngine::genericGenerateSound(int16 soundType, int16 repeatCount) { + debugC(3, kDebugEngine, "genericGenerateSound %d %d", soundType, repeatCount); + if (repeatCount <= 0) return; From 90ceabd3fcb92cd559b67b38ad24670bd1d50b79 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Tue, 24 Jan 2023 07:06:39 +0100 Subject: [PATCH 264/412] EFH: Delete _mainSurface on exit --- engines/efh/efh.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index dcf184e4a330..d6a65901b009 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -48,6 +48,9 @@ int8 InvObject::getUsesLeft() { } EfhEngine::~EfhEngine() { + _mainSurface->free(); + delete _mainSurface; + delete _rnd; delete _graphicsStruct; delete _vgaGraphicsStruct1; From 6c027c0373ee267c7c89735343c3b639df12de35 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Wed, 25 Jan 2023 22:58:34 +0100 Subject: [PATCH 265/412] EFH: Some renaming --- engines/efh/fight.cpp | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index c15910b8e14f..5efc40a152da 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -272,23 +272,23 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { int16 damagePointsAbsorbed = 0; int16 attackSpeed = _items[teamCharItemId]._attacks * _npcBuf[_teamCharId[teamCharId]]._speed; - // Action A - Loop var84 - Start - for (int var84 = 0; var84 < attackSpeed; ++var84) { + // Action A - Loop attackCounter - Start + for (int attackCounter = 0; attackCounter < attackSpeed; ++attackCounter) { if (getRandom(100) < charScore) { ++hitCount; if (!hasAdequateDefense(_teamMonsterIdArray[groupId], _items[teamCharItemId]._attackType)) { - int16 var7C = getRandom(_items[teamCharItemId]._damage); - int16 varInt = var7C - randomDamageAbsorbed; - if (varInt > 0) { - originalDamage += varInt; + int16 randomDamage = getRandom(_items[teamCharItemId]._damage); + int16 residualDamage = randomDamage - randomDamageAbsorbed; + if (residualDamage > 0) { + originalDamage += residualDamage; damagePointsAbsorbed += randomDamageAbsorbed; } else { - damagePointsAbsorbed += var7C; + damagePointsAbsorbed += randomDamage; } } } } - // Action A - Loop var84 - End + // Action A - Loop attackCounter - End if (originalDamage < 0) originalDamage = 0; @@ -513,7 +513,7 @@ void EfhEngine::handleFight_MobstersAttack(int groupId) { if (minTeamMemberId == -1) continue; - // handleFight - Loop on var7E - Start + // handleFight - Loop on targetId - Start for (int16 targetId = minTeamMemberId; targetId < maxTeamMemberId; ++targetId) { if (_teamCharId[targetId] == -1 || !isTeamMemberStatusNormal(targetId)) continue; @@ -667,7 +667,7 @@ void EfhEngine::handleFight_MobstersAttack(int groupId) { genericGenerateSound(_items[monsterWeaponItemId]._attackType, hitCount); displayBoxWithText(_messageToBePrinted, 1, 2, true); } - // handleFight - Loop on var7E - End + // handleFight - Loop on targetId - End } else if (_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] > 0 && _teamMonsterEffects[groupId]._effect[ctrMobsterId] > 0) { --_teamMonsterEffects[groupId]._duration[ctrMobsterId]; if (_teamMonsterEffects[groupId]._duration[ctrMobsterId] <= 0) { @@ -1598,8 +1598,8 @@ void EfhEngine::addNewOpponents(int16 monsterId) { } if (teamMonsterId != -1) { - // addNewOpponents - loop var2 - Start - for (int var2 = 1; var2 < 3; ++var2) { + // addNewOpponents - loop distCtr - Start + for (int distCtr = 1; distCtr < 3; ++distCtr) { if (teamMonsterId >= 5) break; @@ -1620,7 +1620,7 @@ void EfhEngine::addNewOpponents(int16 monsterId) { if (!monsterActiveFound) continue; - if (computeMonsterGroupDistance(ctrMapMonsterId) > var2) + if (computeMonsterGroupDistance(ctrMapMonsterId) > distCtr) continue; if (isMonsterAlreadyFighting(ctrMapMonsterId, teamMonsterId)) @@ -1641,7 +1641,7 @@ void EfhEngine::addNewOpponents(int16 monsterId) { } } } - // addNewOpponents - loop var2 - End + // addNewOpponents - loop distCtr - End } if (teamMonsterId == -1 || teamMonsterId > 4) From a33db72da44d9a1576ad8871d17a0654ff6ed353 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Fri, 27 Jan 2023 19:17:48 +0100 Subject: [PATCH 266/412] EFH: Move songDelay, playNote and PlaySong to sound.sound.cpp --- engines/efh/efh.cpp | 72 ------------------------------------------- engines/efh/efh.h | 6 ++-- engines/efh/sound.cpp | 72 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+), 75 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index d6a65901b009..c4909c73f4cc 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -286,78 +286,6 @@ void EfhEngine::initialize() { _shouldQuit = false; } -void EfhEngine::songDelay(int delay) { - debug("songDelay %ld", delay); - - int remainingDelay = delay / 2; - while (remainingDelay > 0 && !shouldQuit()) { - remainingDelay -= 3; - _system->delayMillis(3); - } -} - -void EfhEngine::playNote(int frequencyIndex, int totalDelay) { - debug("playNote %d %d", frequencyIndex, totalDelay); - _speakerStream->play(Audio::PCSpeaker::kWaveFormSquare, 0x1234DD / kSoundFrequency[frequencyIndex], -1); - songDelay(totalDelay); - _speakerStream->stop(); -} - -Common::KeyCode EfhEngine::playSong(uint8 *buffer) { - debug("playSong"); - - _speakerStream = new Audio::PCSpeaker(_mixer->getOutputRate()); - _mixer->playStream(Audio::Mixer::kSFXSoundType, &_speakerHandle, - _speakerStream, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true); - - Common::KeyCode inputChar = Common::KEYCODE_INVALID; - int totalDelay = 0; - - int8 stopFl; - uint8 varC = *buffer++; - Common::Event event; - do { - stopFl = *buffer & 0x3F; - if (stopFl != 0) { - int delay = stopFl * varC * 0x2200 / 1000; - - if (*buffer > 0x7F) - delay /= 2; - - if (*buffer & 0x40) - delay = (delay * 2) / 3; - - ++buffer; - uint8 frequencyIndex = *buffer; - ++buffer; - - if (frequencyIndex > 0x7F) - totalDelay += delay; - else if (frequencyIndex == 0) - songDelay(delay); - else { - playNote(frequencyIndex, totalDelay + delay); - totalDelay = 0; - } - } - - songDelay(10); - _system->getEventManager()->pollEvent(event); - if (event.type == Common::EVENT_KEYUP) { - inputChar = event.kbd.keycode; - // Hack, sometimes there's a ghost event after the 2nd note - if (inputChar == Common::KEYCODE_ESCAPE || inputChar == Common::KEYCODE_RETURN) - stopFl = 0; - } - } while (stopFl != 0); - - _mixer->stopHandle(_speakerHandle); - delete _speakerStream; - _speakerStream = nullptr; - - return inputChar; -} - void EfhEngine::playIntro() { debugC(6, kDebugEngine, "playIntro"); diff --git a/engines/efh/efh.h b/engines/efh/efh.h index a27c739ca93c..0a7329e1aa45 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -285,9 +285,6 @@ class EfhEngine : public Engine { bool _saveAuthorized; void initialize(); - void songDelay(int delay); - void playNote(int frequencyIndex, int totalDelay); - Common::KeyCode playSong(uint8 *buffer); void playIntro(); void initEngine(); void initMapMonsters(); @@ -482,6 +479,9 @@ class EfhEngine : public Engine { int16 script_parse(Common::String str, int16 posX, int16 posY, int16 maxX, int16 maxY, bool scriptExecuteFlag); // Sound + void songDelay(int delay); + void playNote(int frequencyIndex, int totalDelay); + Common::KeyCode playSong(uint8 *buffer); void generateSound1(int lowFreq, int highFreq, int duration); void generateSound2(int startFreq, int endFreq, int speed); void generateSound3(); diff --git a/engines/efh/sound.cpp b/engines/efh/sound.cpp index 17b32332f980..e0b0181cabe1 100644 --- a/engines/efh/sound.cpp +++ b/engines/efh/sound.cpp @@ -23,6 +23,78 @@ namespace Efh { +void EfhEngine::songDelay(int delay) { + debugC(3, kDebugEngine, "songDelay %ld", delay); + + int remainingDelay = delay / 2; + while (remainingDelay > 0 && !shouldQuit()) { + remainingDelay -= 3; + _system->delayMillis(3); + } +} + +void EfhEngine::playNote(int frequencyIndex, int totalDelay) { + debugC(3, kDebugEngine, "playNote %d %d", frequencyIndex, totalDelay); + _speakerStream->play(Audio::PCSpeaker::kWaveFormSquare, 0x1234DD / kSoundFrequency[frequencyIndex], -1); + songDelay(totalDelay); + _speakerStream->stop(); +} + +Common::KeyCode EfhEngine::playSong(uint8 *buffer) { + debugC(3, kDebugEngine, "playSong"); + + _speakerStream = new Audio::PCSpeaker(_mixer->getOutputRate()); + _mixer->playStream(Audio::Mixer::kSFXSoundType, &_speakerHandle, + _speakerStream, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true); + + Common::KeyCode inputChar = Common::KEYCODE_INVALID; + int totalDelay = 0; + + int8 stopFl; + uint8 varC = *buffer++; + Common::Event event; + do { + stopFl = *buffer & 0x3F; + if (stopFl != 0) { + int delay = stopFl * varC * 0x2200 / 1000; + + if (*buffer > 0x7F) + delay /= 2; + + if (*buffer & 0x40) + delay = (delay * 2) / 3; + + ++buffer; + uint8 frequencyIndex = *buffer; + ++buffer; + + if (frequencyIndex > 0x7F) + totalDelay += delay; + else if (frequencyIndex == 0) + songDelay(delay); + else { + playNote(frequencyIndex, totalDelay + delay); + totalDelay = 0; + } + } + + songDelay(10); + _system->getEventManager()->pollEvent(event); + if (event.type == Common::EVENT_KEYUP) { + inputChar = event.kbd.keycode; + // Hack, sometimes there's a ghost event after the 2nd note + if (inputChar == Common::KEYCODE_ESCAPE || inputChar == Common::KEYCODE_RETURN) + stopFl = 0; + } + } while (stopFl != 0); + + _mixer->stopHandle(_speakerHandle); + delete _speakerStream; + _speakerStream = nullptr; + + return inputChar; +} + void EfhEngine::generateSound1(int lowFreq, int highFreq, int duration) { debugC(3, kDebugEngine, "generateSound1 %d %d %d - suspicious code", lowFreq, highFreq, duration); From 207bbbbbbfe8fd47d9e79843b172cf767400c845 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Fri, 27 Jan 2023 19:29:22 +0100 Subject: [PATCH 267/412] EFH: Turn some debug into debugC() --- engines/efh/efh.cpp | 4 +--- engines/efh/fight.cpp | 6 +++--- engines/efh/menu.cpp | 2 +- engines/efh/script.cpp | 2 +- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index c4909c73f4cc..976b04831eb4 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -58,8 +58,6 @@ EfhEngine::~EfhEngine() { } Common::Error EfhEngine::run() { - debug("run"); - initialize(); initGraphics(320, 200); @@ -2480,7 +2478,7 @@ void EfhEngine::checkProtection() { } void EfhEngine::loadEfhGame() { - debug("loadEfhGame"); + debugC(2, kDebugEngine, "loadEfhGame"); // The original used a loop to check for the presence of the savegame on the current floppy. // When the savegame wasn't found, it was displaying a screen asking for Disk 1 and was setting a flag used diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index 5efc40a152da..2ff065801bc2 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -78,7 +78,7 @@ void EfhEngine::initFight(int16 monsterId) { } bool EfhEngine::handleFight(int16 monsterId) { - debug("handleFight %d", monsterId); + debugC(3, kDebugFight, "handleFight %d", monsterId); _ongoingFightFl = true; @@ -210,7 +210,7 @@ void EfhEngine::handleFight_checkEndEffect(int16 charId) { } void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { - debug("handleFight_lastAction_A %d", teamCharId); + debugC(3, kDebugFight, "handleFight_lastAction_A %d", teamCharId); // In the original, this function is part of handleFight. // It has been split for readability purposes. @@ -486,7 +486,7 @@ bool EfhEngine::handleFight_lastAction_U(int16 teamCharId) { void EfhEngine::handleFight_MobstersAttack(int groupId) { // In the original, this function is part of handleFight. // It has been split for readability purposes. - debug("handleFight_MobstersAttack %d", groupId); + debugC(3, kDebugFight, "handleFight_MobstersAttack %d", groupId); // handleFight - Loop on mobsterId - Start for (uint ctrMobsterId = 0; ctrMobsterId < 9; ++ctrMobsterId) { diff --git a/engines/efh/menu.cpp b/engines/efh/menu.cpp index c7bcc2cd675b..afb9593bb754 100644 --- a/engines/efh/menu.cpp +++ b/engines/efh/menu.cpp @@ -889,7 +889,7 @@ void EfhEngine::tryToggleEquipped(int16 charId, int16 objectId, int16 windowId, } int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, int16 menuId, int16 curMenuLine, int16 gameMode) { - debug("useObject %d %d %d %d %d %s", charId, objectId, teamMonsterId, menuId, curMenuLine, gameMode == 3 ? "Combat" : "Normal"); + debugC(3, kDebugEngine, "useObject %d %d %d %d %d %s", charId, objectId, teamMonsterId, menuId, curMenuLine, gameMode == 3 ? "Combat" : "Normal"); Common::String buffer1 = ""; diff --git a/engines/efh/script.cpp b/engines/efh/script.cpp index 2eb19348c935..298e960cf05d 100644 --- a/engines/efh/script.cpp +++ b/engines/efh/script.cpp @@ -55,7 +55,7 @@ uint8 *EfhEngine::script_getNumber(uint8 *srcBuffer, int16 *retBuf) { } int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 posY, int16 maxX, int16 maxY, bool scriptExecuteFlag) { - debug("script_parse stringBuffer %d-%d %d-%d %s", posX, posY, maxX, maxY, scriptExecuteFlag ? "True" : "False"); + debugC(3, kDebugScript, "script_parse stringBuffer %d-%d %d-%d %s", posX, posY, maxX, maxY, scriptExecuteFlag ? "True" : "False"); debugC(6, kDebugScript, "%s", stringBuffer.c_str()); bool doneFlag = false; From 0ee97e0a6568b2503423355fd8e0a3b929cf0c83 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Fri, 27 Jan 2023 22:38:40 +0100 Subject: [PATCH 268/412] EFH: Use hex values for palette definition --- engines/efh/graphics.cpp | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/engines/efh/graphics.cpp b/engines/efh/graphics.cpp index 7d73ea35cf9a..2ac0736e1b40 100644 --- a/engines/efh/graphics.cpp +++ b/engines/efh/graphics.cpp @@ -28,22 +28,22 @@ namespace Efh { void EfhEngine::initPalette() { // Strangerke - values from a tool I wrote in 2008. I can't remember if it's guess work or not. static const uint8 pal[3 * 16] = { - 0, 0, 0, - 0, 0, 170, - 0, 170, 0, - 0, 170, 170, - 170, 0, 0, - 170, 0, 170, - 170, 85, 0, - 170, 170, 170, - 85, 85, 85, - 85, 85, 255, - 1, 1, 1, // Color 0xA is for transparency - 85, 255, 255, - 255, 85, 85, - 255, 85, 255, - 255, 255, 85, - 255, 255, 255 + 0x00, 0x00, 0x00, + 0x00, 0x00, 0xAA, + 0x00, 0xAA, 0x00, + 0x00, 0xAA, 0xAA, + 0xAA, 0x00, 0x00, + 0xAA, 0x00, 0xAA, + 0xAA, 0x55, 0x00, + 0xAA, 0xAA, 0xAA, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0xFF, + 0x01, 0x01, 0x01, // Color 0xA is for transparency + 0x55, 0xFF, 0xFF, + 0xFF, 0x55, 0x55, + 0xFF, 0x55, 0xFF, + 0xFF, 0xFF, 0x55, + 0xFF, 0xFF, 0xFF }; debugC(1, kDebugGraphics, "initPalette"); From b62431dd4dea54dec694afe62f08bef73708c3c7 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Fri, 27 Jan 2023 22:42:17 +0100 Subject: [PATCH 269/412] EFH: Fix fileorder in makefile --- engines/efh/module.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/engines/efh/module.mk b/engines/efh/module.mk index a81d60c278d7..d8e9fc59b097 100644 --- a/engines/efh/module.mk +++ b/engines/efh/module.mk @@ -8,11 +8,11 @@ MODULE_OBJS = \ graphics.o \ init.o \ menu.o \ + metaengine.o \ savegames.o \ script.o \ sound.o \ - utils.o \ - metaengine.o + utils.o MODULE_DIRS += \ engines/efh From cdd3004c29611dc205231c5a90879e7e836fcdf9 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Fri, 27 Jan 2023 23:11:38 +0100 Subject: [PATCH 270/412] EFH: Make use of dump-scripts command instead of defines --- engines/efh/files.cpp | 21 ++++++++++----------- engines/efh/utils.cpp | 25 +++++++++++++------------ 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/engines/efh/files.cpp b/engines/efh/files.cpp index 9940cde059ab..d1350447048e 100644 --- a/engines/efh/files.cpp +++ b/engines/efh/files.cpp @@ -19,6 +19,7 @@ * */ +#include "common/config-manager.h" #include "efh/efh.h" namespace Efh { @@ -88,18 +89,16 @@ void EfhEngine::rImageFile(Common::String filename, uint8 *targetBuffer, uint8 * debugC(1, kDebugUtils, "rImageFile %s", filename.c_str()); readFileToBuffer(filename, packedBuffer); -#ifndef debug - uncompressBuffer(packedBuffer, targetBuffer); -#else uint32 size = uncompressBuffer(packedBuffer, targetBuffer); - // dump a decompressed image file - Common::DumpFile dump; - dump.open(filename + ".dump"); - dump.write(targetBuffer, size); - dump.flush(); - dump.close(); - // End of dump -#endif + if (ConfMan.getBool("dump_scripts")) { + // dump a decompressed image file + Common::DumpFile dump; + dump.open(filename + ".dump"); + dump.write(targetBuffer, size); + dump.flush(); + dump.close(); + // End of dump + } // TODO: Refactoring: once uncompressed, the container contains for each image its width, its height, and raw data (4 Bpp) // => Write a class to handle that more properly diff --git a/engines/efh/utils.cpp b/engines/efh/utils.cpp index e10b99c5462d..ed4a9ceceb36 100644 --- a/engines/efh/utils.cpp +++ b/engines/efh/utils.cpp @@ -19,6 +19,7 @@ * */ +#include "common/config-manager.h" #include "common/system.h" #include "common/random.h" #include "efh/efh.h" @@ -60,19 +61,19 @@ void EfhEngine::decryptImpFile(bool techMapFl) { ++curPtr; } while (*curPtr != 0x60 && counter <= target); -#ifdef debug -// Dump the decompressed IMP file - Common::DumpFile dump; - if (!techMapFl) { - dump.open("imp2_unc.dump"); - dump.write(_imp2, curPtr - _imp2); - } else { - dump.open("imp1_unc.dump"); - dump.write(_imp1, curPtr - _imp1); + if (ConfMan.getBool("dump_scripts")) { + // Dump the decompressed IMP file + Common::DumpFile dump; + if (!techMapFl) { + dump.open("imp2_unc.dump"); + dump.write(_imp2, curPtr - _imp2); + } else { + dump.open("imp1_unc.dump"); + dump.write(_imp1, curPtr - _imp1); + } + dump.flush(); + dump.close(); } - dump.flush(); - dump.close(); -#endif } void EfhEngine::loadImageSet(int16 imageSetId, uint8 *buffer, uint8 **subFilesArray, uint8 *destBuffer) { From 956913fbbe0ca32c8d4577680a6c5a1db85eb276 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Fri, 27 Jan 2023 23:36:59 +0100 Subject: [PATCH 271/412] EFH: Add brackets for look consistency --- engines/efh/fight.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index 2ff065801bc2..7dfdcf7ea1cf 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -775,9 +775,9 @@ void EfhEngine::getDeathTypeDescription(int16 victimId, int16 attackerId) { else deathType = _items[exclusiveItemId]._attackType + 1; } - } else if (_teamMonsterIdArray[attackerId] == -1) + } else if (_teamMonsterIdArray[attackerId] == -1) { deathType = 0; - else { + } else { int16 itemId = _mapMonsters[_techId][_teamMonsterIdArray[attackerId]]._weaponItemId; deathType = _items[itemId]._attackType + 1; } From f41c0e85ed0ffc20a76231a8cc972d387c27ae8b Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sun, 29 Jan 2023 09:29:39 +0100 Subject: [PATCH 272/412] EFH: Add code to dump decoded maps --- engines/efh/files.cpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/engines/efh/files.cpp b/engines/efh/files.cpp index d1350447048e..dc8303c9d065 100644 --- a/engines/efh/files.cpp +++ b/engines/efh/files.cpp @@ -322,6 +322,11 @@ void EfhEngine::loadNPCS() { * This is required in order to implement a clean savegame feature */ void EfhEngine::preLoadMaps() { + Common::DumpFile dump; + if (ConfMan.getBool("dump_scripts")) { + dump.open("efhMaps.dump"); + } + for (int idx = 0; idx < 19; ++idx) { Common::String fileName = Common::String::format("tech.%d", idx); readFileToBuffer(fileName, _hiResImageBuf); @@ -344,6 +349,14 @@ void EfhEngine::preLoadMaps() { _mapSpecialTiles[idx][i]._triggerId = mapSpecialTilePtr[9 * i + 4]; _mapSpecialTiles[idx][i]._field5_textId = READ_LE_UINT16(&mapSpecialTilePtr[9 * i + 5]); _mapSpecialTiles[idx][i]._field7_textId = READ_LE_UINT16(&mapSpecialTilePtr[9 * i + 7]); + + if (ConfMan.getBool("dump_scripts") && _mapSpecialTiles[idx][i]._placeId != 0xFF) { + // dump a decoded version of the maps + Common::String buffer = Common::String::format("[%d][%d] _ placeId: 0x%02X _pos: %d, %d _field3: 0x%02X (%d), triggerId: %d, _field5/7: %d %d\n" + , idx, i, _mapSpecialTiles[idx][i]._placeId, _mapSpecialTiles[idx][i]._posX, _mapSpecialTiles[idx][i]._posX, _mapSpecialTiles[idx][i]._field3 + , _mapSpecialTiles[idx][i]._field3, _mapSpecialTiles[idx][i]._triggerId, _mapSpecialTiles[idx][i]._field5_textId, _mapSpecialTiles[idx][i]._field7_textId); + dump.write(buffer.c_str(), buffer.size()); + } } uint8 *mapMonstersPtr = &_mapArr[idx][902]; @@ -368,8 +381,11 @@ void EfhEngine::preLoadMaps() { for (int j = 0; j < 64; ++j) _mapGameMaps[idx][i][j] = *mapPtr++; } - + } + if (ConfMan.getBool("dump_scripts")) { + dump.flush(); + dump.close(); } } From de2f2390ee4d3f4630bd93fcb905bafbb3b60bc2 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sun, 29 Jan 2023 09:30:59 +0100 Subject: [PATCH 273/412] EFH: Introduce getArticle(), some renaming --- engines/efh/efh.cpp | 8 ++-- engines/efh/efh.h | 1 + engines/efh/fight.cpp | 108 ++++++++++++++++-------------------------- engines/efh/utils.cpp | 6 +++ 4 files changed, 52 insertions(+), 71 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 976b04831eb4..4558268a7cf3 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -2093,16 +2093,16 @@ bool EfhEngine::handleInteractionText(int16 mapPosX, int16 mapPosY, int16 charId } // original makes a useless check on (_mapSpecialTile[tileId]._field3 > 0x7F) } else if (_mapSpecialTiles[_techId][tileId]._field3 <= 0x77) { - int16 var6 = _mapSpecialTiles[_techId][tileId]._field3; + int16 scoreId = _mapSpecialTiles[_techId][tileId]._field3; for (int counter = 0; counter < _teamSize; ++counter) { if (_teamCharId[counter] == -1) continue; for (uint var2 = 0; var2 < 39; ++var2) { - // CHECKME : the whole loop doesn't make much sense as it's using var6 instead of var2, plus _activeScore is an array of 15 bytes, not 0x77... + // CHECKME : the whole loop doesn't make much sense as it's using scoreId instead of var2, plus _activeScore is an array of 15 bytes, not 0x77... // Also, 39 correspond to the size of activeScore + passiveScore + infoScore + the 2 remaining bytes of the struct - warning("handleInteractionText - _activeScore[%d]", var6); - if (_npcBuf[_teamCharId[counter]]._activeScore[var6] >= _mapSpecialTiles[_techId][tileId]._triggerId) { + warning("handleInteractionText - _activeScore[%d]", scoreId); + if (_npcBuf[_teamCharId[counter]]._activeScore[scoreId] >= _mapSpecialTiles[_techId][tileId]._triggerId) { displayImp1Text(_mapSpecialTiles[_techId][tileId]._field5_textId); return true; } diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 0a7329e1aa45..f13f1358aaf2 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -505,6 +505,7 @@ class EfhEngine : public Engine { void setNumLock(); bool getValidationFromUser(); uint32 ROR(uint32 val, uint8 shiftVal); + Common::String getArticle(int pronoun); uint8 _videoMode; uint8 _bufferCharBM[128]; diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index 7dfdcf7ea1cf..6dd3e4a02d95 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -183,12 +183,8 @@ void EfhEngine::handleFight_checkEndEffect(int16 charId) { // At this point : The status is different to 0 (normal) and the effect duration is finally 0 (end of effect) _enemyNamePt2 = _npcBuf[_teamCharId[charId]]._name; - if (_npcBuf[_teamCharId[charId]].getPronoun() == 2) { - _enemyNamePt1 = "The "; - } else { - _enemyNamePt1 = ""; - } - + _enemyNamePt1 = getArticle(_npcBuf[_teamCharId[charId]].getPronoun()); + // End of effect message depends on the type of effect switch (_teamCharStatus[charId]._status) { case 1: @@ -262,7 +258,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { noticedFl = false; int16 randomDamageAbsorbed = getRandom(_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._maxDamageAbsorption); - int16 ennemyPronoun = _npcBuf[_teamCharId[teamCharId]].getPronoun(); + int16 enemyPronoun = _npcBuf[_teamCharId[teamCharId]].getPronoun(); int16 monsterId = _teamMonsterIdArray[groupId]; int16 characterPronoun = kEncounters[_mapMonsters[_techId][monsterId]._monsterRef]._nameArticle; int16 charScore = getCharacterScore(_teamCharId[teamCharId], teamCharItemId); @@ -307,29 +303,22 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { } } int16 verbId = (3 * _items[teamCharItemId]._attackType + 1) + getRandom(3) - 1; - if (characterPronoun == 2) { - _characterNamePt1 = "The "; - } else { - _characterNamePt1 = ""; - } - - if (ennemyPronoun == 2) { - _enemyNamePt1 = "The "; - } else { - _enemyNamePt1 = ""; - } + _characterNamePt1 = getArticle(characterPronoun); _characterNamePt2 = kEncounters[_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._monsterRef]._name; + + _enemyNamePt1 = getArticle(enemyPronoun); _enemyNamePt2 = _npcBuf[_teamCharId[teamCharId]]._name; + _nameBuffer = _items[teamCharItemId]._name; if (checkSpecialItemsOnCurrentPlace(teamCharItemId)) { // Action A - Check damages - Start if (hitCount == 0) { - _messageToBePrinted = Common::String::format("%s%s %s at %s%s with %s %s, but misses!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[verbId], _characterNamePt1.c_str(), _characterNamePt2.c_str(), kPossessive[ennemyPronoun], _nameBuffer.c_str()); + _messageToBePrinted = Common::String::format("%s%s %s at %s%s with %s %s, but misses!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[verbId], _characterNamePt1.c_str(), _characterNamePt2.c_str(), kPossessive[enemyPronoun], _nameBuffer.c_str()); } else if (hitPoints <= 0) { - _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s, but does no damage!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[verbId], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[ennemyPronoun], _nameBuffer.c_str()); + _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s, but does no damage!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[verbId], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[enemyPronoun], _nameBuffer.c_str()); } else if (hitPoints == 1) { - _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s for 1 point", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[verbId], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[ennemyPronoun], _nameBuffer.c_str()); + _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s for 1 point", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[verbId], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[enemyPronoun], _nameBuffer.c_str()); if (_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] <= 0) { getDeathTypeDescription(groupId, teamCharId + 1000); getXPAndSearchCorpse(_teamCharId[teamCharId], _enemyNamePt1, _enemyNamePt2, _teamMonsterIdArray[groupId]); @@ -337,7 +326,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { _messageToBePrinted += "!"; } } else { - _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s for %d points", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[verbId], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[ennemyPronoun], _nameBuffer.c_str(), hitPoints); + _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s for %d points", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[verbId], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[enemyPronoun], _nameBuffer.c_str(), hitPoints); if (_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] <= 0) { getDeathTypeDescription(groupId, teamCharId + 1000); getXPAndSearchCorpse(_teamCharId[teamCharId], _enemyNamePt1, _enemyNamePt2, _teamMonsterIdArray[groupId]); @@ -413,7 +402,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { } // Action A - Check effect - End } else { - _messageToBePrinted = Common::String::format("%s%s tries to use %s %s, but it doesn't work!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPossessive[ennemyPronoun], _nameBuffer.c_str()); + _messageToBePrinted = Common::String::format("%s%s tries to use %s %s, but it doesn't work!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPossessive[enemyPronoun], _nameBuffer.c_str()); } genericGenerateSound(_items[teamCharItemId]._attackType, hitCount); @@ -429,14 +418,10 @@ void EfhEngine::handleFight_lastAction_D(int16 teamCharId) { debugC(3, kDebugFight, "handleFight_lastAction_D %d", teamCharId); _teamPctDodgeMiss[teamCharId] -= 40; - _enemyNamePt2 = _npcBuf[_teamCharId[teamCharId]]._name; uint8 pronoun = _npcBuf[_teamCharId[teamCharId]].getPronoun(); - - if (pronoun == 2) - _enemyNamePt1 = "The "; - else - _enemyNamePt1 = ""; + _enemyNamePt1 = getArticle(pronoun); + _enemyNamePt2 = _npcBuf[_teamCharId[teamCharId]]._name; _messageToBePrinted = Common::String::format("%s%s prepares to defend %sself!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPersonal[pronoun]); displayBoxWithText(_messageToBePrinted, 1, 2, true); @@ -449,13 +434,10 @@ void EfhEngine::handleFight_lastAction_H(int16 teamCharId) { debugC(3, kDebugFight, "handleFight_lastAction_H %d", teamCharId); _teamPctVisible[teamCharId] -= 50; - _enemyNamePt2 = _npcBuf[_teamCharId[teamCharId]]._name; - int16 pronoun = _npcBuf[_teamCharId[teamCharId]].getPronoun(); - if (pronoun == 2) - _enemyNamePt1 = "The "; - else - _enemyNamePt1 = ""; + int16 pronoun = _npcBuf[_teamCharId[teamCharId]].getPronoun(); + _enemyNamePt1 = getArticle(pronoun); + _enemyNamePt2 = _npcBuf[_teamCharId[teamCharId]]._name; _messageToBePrinted = Common::String::format("%s%s attempts to hide %sself!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPersonal[pronoun]); displayBoxWithText(_messageToBePrinted, 1, 2, true); @@ -468,13 +450,11 @@ bool EfhEngine::handleFight_lastAction_U(int16 teamCharId) { debugC(3, kDebugFight, "handleFight_lastAction_U %d", teamCharId); int16 itemId = _npcBuf[_teamCharId[teamCharId]]._inventory[_teamLastInventoryUsed[teamCharId]]._ref; - _enemyNamePt2 = _npcBuf[_teamCharId[teamCharId]]._name; _nameBuffer = _items[itemId]._name; + int16 pronoun = _npcBuf[_teamCharId[teamCharId]].getPronoun(); - if (pronoun == 2) - _enemyNamePt1 = "The "; - else - _enemyNamePt1 = ""; + _enemyNamePt1 = getArticle(pronoun); + _enemyNamePt2 = _npcBuf[_teamCharId[teamCharId]]._name; _messageToBePrinted = Common::String::format("%s%s uses %s %s! ", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPossessive[pronoun], _nameBuffer.c_str()); bool retVal = useObject(_teamCharId[teamCharId], _teamLastInventoryUsed[teamCharId], _teamNextAttack[teamCharId], teamCharId, 0, 3); @@ -518,9 +498,11 @@ void EfhEngine::handleFight_MobstersAttack(int groupId) { if (_teamCharId[targetId] == -1 || !isTeamMemberStatusNormal(targetId)) continue; - int16 randomeDefense = getRandom(getEquipmentDefense(_teamCharId[targetId], false)); - int16 ennemyPronoun = kEncounters[_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._monsterRef]._nameArticle; + int16 randomDefense = getRandom(getEquipmentDefense(_teamCharId[targetId], false)); + + int16 enemyPronoun = kEncounters[_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._monsterRef]._nameArticle; int16 characterPronoun = _npcBuf[_teamCharId[targetId]].getPronoun(); + _teamPctDodgeMiss[targetId] += (_items[monsterWeaponItemId].field_13 * 5); int16 hitCount = 0; int16 originalDamage = 0; @@ -537,14 +519,14 @@ void EfhEngine::handleFight_MobstersAttack(int groupId) { if (hasAdequateDefenseNPC(_teamCharId[targetId], _items[monsterWeaponItemId]._attackType)) continue; - int16 var7C = getRandom(_items[monsterWeaponItemId]._damage); - int varInt = var7C - randomeDefense; + int16 baseDamage = getRandom(_items[monsterWeaponItemId]._damage); + int deltaDamage = baseDamage - randomDefense; - if (varInt > 0) { - damagePointsAbsorbed += randomeDefense; - originalDamage += varInt; + if (deltaDamage > 0) { + damagePointsAbsorbed += randomDefense; + originalDamage += deltaDamage; } else { - damagePointsAbsorbed += var7C; + damagePointsAbsorbed += baseDamage; } // handleFight - Loop var84 on var64 (objectId) - End } @@ -566,33 +548,28 @@ void EfhEngine::handleFight_MobstersAttack(int groupId) { int16 var68 = _items[monsterWeaponItemId]._attackType + 1; int16 var6A = getRandom(3); - if (characterPronoun == 2) - _characterNamePt1 = "The "; - else - _characterNamePt1 = ""; - - if (ennemyPronoun == 2) - _enemyNamePt1 = "The "; - else - _enemyNamePt1 = ""; + _enemyNamePt1 = getArticle(enemyPronoun); _enemyNamePt2 = kEncounters[_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._monsterRef]._name; + + _characterNamePt1 = getArticle(characterPronoun); _characterNamePt2 = _npcBuf[_teamCharId[targetId]]._name; + _nameBuffer = _items[monsterWeaponItemId]._name; if (checkSpecialItemsOnCurrentPlace(monsterWeaponItemId)) { // handleFight - check damages - Start if (hitCount == 0) { - _messageToBePrinted = Common::String::format("%s%s %s at %s%s with %s %s, but misses!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1.c_str(), _characterNamePt2.c_str(), kPossessive[ennemyPronoun], _nameBuffer.c_str()); + _messageToBePrinted = Common::String::format("%s%s %s at %s%s with %s %s, but misses!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1.c_str(), _characterNamePt2.c_str(), kPossessive[enemyPronoun], _nameBuffer.c_str()); } else if (hitPoints <= 0) { - _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s, but does no damage!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[ennemyPronoun], _nameBuffer.c_str()); + _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s, but does no damage!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[enemyPronoun], _nameBuffer.c_str()); } else if (hitPoints == 1) { - _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s for 1 point", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[ennemyPronoun], _nameBuffer.c_str()); + _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s for 1 point", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[enemyPronoun], _nameBuffer.c_str()); if (_npcBuf[_teamCharId[targetId]]._hitPoints <= 0) getDeathTypeDescription(targetId + 1000, groupId); else _messageToBePrinted += "!"; } else { - _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s for %d points", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[ennemyPronoun], _nameBuffer.c_str(), hitPoints); + _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s for %d points", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[enemyPronoun], _nameBuffer.c_str(), hitPoints); if (_npcBuf[_teamCharId[targetId]]._hitPoints <= 0) getDeathTypeDescription(targetId + 1000, groupId); else @@ -623,7 +600,7 @@ void EfhEngine::handleFight_MobstersAttack(int groupId) { // handleFight - Add reaction text - end // handleFight - Check armor - start - if (randomeDefense != 0 && hitCount != 0 && _npcBuf[_teamCharId[targetId]]._hitPoints > 0) { + if (randomDefense != 0 && hitCount != 0 && _npcBuf[_teamCharId[targetId]]._hitPoints > 0) { if (damagePointsAbsorbed <= 1) _messageToBePrinted += Common::String::format(" %s%s's armor absorbs 1 point!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); else @@ -662,7 +639,7 @@ void EfhEngine::handleFight_MobstersAttack(int groupId) { } // handleFight - Check effect - end } else { - _messageToBePrinted = Common::String::format("%s%s tries to use %s %s, but it doesn't work!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPossessive[ennemyPronoun], _nameBuffer.c_str()); + _messageToBePrinted = Common::String::format("%s%s tries to use %s %s, but it doesn't work!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPossessive[enemyPronoun], _nameBuffer.c_str()); } genericGenerateSound(_items[monsterWeaponItemId]._attackType, hitCount); displayBoxWithText(_messageToBePrinted, 1, 2, true); @@ -671,11 +648,8 @@ void EfhEngine::handleFight_MobstersAttack(int groupId) { } else if (_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] > 0 && _teamMonsterEffects[groupId]._effect[ctrMobsterId] > 0) { --_teamMonsterEffects[groupId]._duration[ctrMobsterId]; if (_teamMonsterEffects[groupId]._duration[ctrMobsterId] <= 0) { + _enemyNamePt1 = getArticle(kEncounters[_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._monsterRef]._nameArticle); _enemyNamePt2 = kEncounters[_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._monsterRef]._name; - if (kEncounters[_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._monsterRef]._nameArticle == 2) - _enemyNamePt1 = "The "; - else - _enemyNamePt1 = ""; switch (_teamMonsterEffects[groupId]._effect[ctrMobsterId]) { case 1: diff --git a/engines/efh/utils.cpp b/engines/efh/utils.cpp index ed4a9ceceb36..6eba099c0bf5 100644 --- a/engines/efh/utils.cpp +++ b/engines/efh/utils.cpp @@ -300,4 +300,10 @@ uint32 EfhEngine::ROR(uint32 val, uint8 shiftVal) { return val >> shiftVal | val << (32 - shiftVal); } +Common::String EfhEngine::getArticle(int pronoun) { + if (pronoun == 2) + return "The "; + + return ""; +} } // End of namespace Efh From e20186c0bc0b5d5f7f4512de894663f617fa5c3d Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sun, 29 Jan 2023 10:54:55 +0100 Subject: [PATCH 274/412] EFH: Some renaming in drawMap --- engines/efh/efh.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 4558268a7cf3..359d04aafd78 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -633,27 +633,27 @@ void EfhEngine::drawMap(bool largeMapFl, int16 mapPosX, int16 mapPosY, int16 map } if (drawMonstersFl) { - for (uint var16 = 0; var16 < 64; ++var16) { - if ((_largeMapFlag && _mapMonsters[_techId][var16]._fullPlaceId == 0xFE) || (!_largeMapFlag && _mapMonsters[_techId][var16]._fullPlaceId == _fullPlaceId)){ + for (uint monsterId = 0; monsterId < 64; ++monsterId) { + if ((_largeMapFlag && _mapMonsters[_techId][monsterId]._fullPlaceId == 0xFE) || (!_largeMapFlag && _mapMonsters[_techId][monsterId]._fullPlaceId == _fullPlaceId)) { bool var4 = false; - int16 posX = _mapMonsters[_techId][var16]._posX; - int16 posY = _mapMonsters[_techId][var16]._posY; + int16 posX = _mapMonsters[_techId][monsterId]._posX; + int16 posY = _mapMonsters[_techId][monsterId]._posY; if (posX < minX || posX > maxX || posY < minY || posY > maxY) continue; for (uint counterY = 0; counterY < 9 && !var4; ++counterY) { - if (_mapMonsters[_techId][var16]._hitPoints[counterY] > 0) + if (_mapMonsters[_techId][monsterId]._hitPoints[counterY] > 0) var4 = true; } if (!var4) continue; - int16 var6 = 148 + kEncounters[_mapMonsters[_techId][var16]._monsterRef]._animId; - int16 var1 = _mapMonsters[_techId][var16]._possessivePronounSHL6 & 0x3F; + int16 var6 = 148 + kEncounters[_mapMonsters[_techId][monsterId]._monsterRef]._animId; + int16 var1 = _mapMonsters[_techId][monsterId]._possessivePronounSHL6 & 0x3F; - if (var1 == 0x3F && isNpcATeamMember(_mapMonsters[_techId][var16]._npcId)) + if (var1 == 0x3F && isNpcATeamMember(_mapMonsters[_techId][monsterId]._npcId)) continue; int16 drawPosX = 128 + (posX - minX) * 16; From 21ea9c9729354fc69dcb06ddd9f0adb3048303b8 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sun, 29 Jan 2023 22:50:08 +0100 Subject: [PATCH 275/412] EFH: Start making code less verbose, remove a useless parameter to getEquipmentDefense() --- engines/efh/efh.cpp | 87 +++++++++++++++++++++---------------------- engines/efh/efh.h | 2 +- engines/efh/fight.cpp | 2 +- engines/efh/menu.cpp | 2 +- 4 files changed, 45 insertions(+), 48 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 359d04aafd78..9919838b9386 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -454,13 +454,14 @@ void EfhEngine::initMapMonsters() { debugC(3, kDebugEngine, "initMapMonsters"); for (uint monsterId = 0; monsterId < 64; ++monsterId) { - if (_mapMonsters[_techId][monsterId]._fullPlaceId == 0xFF) + MapMonster *curMons = &_mapMonsters[_techId][monsterId]; + if (curMons->_fullPlaceId == 0xFF) continue; for (uint counter = 0; counter < 9; ++counter) - _mapMonsters[_techId][monsterId]._hitPoints[counter] = 0; + curMons->_hitPoints[counter] = 0; - uint8 groupSize = _mapMonsters[_techId][monsterId]._groupSize; + uint8 groupSize = curMons->_groupSize; if (groupSize == 0) groupSize = getRandom(10) - 1; @@ -469,17 +470,15 @@ void EfhEngine::initMapMonsters() { for (uint counter = 0; counter < groupSize; ++counter) { uint rand100 = getRandom(100); - uint16 pictureRef = kEncounters[_mapMonsters[_techId][monsterId]._monsterRef]._pictureRef; - - if (rand100 <= 25) { - uint16 delta = getRandom(pictureRef / 2); - _mapMonsters[_techId][monsterId]._hitPoints[counter] = pictureRef - delta; - } else if (rand100 <= 75) { - _mapMonsters[_techId][monsterId]._hitPoints[counter] = pictureRef; - } else { - uint16 delta = getRandom(pictureRef / 2); - _mapMonsters[_techId][monsterId]._hitPoints[counter] = pictureRef + delta; - } + uint16 pictureRef = kEncounters[curMons->_monsterRef]._pictureRef; + uint16 delta = getRandom(pictureRef / 2); + + if (rand100 <= 25) + curMons->_hitPoints[counter] = pictureRef - delta; + else if (rand100 <= 75) + curMons->_hitPoints[counter] = pictureRef; + else + curMons->_hitPoints[counter] = pictureRef + delta; } } } @@ -495,33 +494,27 @@ void EfhEngine::saveAnimImageSetId() { _animImageSetId = 0xFF; } -int16 EfhEngine::getEquipmentDefense(int16 charId, bool flag) { - debugC(2, kDebugGraphics, "getEquipmentDefense %d %s", charId, flag ? "True" : "False"); - // TODO: flag is always false, remove it when refactoring +int16 EfhEngine::getEquipmentDefense(int16 charId) { + debugC(2, kDebugGraphics, "getEquipmentDefense %d %s", charId); int16 altDef = 0; - int16 totalDef = 0; + for (int i = 0; i < 10; ++i) { - if (_npcBuf[charId]._inventory[i]._ref == 0x7FFF) - continue; + InvObject *curInvObj = &_npcBuf[charId]._inventory[i]; - if (!_npcBuf[charId]._inventory[i].isEquipped()) + if (curInvObj->_ref == 0x7FFF || !curInvObj->isEquipped()) continue; - int16 curDef = _npcBuf[charId]._inventory[i]._curHitPoints; + int16 curDef = curInvObj->_curHitPoints; if (curDef == 0xFF) - curDef = _items[_npcBuf[charId]._inventory[i]._ref]._defense; + curDef = _items[curInvObj->_ref]._defense; if (curDef <= 0) continue; - totalDef += curDef; altDef += (curDef / 8) + 1; } - if (flag) - return totalDef; - return altDef; } @@ -529,10 +522,12 @@ uint16 EfhEngine::getEquippedExclusiveType(int16 charId, int16 exclusiveType, bo debugC(2, kDebugEngine, "getEquippedExclusiveType %d %d %s", charId, exclusiveType, flag ? "True" : "False"); for (int i = 0; i < 10; ++i) { - if (!_npcBuf[charId]._inventory[i].isEquipped()) + InvObject *curInvObj = &_npcBuf[charId]._inventory[i]; + + if (!curInvObj->isEquipped()) continue; - int16 curItemId = _npcBuf[charId]._inventory[i]._ref; + int16 curItemId = curInvObj->_ref; if (_items[curItemId]._exclusiveType != exclusiveType) continue; @@ -634,31 +629,31 @@ void EfhEngine::drawMap(bool largeMapFl, int16 mapPosX, int16 mapPosY, int16 map if (drawMonstersFl) { for (uint monsterId = 0; monsterId < 64; ++monsterId) { - if ((_largeMapFlag && _mapMonsters[_techId][monsterId]._fullPlaceId == 0xFE) || (!_largeMapFlag && _mapMonsters[_techId][monsterId]._fullPlaceId == _fullPlaceId)) { - bool var4 = false; - int16 posX = _mapMonsters[_techId][monsterId]._posX; - int16 posY = _mapMonsters[_techId][monsterId]._posY; + MapMonster *curMapMons = &_mapMonsters[_techId][monsterId]; + if ((_largeMapFlag && curMapMons->_fullPlaceId == 0xFE) || (!_largeMapFlag && curMapMons->_fullPlaceId == _fullPlaceId)) { + int16 posX = curMapMons->_posX; + int16 posY = curMapMons->_posY; if (posX < minX || posX > maxX || posY < minY || posY > maxY) continue; - for (uint counterY = 0; counterY < 9 && !var4; ++counterY) { - if (_mapMonsters[_techId][monsterId]._hitPoints[counterY] > 0) - var4 = true; + bool groupAliveFl = false; + for (uint counterY = 0; counterY < 9 && !groupAliveFl; ++counterY) { + if (curMapMons->_hitPoints[counterY] > 0) + groupAliveFl = true; } - if (!var4) + if (!groupAliveFl) continue; - int16 var6 = 148 + kEncounters[_mapMonsters[_techId][monsterId]._monsterRef]._animId; - int16 var1 = _mapMonsters[_techId][monsterId]._possessivePronounSHL6 & 0x3F; + int16 imageSetIdx = 148 + kEncounters[curMapMons->_monsterRef]._animId; - if (var1 == 0x3F && isNpcATeamMember(_mapMonsters[_techId][monsterId]._npcId)) + if ((curMapMons->_possessivePronounSHL6 & 0x3F) == 0x3F && isNpcATeamMember(curMapMons->_npcId)) continue; int16 drawPosX = 128 + (posX - minX) * 16; drawPosY = 8 + (posY - minY) * 16; - displayRawDataAtPos(_imageSetSubFilesArray[var6], drawPosX, drawPosY); + displayRawDataAtPos(_imageSetSubFilesArray[imageSetIdx], drawPosX, drawPosY); } } } @@ -713,7 +708,7 @@ void EfhEngine::displayLowStatusScreen(bool flag) { Common::String buffer = _npcBuf[charId]._name; setTextPos(16, textPosY); displayStringAtTextPos(buffer); - buffer = Common::String::format("%d", getEquipmentDefense(charId, false)); + buffer = Common::String::format("%d", getEquipmentDefense(charId)); displayCenteredString(buffer, 104, 128, textPosY); buffer = Common::String::format("%d", _npcBuf[charId]._hitPoints); displayCenteredString(buffer, 144, 176, textPosY); @@ -757,9 +752,11 @@ void EfhEngine::displayLowStatusScreen(bool flag) { void EfhEngine::removeObject(int16 charId, int16 objectId) { debugC(6, kDebugEngine, "removeObject %d %d", charId, objectId); - _npcBuf[charId]._inventory[objectId]._ref = 0x7FFF; - _npcBuf[charId]._inventory[objectId]._stat1 = 0; - _npcBuf[charId]._inventory[objectId]._curHitPoints = 0; + + InvObject *curInvObj = &_npcBuf[charId]._inventory[objectId]; + curInvObj->_ref = 0x7FFF; + curInvObj->_stat1 = 0; + curInvObj->_curHitPoints = 0; } void EfhEngine::totalPartyKill() { diff --git a/engines/efh/efh.h b/engines/efh/efh.h index f13f1358aaf2..e332834dfc3d 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -290,7 +290,7 @@ class EfhEngine : public Engine { void initMapMonsters(); void loadMapArrays(int idx); void saveAnimImageSetId(); - int16 getEquipmentDefense(int16 charId, bool flag); + int16 getEquipmentDefense(int16 charId); uint16 getEquippedExclusiveType(int16 charId, int16 exclusiveType, bool flag); void displayLowStatusScreen(bool flag); void loadImageSetToTileBank(int16 tileBankId, int16 imageSetId); diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index 6dd3e4a02d95..ac857855a7d2 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -498,7 +498,7 @@ void EfhEngine::handleFight_MobstersAttack(int groupId) { if (_teamCharId[targetId] == -1 || !isTeamMemberStatusNormal(targetId)) continue; - int16 randomDefense = getRandom(getEquipmentDefense(_teamCharId[targetId], false)); + int16 randomDefense = getRandom(getEquipmentDefense(_teamCharId[targetId])); int16 enemyPronoun = kEncounters[_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._monsterRef]._nameArticle; int16 characterPronoun = _npcBuf[_teamCharId[targetId]].getPronoun(); diff --git a/engines/efh/menu.cpp b/engines/efh/menu.cpp index afb9593bb754..72a30f8db664 100644 --- a/engines/efh/menu.cpp +++ b/engines/efh/menu.cpp @@ -289,7 +289,7 @@ void EfhEngine::displayCharacterSummary(int16 curMenuLine, int16 npcId) { buffer1 = Common::String::format("Speed: %d", _npcBuf[npcId]._speed); setTextPos(146, 45); displayStringAtTextPos(buffer1); - buffer1 = Common::String::format("Defense: %d", getEquipmentDefense(npcId, false)); + buffer1 = Common::String::format("Defense: %d", getEquipmentDefense(npcId)); setTextPos(146, 54); displayStringAtTextPos(buffer1); buffer1 = Common::String::format("Hit Points: %d", _npcBuf[npcId]._hitPoints); From 116e15b3559920c07fde96ef1762184afb7ca375 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sun, 29 Jan 2023 22:54:48 +0100 Subject: [PATCH 276/412] EFH: Add code to keep track of character 2 status (and related duration) when character 1 leaves --- engines/efh/efh.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 9919838b9386..83d82b52a135 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -784,6 +784,10 @@ void EfhEngine::removeCharacterFromTeam(int16 teamMemberId) { for (int var4 = teamMemberId; var4 < 2; ++var4) { _teamCharId[var4] = _teamCharId[var4 + 1]; _teamCharId[var4 + 1] = -1; + + // The original isn't doing that, resulting in losing its altered status and remaining duration + _teamCharStatus[var4]._status = _teamCharStatus[var4 + 1]._status; + _teamCharStatus[var4]._duration = _teamCharStatus[var4 + 1]._duration; } refreshTeamSize(); From bd88a709f290e5b505023b9f0aa8591e808d4ba2 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Mon, 30 Jan 2023 07:51:58 +0100 Subject: [PATCH 277/412] EFH: Remove an unused buffer, rename another one --- engines/efh/efh.cpp | 14 ++++++++------ engines/efh/efh.h | 3 +-- engines/efh/files.cpp | 16 ++++++++-------- engines/efh/init.cpp | 3 +-- engines/efh/menu.cpp | 4 ++-- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 83d82b52a135..6417406190e7 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -292,7 +292,7 @@ void EfhEngine::playIntro() { displayRawDataAtPos(_circleImageSubFileArray[0], 0, 0); // Load animations on previous picture with GF - loadImageSet(63, _circleImageBuf, _circleImageSubFileArray, _hiResImageBuf); + loadImageSet(63, _circleImageBuf, _circleImageSubFileArray, _decompBuf); readImpFile(100, false); Common::KeyCode lastInput = getLastCharAfterAnimCount(8); if (lastInput == Common::KEYCODE_ESCAPE) @@ -388,7 +388,7 @@ void EfhEngine::initEngine() { saveAnimImageSetId(); // Load Title Screen, skip if loading a savegame from launcher - loadImageSet(11, _circleImageBuf, _circleImageSubFileArray, _hiResImageBuf); + loadImageSet(11, _circleImageBuf, _circleImageSubFileArray, _decompBuf); if (_loadSaveSlot == -1) { displayFctFullScreen(); displayRawDataAtPos(_circleImageSubFileArray[0], 0, 0); @@ -420,7 +420,7 @@ void EfhEngine::initEngine() { loadNPCS(); // Load picture room with girlfriend - loadImageSet(62, _circleImageBuf, _circleImageSubFileArray, _hiResImageBuf); + loadImageSet(62, _circleImageBuf, _circleImageSubFileArray, _decompBuf); fileName = "titlsong"; readFileToBuffer(fileName, _titleSong); setDefaultNoteDuration(); @@ -430,7 +430,7 @@ void EfhEngine::initEngine() { playIntro(); } - loadImageSet(6, _circleImageBuf, _circleImageSubFileArray, _hiResImageBuf); + loadImageSet(6, _circleImageBuf, _circleImageSubFileArray, _decompBuf); readImpFile(99, false); _introDoneFl = true; restoreAnimImageSetId(); @@ -783,11 +783,13 @@ void EfhEngine::removeCharacterFromTeam(int16 teamMemberId) { for (int var4 = teamMemberId; var4 < 2; ++var4) { _teamCharId[var4] = _teamCharId[var4 + 1]; - _teamCharId[var4 + 1] = -1; // The original isn't doing that, resulting in losing its altered status and remaining duration _teamCharStatus[var4]._status = _teamCharStatus[var4 + 1]._status; _teamCharStatus[var4]._duration = _teamCharStatus[var4 + 1]._duration; + // + + _teamCharId[var4 + 1] = -1; } refreshTeamSize(); @@ -2462,7 +2464,7 @@ void EfhEngine::loadImageSetToTileBank(int16 tileBankId, int16 imageSetId) { _mapBitmapRefArr[_techId]._setId2 = setId; int16 ptrIndex = bankId * 72; - loadImageSet(setId, _tileBank[bankId], &_imageSetSubFilesArray[ptrIndex], _hiResImageBuf); + loadImageSet(setId, _tileBank[bankId], &_imageSetSubFilesArray[ptrIndex], _decompBuf); } void EfhEngine::restoreAnimImageSetId() { diff --git a/engines/efh/efh.h b/engines/efh/efh.h index e332834dfc3d..a39559da8d2e 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -516,8 +516,7 @@ class EfhEngine : public Engine { uint8 _tileBank[3][12000]; uint8 _circleImageBuf[40100]; uint8 _portraitBuf[25000]; - uint8 _hiResImageBuf[40100]; - uint8 _loResImageBuf[40100]; + uint8 _decompBuf[40100]; uint8 _menuBuf[12500]; uint8 _windowWithBorderBuf[1500]; uint8 _mapArr[19][7000]; diff --git a/engines/efh/files.cpp b/engines/efh/files.cpp index dc8303c9d065..909e41be2cf5 100644 --- a/engines/efh/files.cpp +++ b/engines/efh/files.cpp @@ -169,7 +169,7 @@ void EfhEngine::loadNewPortrait() { findMapFile(_techId); _currentAnimImageSetId = 200 + _unkRelatedToAnimImageSetId; int imageSetId = _unkRelatedToAnimImageSetId + 13; - loadImageSet(imageSetId, _portraitBuf, _portraitSubFilesArray, _hiResImageBuf); + loadImageSet(imageSetId, _portraitBuf, _portraitSubFilesArray, _decompBuf); } void EfhEngine::loadAnimImageSet() { @@ -184,7 +184,7 @@ void EfhEngine::loadAnimImageSet() { _currentAnimImageSetId = _animImageSetId; int16 animSetId = _animImageSetId + 17; - loadImageSet(animSetId, _portraitBuf, _portraitSubFilesArray, _hiResImageBuf); + loadImageSet(animSetId, _portraitBuf, _portraitSubFilesArray, _decompBuf); } void EfhEngine::loadHistory() { @@ -232,8 +232,8 @@ void EfhEngine::loadPlacesFile(uint16 fullPlaceId, bool forceReloadFl) { if (_fullPlaceId < minPlace || _fullPlaceId > maxPlace || forceReloadFl) { _lastMainPlaceId = _fullPlaceId / 20; Common::String fileName = Common::String::format("places.%d", _lastMainPlaceId); - readFileToBuffer(fileName, _hiResImageBuf); - uncompressBuffer(_hiResImageBuf, _places); + readFileToBuffer(fileName, _decompBuf); + uncompressBuffer(_decompBuf, _places); } copyCurrentPlaceToBuffer(_fullPlaceId % 20); } @@ -329,12 +329,12 @@ void EfhEngine::preLoadMaps() { for (int idx = 0; idx < 19; ++idx) { Common::String fileName = Common::String::format("tech.%d", idx); - readFileToBuffer(fileName, _hiResImageBuf); - uncompressBuffer(_hiResImageBuf, _techDataArr[idx]); + readFileToBuffer(fileName, _decompBuf); + uncompressBuffer(_decompBuf, _techDataArr[idx]); fileName = Common::String::format("map.%d", idx); - readFileToBuffer(fileName, _hiResImageBuf); - uncompressBuffer(_hiResImageBuf, _mapArr[idx]); + readFileToBuffer(fileName, _decompBuf); + uncompressBuffer(_decompBuf, _mapArr[idx]); _mapBitmapRefArr[idx]._setId1 = _mapArr[idx][0]; _mapBitmapRefArr[idx]._setId2 = _mapArr[idx][1]; diff --git a/engines/efh/init.cpp b/engines/efh/init.cpp index 95ddff0a770e..39ce01765ca9 100644 --- a/engines/efh/init.cpp +++ b/engines/efh/init.cpp @@ -361,8 +361,7 @@ EfhEngine::EfhEngine(OSystem *syst, const ADGameDescription *gd) : Engine(syst), memset(_tileBank[i], 0, ARRAYSIZE(_tileBank[i])); memset(_circleImageBuf, 0, ARRAYSIZE(_circleImageBuf)); memset(_portraitBuf, 0, ARRAYSIZE(_portraitBuf)); - memset(_hiResImageBuf, 0, ARRAYSIZE(_hiResImageBuf)); - memset(_loResImageBuf, 0, ARRAYSIZE(_loResImageBuf)); + memset(_decompBuf, 0, ARRAYSIZE(_decompBuf)); memset(_menuBuf, 0, ARRAYSIZE(_menuBuf)); memset(_windowWithBorderBuf, 0, ARRAYSIZE(_windowWithBorderBuf)); memset(_places, 0, ARRAYSIZE(_places)); diff --git a/engines/efh/menu.cpp b/engines/efh/menu.cpp index 72a30f8db664..fbad82bb13f4 100644 --- a/engines/efh/menu.cpp +++ b/engines/efh/menu.cpp @@ -476,7 +476,7 @@ void EfhEngine::displayWindowAndStatusMenu(int16 charId, int16 windowId, int16 m debugC(6, kDebugEngine, "displayWindowAndStatusMenu %d %d %d %d", charId, windowId, menuId, curMenuLine); for (int counter = 0; counter < 2; ++counter) { - displayWindow(_menuBuf, 0, 0, _hiResImageBuf); + displayWindow(_menuBuf, 0, 0, _decompBuf); prepareStatusMenu(windowId, menuId, curMenuLine, charId, false); if (counter == 0) @@ -491,7 +491,7 @@ int16 EfhEngine::displayStringInSmallWindowWithBorder(Common::String str, bool d for (uint counter = 0; counter < 2; ++counter) { prepareStatusMenu(windowId, menuId, curMenuLine, charId, false); - displayWindow(_windowWithBorderBuf, 19, 113, _hiResImageBuf); + displayWindow(_windowWithBorderBuf, 19, 113, _decompBuf); if (counter == 0) { script_parse(str, 28, 122, 105, 166, false); From cb467912a60c4a7ed43036cf5313f76ed3214f3e Mon Sep 17 00:00:00 2001 From: Strangerke Date: Mon, 30 Jan 2023 08:16:13 +0100 Subject: [PATCH 278/412] EFH: More code simplification --- engines/efh/efh.cpp | 66 ++++++++++++++++++++------------------------- 1 file changed, 29 insertions(+), 37 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 6417406190e7..456d939fe3c9 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -902,17 +902,19 @@ bool EfhEngine::giveItemTo(int16 charId, int16 objectId, int16 fromCharId) { debugC(3, kDebugEngine, "giveItemTo %d %d %d", charId, objectId, fromCharId); for (uint newObjectId = 0; newObjectId < 10; ++newObjectId) { - if (_npcBuf[charId]._inventory[newObjectId]._ref != 0x7FFF) + InvObject *newInvObj = &_npcBuf[charId]._inventory[newObjectId]; + if (newInvObj->_ref != 0x7FFF) continue; if (fromCharId == 0xFF) { - _npcBuf[charId]._inventory[newObjectId]._ref = objectId; - _npcBuf[charId]._inventory[newObjectId]._curHitPoints = _items[objectId]._defense; - _npcBuf[charId]._inventory[newObjectId]._stat1 = _items[objectId]._uses; + newInvObj->_ref = objectId; + newInvObj->_curHitPoints = _items[objectId]._defense; + newInvObj->_stat1 = _items[objectId]._uses; } else { - _npcBuf[charId]._inventory[newObjectId]._ref = _npcBuf[fromCharId]._inventory[objectId]._ref; - _npcBuf[charId]._inventory[newObjectId]._curHitPoints = _npcBuf[fromCharId]._inventory[objectId]._curHitPoints; - _npcBuf[charId]._inventory[newObjectId]._stat1 = _npcBuf[fromCharId]._inventory[objectId].getUsesLeft(); // not equipped as the upper bit isn't set (0x80) + InvObject *fromInvObj = &_npcBuf[fromCharId]._inventory[objectId]; + newInvObj->_ref = fromInvObj->_ref; + newInvObj->_curHitPoints = fromInvObj->_curHitPoints; + newInvObj->_stat1 = fromInvObj->getUsesLeft(); // not equipped as the upper bit isn't set (0x80) } return true; @@ -1082,7 +1084,8 @@ int16 EfhEngine::findMapSpecialTileIndex(int16 posX, int16 posY) { uint16 searchPlaceId = _largeMapFlag ? 0xFE : _fullPlaceId; for (uint counter = 0; counter < 100; ++counter) { - if (_mapSpecialTiles[_techId][counter]._posX == posX && _mapSpecialTiles[_techId][counter]._posY == posY && _mapSpecialTiles[_techId][counter]._placeId == searchPlaceId) + MapSpecialTileStruct *curTile = &_mapSpecialTiles[_techId][counter]; + if (curTile->_posX == posX && curTile->_posY == posY && curTile->_placeId == searchPlaceId) return counter; } @@ -1106,13 +1109,10 @@ bool EfhEngine::isPosOutOfMap(int16 mapPosX, int16 mapPosY) { void EfhEngine::goSouth() { debugC(6,kDebugEngine, "goSouth"); - if (_largeMapFlag) { - if (++_mapPosY > 63) - _mapPosY = 63; - } else { - if (++_mapPosY > 23) - _mapPosY = 23; - } + int16 maxMapBlocks = _largeMapFlag ? 63 : 23; + + if (++_mapPosY > maxMapBlocks) + _mapPosY = maxMapBlocks; if (isPosOutOfMap(_mapPosX, _mapPosY)) { _mapPosX = _oldMapPosX; @@ -1135,13 +1135,10 @@ void EfhEngine::goNorth() { void EfhEngine::goEast() { debugC(6, kDebugEngine, "goEast"); - if (_largeMapFlag) { - if (++_mapPosX > 63) - _mapPosX = 63; - } else { - if (++_mapPosX > 23) - _mapPosX = 23; - } + int16 maxMapBlocks = _largeMapFlag ? 63 : 23; + + if (++_mapPosX > maxMapBlocks) + _mapPosX = maxMapBlocks; if (isPosOutOfMap(_mapPosX, _mapPosY)) { _mapPosX = _oldMapPosX; @@ -1184,17 +1181,13 @@ void EfhEngine::goNorthEast() { void EfhEngine::goSouthEast() { debugC(6, kDebugEngine, "goSouthEast"); - if (_largeMapFlag) { - if (++_mapPosX > 63) - _mapPosX = 63; - } else if (++_mapPosX > 23) - _mapPosX = 23; + int16 maxMapBlocks = _largeMapFlag ? 63 : 23; - if (_largeMapFlag) { - if (++_mapPosY > 63) - _mapPosY = 63; - } else if (++_mapPosY > 23) - _mapPosY = 23; + if (++_mapPosX > maxMapBlocks) + _mapPosX = maxMapBlocks; + + if (++_mapPosY > maxMapBlocks) + _mapPosY = maxMapBlocks; if (isPosOutOfMap(_mapPosX, _mapPosY)) { _mapPosX = _oldMapPosX; @@ -1223,11 +1216,10 @@ void EfhEngine::goSouthWest() { if (--_mapPosX < 0) _mapPosX = 0; - if (_largeMapFlag) { - if (++_mapPosY > 63) - _mapPosY = 63; - } else if (++_mapPosY > 23) - _mapPosY = 23; + int16 maxMapBlocks = _largeMapFlag ? 63 : 23; + + if (++_mapPosY > maxMapBlocks) + _mapPosY = maxMapBlocks; if (isPosOutOfMap(_mapPosX, _mapPosY)) { _mapPosX = _oldMapPosX; From 2a48a8f6c653623c5fa76fd7482f6db24d71d01b Mon Sep 17 00:00:00 2001 From: Strangerke Date: Mon, 30 Jan 2023 08:22:03 +0100 Subject: [PATCH 279/412] EFH: Fix issue in regen --- engines/efh/efh.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 456d939fe3c9..c59a35695781 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -1246,8 +1246,8 @@ void EfhEngine::handleNewRoundEffects() { for (int counter = 0; counter < _teamSize; ++counter) { NPCStruct *curNpc = &_npcBuf[_teamCharId[counter]]; - if (curNpc->_hitPoints < curNpc->_maxHP) - ++curNpc->_hitPoints = curNpc->_maxHP; + if (++curNpc->_hitPoints > curNpc->_maxHP) + curNpc->_hitPoints = curNpc->_maxHP; } _regenCounter = 0; } From e5cd8dc6ef8c37442b64cb4a82612bf7d85bcddd Mon Sep 17 00:00:00 2001 From: Strangerke Date: Mon, 30 Jan 2023 08:58:12 +0100 Subject: [PATCH 280/412] EFH: Add comment in checkMonsterMovementType, refactor computeMapAnimation and more code simplification --- engines/efh/efh.cpp | 133 +++++++++++++++++++++----------------------- 1 file changed, 62 insertions(+), 71 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index c59a35695781..8cba17a50203 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -1276,25 +1276,13 @@ void EfhEngine::computeMapAnimation() { if (_currentTileBankImageSetId[0] != 0) continue; - if (_largeMapFlag) { - uint8 curTile = _mapGameMaps[_techId][counterX][counterY]; - if (curTile >= 1 && curTile <= 0xF) { - if (getRandom(100) < 50) - _mapGameMaps[_techId][counterX][counterY] += 0xC5; - } else if (curTile >= 0xC6 && curTile <= 0xD5) { - if (getRandom(100) < 50) - _mapGameMaps[_techId][counterX][counterY] -= 0xC5; - } - } else { - uint8 curTile = _curPlace[counterX][counterY]; - if (curTile >= 1 && curTile <= 0xF) { - if (getRandom(100) < 50) - _curPlace[counterX][counterY] += 0xC5; - } else if (curTile >= 0xC6 && curTile <= 0xD5) { - if (getRandom(100) < 50) - _curPlace[counterX][counterY] -= 0xC5; - } - } + uint8 *curTile = _largeMapFlag ? &_mapGameMaps[_techId][counterX][counterY] : &_curPlace[counterX][counterY]; + + if (*curTile >= 1 && *curTile <= 0xF && getRandom(100) < 50) + *curTile += 0xC5; + else if (*curTile >= 0xC6 && *curTile <= 0xD5 && getRandom(100) < 50) + *curTile -= 0xC5; + } } } @@ -1320,10 +1308,11 @@ int8 EfhEngine::checkMonsterMoveCollisionAndTileTexture(int16 monsterId) { debugC(3, kDebugEngine,"checkMonsterMoveCollisionAndTileTexture %d", monsterId); int16 maxSize = _largeMapFlag ? 63 : 23; - if (_mapMonsters[_techId][monsterId]._posX < 0 || _mapMonsters[_techId][monsterId]._posY < 0 || _mapMonsters[_techId][monsterId]._posX > maxSize || _mapMonsters[_techId][monsterId]._posY > maxSize) + MapMonster *curMapMonster = &_mapMonsters[_techId][monsterId]; + if (curMapMonster->_posX < 0 || curMapMonster->_posY < 0 || curMapMonster->_posX > maxSize || curMapMonster->_posY > maxSize) return 0; - if (_mapMonsters[_techId][monsterId]._posX == _mapPosX && _mapMonsters[_techId][monsterId]._posY == _mapPosY) + if (curMapMonster->_posX == _mapPosX && curMapMonster->_posY == _mapPosY) return 0; for (int counter = 0; counter < 64; ++counter) { @@ -1333,43 +1322,43 @@ int8 EfhEngine::checkMonsterMoveCollisionAndTileTexture(int16 monsterId) { if (!checkMapMonsterAvailability(counter)) continue; - if (_mapMonsters[_techId][monsterId]._fullPlaceId == _mapMonsters[_techId][counter]._fullPlaceId - && _mapMonsters[_techId][monsterId]._posX == _mapMonsters[_techId][counter]._posX - && _mapMonsters[_techId][monsterId]._posY == _mapMonsters[_techId][counter]._posY) + MapMonster *compMapMonster = &_mapMonsters[_techId][counter]; + if (curMapMonster->_fullPlaceId == compMapMonster->_fullPlaceId && curMapMonster->_posX == compMapMonster->_posX && curMapMonster->_posY == compMapMonster->_posY) return 0; } - return checkTileStatus(_mapMonsters[_techId][monsterId]._posX, _mapMonsters[_techId][monsterId]._posY, false); + return checkTileStatus(curMapMonster->_posX, curMapMonster->_posY, false); } bool EfhEngine::moveMonsterAwayFromTeam(int16 monsterId) { debugC(6, kDebugEngine, "moveMonsterAwayFromTeam %d", monsterId); - if (_mapMonsters[_techId][monsterId]._posX < _mapPosX) { - --_mapMonsters[_techId][monsterId]._posX; - if (_mapMonsters[_techId][monsterId]._posY < _mapPosY) - --_mapMonsters[_techId][monsterId]._posY; - else if (_mapMonsters[_techId][monsterId]._posY > _mapPosY) - ++_mapMonsters[_techId][monsterId]._posY; + MapMonster *curMapMonster = &_mapMonsters[_techId][monsterId]; + if (curMapMonster->_posX < _mapPosX) { + --curMapMonster->_posX; + if (curMapMonster->_posY < _mapPosY) + --curMapMonster->_posY; + else if (curMapMonster->_posY > _mapPosY) + ++curMapMonster->_posY; return true; } - if (_mapMonsters[_techId][monsterId]._posX > _mapPosX) { - ++_mapMonsters[_techId][monsterId]._posX; - if (_mapMonsters[_techId][monsterId]._posY < _mapPosY) - --_mapMonsters[_techId][monsterId]._posY; - else if (_mapMonsters[_techId][monsterId]._posY > _mapPosY) - ++_mapMonsters[_techId][monsterId]._posY; + if (curMapMonster->_posX > _mapPosX) { + ++curMapMonster->_posX; + if (curMapMonster->_posY < _mapPosY) + --curMapMonster->_posY; + else if (curMapMonster->_posY > _mapPosY) + ++curMapMonster->_posY; return true; } // Original checks for posX equality, which is the only possible option at this point => skipped - if (_mapMonsters[_techId][monsterId]._posY < _mapPosY) - --_mapMonsters[_techId][monsterId]._posY; - else if (_mapMonsters[_techId][monsterId]._posY > _mapPosY) - ++_mapMonsters[_techId][monsterId]._posY; + if (curMapMonster->_posY < _mapPosY) + --curMapMonster->_posY; + else if (curMapMonster->_posY > _mapPosY) + ++curMapMonster->_posY; else return false; @@ -1379,31 +1368,32 @@ bool EfhEngine::moveMonsterAwayFromTeam(int16 monsterId) { bool EfhEngine::moveMonsterTowardsTeam(int16 monsterId) { debugC(6, kDebugEngine, "moveMonsterTowardsTeam %d", monsterId); - if (_mapMonsters[_techId][monsterId]._posX < _mapPosX) { - ++_mapMonsters[_techId][monsterId]._posX; - if (_mapMonsters[_techId][monsterId]._posY < _mapPosY) - ++_mapMonsters[_techId][monsterId]._posY; - else if (_mapMonsters[_techId][monsterId]._posY > _mapPosY) - --_mapMonsters[_techId][monsterId]._posY; + MapMonster *curMapMonster = &_mapMonsters[_techId][monsterId]; + if (curMapMonster->_posX < _mapPosX) { + ++curMapMonster->_posX; + if (curMapMonster->_posY < _mapPosY) + ++curMapMonster->_posY; + else if (curMapMonster->_posY > _mapPosY) + --curMapMonster->_posY; return true; } - if (_mapMonsters[_techId][monsterId]._posX > _mapPosX) { - --_mapMonsters[_techId][monsterId]._posX; - if (_mapMonsters[_techId][monsterId]._posY < _mapPosY) - ++_mapMonsters[_techId][monsterId]._posY; - else if (_mapMonsters[_techId][monsterId]._posY > _mapPosY) - --_mapMonsters[_techId][monsterId]._posY; + if (curMapMonster->_posX > _mapPosX) { + --curMapMonster->_posX; + if (curMapMonster->_posY < _mapPosY) + ++curMapMonster->_posY; + else if (curMapMonster->_posY > _mapPosY) + --curMapMonster->_posY; return true; } // Original checks for posX equality, which is the only possible option at this point => skipped - if (_mapMonsters[_techId][monsterId]._posY < _mapPosY) - ++_mapMonsters[_techId][monsterId]._posY; - else if (_mapMonsters[_techId][monsterId]._posY > _mapPosY) - --_mapMonsters[_techId][monsterId]._posY; + if (curMapMonster->_posY < _mapPosY) + ++curMapMonster->_posY; + else if (curMapMonster->_posY > _mapPosY) + --curMapMonster->_posY; else return false; @@ -1414,42 +1404,43 @@ bool EfhEngine::moveMonsterGroupOther(int16 monsterId, int16 direction) { debugC(6, kDebugEngine, "moveMonsterGroupOther %d %d", monsterId, direction); bool retVal; + MapMonster *curMapMonster = &_mapMonsters[_techId][monsterId]; switch (direction - 1) { case 0: - --_mapMonsters[_techId][monsterId]._posY; + --curMapMonster->_posY; retVal = true; break; case 1: - --_mapMonsters[_techId][monsterId]._posY; - ++_mapMonsters[_techId][monsterId]._posX; + --curMapMonster->_posY; + ++curMapMonster->_posX; retVal = true; break; case 2: - ++_mapMonsters[_techId][monsterId]._posX; + ++curMapMonster->_posX; retVal = true; break; case 3: - ++_mapMonsters[_techId][monsterId]._posX; - ++_mapMonsters[_techId][monsterId]._posY; + ++curMapMonster->_posX; + ++curMapMonster->_posY; retVal = true; break; case 4: - ++_mapMonsters[_techId][monsterId]._posY; + ++curMapMonster->_posY; retVal = true; break; case 5: - ++_mapMonsters[_techId][monsterId]._posY; - --_mapMonsters[_techId][monsterId]._posX; + ++curMapMonster->_posY; + --curMapMonster->_posX; retVal = true; break; case 6: - --_mapMonsters[_techId][monsterId]._posX; + --curMapMonster->_posX; retVal = true; break; case 7: - --_mapMonsters[_techId][monsterId]._posX; - --_mapMonsters[_techId][monsterId]._posY; + --curMapMonster->_posX; + --curMapMonster->_posY; retVal = true; break; default: @@ -1506,7 +1497,7 @@ bool EfhEngine::checkMonsterMovementType(int16 id, bool teamFlag) { if (teamFlag) monsterId = _teamMonsterIdArray[id]; - if ((_mapMonsters[_techId][monsterId]._additionalInfo & 0xF) >= 8) + if ((_mapMonsters[_techId][monsterId]._additionalInfo & 0xF) >= 8) // Check hostility return true; if (_unk2C8AA != 0 && (_mapMonsters[_techId][monsterId]._additionalInfo & 0x80) != 0) @@ -1580,7 +1571,7 @@ void EfhEngine::handleMapMonsterMoves() { int8 monsterMoveType = _mapMonsters[_techId][monsterId]._additionalInfo & 0xF; // 0000 1111 if (_unk2C8AA != 0 && (_mapMonsters[_techId][monsterId]._additionalInfo & 0x80)) // 1000 0000 - monsterMoveType = 9; + monsterMoveType = 9; // Hostility + Move type 1 int16 randomModPct = _mapMonsters[_techId][monsterId]._additionalInfo & 0x70; // 0111 0000 randomModPct >>= 4; // Max 7 (0111) From 103b590d07e82dd841f0ea54d92cab0fba402655 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Mon, 30 Jan 2023 23:17:49 +0100 Subject: [PATCH 281/412] EFH: Remove useless parameter from setMapMonsterAggressivenessAndMovementType(), simplify more code --- engines/efh/efh.cpp | 104 +++++++++++++++++++++--------------------- engines/efh/efh.h | 2 +- engines/efh/fight.cpp | 2 +- engines/efh/menu.cpp | 2 +- 4 files changed, 55 insertions(+), 55 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 8cba17a50203..fee4e53ed383 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -1469,8 +1469,9 @@ bool EfhEngine::moveMonsterGroupRandom(int16 monsterId) { int16 EfhEngine::computeMonsterGroupDistance(int16 monsterId) { debugC(2, kDebugEngine, "computeMonsterGroupDistance %d", monsterId); - int16 monsterPosX = _mapMonsters[_techId][monsterId]._posX; - int16 monsterPosY = _mapMonsters[_techId][monsterId]._posY; + MapMonster *curMapMonst = &_mapMonsters[_techId][monsterId]; + int16 monsterPosX = curMapMonst->_posX; + int16 monsterPosY = curMapMonst->_posY; int16 deltaX = monsterPosX - _mapPosX; int16 deltaY = monsterPosY - _mapPosY; @@ -1493,14 +1494,13 @@ bool EfhEngine::checkWeaponRange(int16 monsterId, int16 weaponId) { bool EfhEngine::checkMonsterMovementType(int16 id, bool teamFlag) { debugC(6, kDebugEngine, "checkMonsterMovementType %d %s", id, teamFlag ? "True" : "False"); - int16 monsterId = id; - if (teamFlag) - monsterId = _teamMonsterIdArray[id]; + int16 monsterId = teamFlag ? _teamMonsterIdArray[id] : id; + MapMonster *curMapMonst = &_mapMonsters[_techId][monsterId]; - if ((_mapMonsters[_techId][monsterId]._additionalInfo & 0xF) >= 8) // Check hostility + if ((curMapMonst->_additionalInfo & 0xF) >= 8) // Check hostility return true; - if (_unk2C8AA != 0 && (_mapMonsters[_techId][monsterId]._additionalInfo & 0x80) != 0) + if (_unk2C8AA != 0 && (curMapMonst->_additionalInfo & 0x80) != 0) return true; return false; @@ -1523,10 +1523,11 @@ bool EfhEngine::checkTeamWeaponRange(int16 monsterId) { bool EfhEngine::checkIfMonsterOnSameLargeMapPlace(int16 monsterId) { debugC(6, kDebugEngine, "checkIfMonsterOnSameLargeMapPlace %d", monsterId); - if (_largeMapFlag && _mapMonsters[_techId][monsterId]._fullPlaceId == 0xFE) + MapMonster *curMapMonst = &_mapMonsters[_techId][monsterId]; + if (_largeMapFlag && curMapMonst->_fullPlaceId == 0xFE) return true; - if (!_largeMapFlag && _mapMonsters[_techId][monsterId]._fullPlaceId == _fullPlaceId) + if (!_largeMapFlag && curMapMonst->_fullPlaceId == _fullPlaceId) return true; return false; @@ -1559,8 +1560,9 @@ void EfhEngine::handleMapMonsterMoves() { if (!checkIfMonsterOnSameLargeMapPlace(monsterId)) continue; - int16 previousPosX = _mapMonsters[_techId][monsterId]._posX; - int16 previousPosY = _mapMonsters[_techId][monsterId]._posY; + MapMonster *curMapMonst = &_mapMonsters[_techId][monsterId]; + int16 previousPosX = curMapMonst->_posX; + int16 previousPosY = curMapMonst->_posY; if (previousPosX < minDisplayedMapX || previousPosX > maxDisplayedMapX || previousPosY < minDisplayedMapY || previousPosY > maxDisplayedMapY) continue; @@ -1568,12 +1570,12 @@ void EfhEngine::handleMapMonsterMoves() { bool monsterMovedFl = false; int16 lastRangeCheck = 0; - int8 monsterMoveType = _mapMonsters[_techId][monsterId]._additionalInfo & 0xF; // 0000 1111 + int8 monsterMoveType = curMapMonst->_additionalInfo & 0xF; // 0000 1111 - if (_unk2C8AA != 0 && (_mapMonsters[_techId][monsterId]._additionalInfo & 0x80)) // 1000 0000 + if (_unk2C8AA != 0 && (curMapMonst->_additionalInfo & 0x80)) // 1000 0000 monsterMoveType = 9; // Hostility + Move type 1 - int16 randomModPct = _mapMonsters[_techId][monsterId]._additionalInfo & 0x70; // 0111 0000 + int16 randomModPct = curMapMonst->_additionalInfo & 0x70; // 0111 0000 randomModPct >>= 4; // Max 7 (0111) int16 retryCounter = randomModPct; @@ -1675,23 +1677,21 @@ void EfhEngine::handleMapMonsterMoves() { for (;;) { if (!monsterMovedFl) { - if (lastRangeCheck == 0) { - monsterMovedFl = true; - } else { + if (lastRangeCheck != 0) attackMonsterId = monsterId; - monsterMovedFl = true; - } + + monsterMovedFl = true; } else { int8 checkMoveFl = checkMonsterMoveCollisionAndTileTexture(monsterId); if (checkMoveFl == 0) { // Blocked - _mapMonsters[_techId][monsterId]._posX = previousPosX; - _mapMonsters[_techId][monsterId]._posY = previousPosY; + curMapMonst->_posX = previousPosX; + curMapMonst->_posY = previousPosY; monsterMovedFl = false; --retryCounter; } else if (checkMoveFl == 2) { // Wall - _mapMonsters[_techId][monsterId]._posX = previousPosX; - _mapMonsters[_techId][monsterId]._posY = previousPosY; + curMapMonst->_posX = previousPosX; + curMapMonst->_posY = previousPosY; } } @@ -1712,11 +1712,13 @@ void EfhEngine::handleMapMonsterMoves() { bool EfhEngine::checkMapMonsterAvailability(int16 monsterId) { debugC(6, kDebugEngine, "checkMapMonsterAvailability %d", monsterId); - if (_mapMonsters[_techId][monsterId]._fullPlaceId == 0xFF) + MapMonster *curMapMonst = &_mapMonsters[_techId][monsterId]; + + if (curMapMonst->_fullPlaceId == 0xFF) return false; for (uint counter = 0; counter < 9; ++counter) { - if (_mapMonsters[_techId][monsterId]._hitPoints[counter] > 0) + if (curMapMonst->_hitPoints[counter] > 0) return true; } @@ -1735,10 +1737,11 @@ void EfhEngine::displayMonsterAnim(int16 monsterId) { int16 EfhEngine::countAliveMonsters(int16 id) { debugC(6, kDebugEngine, "countAliveMonsters %d", id); - int16 count = 0; + MapMonster *curMapMonst = &_mapMonsters[_techId][id]; + int16 count = 0; for (uint counter = 0; counter < 9; ++counter) { - if (_mapMonsters[_techId][id]._hitPoints[counter] > 0) + if (curMapMonst->_hitPoints[counter] > 0) ++count; } @@ -1757,7 +1760,8 @@ bool EfhEngine::checkMonsterGroupDistance1OrLess(int16 monsterId) { bool EfhEngine::handleTalk(int16 monsterId, int16 arg2, int16 itemId) { debugC(6, kDebugEngine, "handleTalk %d %d %d", monsterId, arg2, itemId); - if (_mapMonsters[_techId][monsterId]._fullPlaceId == 0xFF) + MapMonster *curMapMonst = &_mapMonsters[_techId][monsterId]; + if (curMapMonst->_fullPlaceId == 0xFF) return false; if (countAliveMonsters(monsterId) < 1) @@ -1769,20 +1773,20 @@ bool EfhEngine::handleTalk(int16 monsterId, int16 arg2, int16 itemId) { if (!checkMonsterGroupDistance1OrLess(monsterId)) return false; - if ((_mapMonsters[_techId][monsterId]._possessivePronounSHL6 & 0x3F) != 0x3F) { - if (_mapMonsters[_techId][monsterId]._talkTextId == 0xFF || arg2 != 5) { + if ((curMapMonst->_possessivePronounSHL6 & 0x3F) != 0x3F) { + if (curMapMonst->_talkTextId == 0xFF || arg2 != 5) { return false; } displayMonsterAnim(monsterId); - displayImp1Text(_mapMonsters[_techId][monsterId]._talkTextId); + displayImp1Text(curMapMonst->_talkTextId); displayAnimFrames(0xFE, true); return true; } - if (isNpcATeamMember(_mapMonsters[_techId][monsterId]._npcId)) + if (isNpcATeamMember(curMapMonst->_npcId)) return false; - int16 npcId = _mapMonsters[_techId][monsterId]._npcId; + int16 npcId = curMapMonst->_npcId; switch (_npcBuf[npcId].field_10 - 0xEE) { case 0: if (arg2 == 4 && _npcBuf[npcId].field11_NpcId == itemId) { @@ -2254,19 +2258,15 @@ bool EfhEngine::hasObjectEquipped(int16 charId, int16 objectId) { } -void EfhEngine::setMapMonsterAggressivenessAndMovementType(int16 id, uint8 mask, bool groupFl) { - debugC(2, kDebugEngine, "setMapMonsterAggressivenessAndMovementType %d 0x%X %s", id, mask, groupFl ? "True" : "False"); +void EfhEngine::setMapMonsterAggressivenessAndMovementType(int16 id, uint8 mask) { + debugC(2, kDebugEngine, "setMapMonsterAggressivenessAndMovementType %d 0x%X", id, mask); - int16 monsterId; - if (groupFl) { // groupFl is always True - monsterId = _teamMonsterIdArray[id]; - } else { - monsterId = id; - } + int16 monsterId = _teamMonsterIdArray[id]; + MapMonster *curMapMonst = &_mapMonsters[_techId][monsterId]; mask &= 0x0F; - _mapMonsters[_techId][monsterId]._additionalInfo &= 0xF0; - _mapMonsters[_techId][monsterId]._additionalInfo |= mask; + curMapMonst->_additionalInfo &= 0xF0; + curMapMonst->_additionalInfo |= mask; } bool EfhEngine::isMonsterActive(int16 groupId, int16 id) { @@ -2317,15 +2317,15 @@ bool EfhEngine::checkMonsterCollision() { if (!checkMapMonsterAvailability(monsterId)) continue; - if (!(_largeMapFlag && _mapMonsters[_techId][monsterId]._fullPlaceId == 0xFE) - && !(!_largeMapFlag && _mapMonsters[_techId][monsterId]._fullPlaceId == _fullPlaceId)) + MapMonster *curMapMonst = &_mapMonsters[_techId][monsterId]; + + if (!(_largeMapFlag && curMapMonst->_fullPlaceId == 0xFE) && !(!_largeMapFlag && curMapMonst->_fullPlaceId == _fullPlaceId)) continue; - if ((_mapMonsters[_techId][monsterId]._possessivePronounSHL6 & 0x3F) > 0x3D - && ((_mapMonsters[_techId][monsterId]._possessivePronounSHL6 & 0x3F) != 0x3F || isNpcATeamMember(_mapMonsters[_techId][monsterId]._npcId))) + if ((curMapMonst->_possessivePronounSHL6 & 0x3F) > 0x3D && ((curMapMonst->_possessivePronounSHL6 & 0x3F) != 0x3F || isNpcATeamMember(curMapMonst->_npcId))) continue; - if (_mapMonsters[_techId][monsterId]._posX != _mapPosX || _mapMonsters[_techId][monsterId]._posY != _mapPosY) + if (curMapMonst->_posX != _mapPosX || curMapMonst->_posY != _mapPosY) continue; _mapPosX = _oldMapPosX; @@ -2336,7 +2336,7 @@ bool EfhEngine::checkMonsterCollision() { int16 mobsterCount = 0; for (uint mobsterCounter = 0; mobsterCounter < 9; ++mobsterCounter) { - if (_mapMonsters[_techId][monsterId]._hitPoints[mobsterCounter]) + if (curMapMonst->_hitPoints[mobsterCounter]) ++mobsterCount; } @@ -2345,18 +2345,18 @@ bool EfhEngine::checkMonsterCollision() { do { for (uint displayCounter = 0; displayCounter < 2; ++displayCounter) { Common::String dest; - switch (_mapMonsters[_techId][monsterId]._possessivePronounSHL6 & 0x3F) { + switch (curMapMonst->_possessivePronounSHL6 & 0x3F) { case 0x3E: buffer = "(NOT DEFINED)"; dest = "(NOT DEFINED)"; break; case 0x3F: // Special character name - dest = _npcBuf[_mapMonsters[_techId][monsterId]._npcId]._name; + dest = _npcBuf[curMapMonst->_npcId]._name; buffer = Common::String("with ") + dest; break; default: - dest = kEncounters[_mapMonsters[_techId][monsterId]._monsterRef]._name; + dest = kEncounters[curMapMonst->_monsterRef]._name; if (mobsterCount > 1) dest += "s"; diff --git a/engines/efh/efh.h b/engines/efh/efh.h index a39559da8d2e..5d0aa3aca5ab 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -361,7 +361,7 @@ class EfhEngine : public Engine { uint16 getXPLevel(uint32 xp); bool isItemCursed(int16 itemId); bool hasObjectEquipped(int16 charId, int16 objectId); - void setMapMonsterAggressivenessAndMovementType(int16 id, uint8 mask, bool groupFl); + void setMapMonsterAggressivenessAndMovementType(int16 id, uint8 mask); bool isMonsterActive(int16 groupId, int16 id); int16 getTileFactId(int16 mapPosX, int16 mapPosY); void setCharacterObjectToBroken(int16 charId, int16 objectId); diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index ac857855a7d2..1647a7c640ac 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -251,7 +251,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { bool noticedFl; if (!checkMonsterMovementType(groupId, true)) { - setMapMonsterAggressivenessAndMovementType(groupId, 9, true); + setMapMonsterAggressivenessAndMovementType(groupId, 9); _unk2C8AA += 500; noticedFl = true; } else diff --git a/engines/efh/menu.cpp b/engines/efh/menu.cpp index fbad82bb13f4..eefdfc6aeef9 100644 --- a/engines/efh/menu.cpp +++ b/engines/efh/menu.cpp @@ -1038,7 +1038,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in displayStringInSmallWindowWithBorder("There is no apparent affect!", false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += " The magic sparkles brilliant hues in the air!"; - setMapMonsterAggressivenessAndMovementType(teamMonsterId, _items[itemId]._field17_attackTypeDefense, true); + setMapMonsterAggressivenessAndMovementType(teamMonsterId, _items[itemId]._field17_attackTypeDefense); } objectUsedFl = true; break; From c6f3e50a28ce9ea4c83b6319c01103be6406034b Mon Sep 17 00:00:00 2001 From: Strangerke Date: Tue, 31 Jan 2023 07:28:54 +0100 Subject: [PATCH 282/412] EFH: Rename 3 previously unknown variables --- engines/efh/efh.cpp | 18 +++++++++--------- engines/efh/efh.h | 6 +++--- engines/efh/fight.cpp | 9 +++++---- engines/efh/init.cpp | 6 +++--- engines/efh/menu.cpp | 6 +++--- engines/efh/savegames.cpp | 2 +- engines/efh/script.cpp | 16 ++++++++-------- 7 files changed, 32 insertions(+), 31 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index fee4e53ed383..a8db6b39956f 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -265,8 +265,8 @@ Common::Error EfhEngine::run() { } } - if (_unk2C8AA > 0) - --_unk2C8AA; + if (_alertDelay > 0) + --_alertDelay; if (isTPK()) { if (handleDeathMenu()) @@ -1258,7 +1258,7 @@ void EfhEngine::resetGame() { _oldMapPosX = _mapPosX = 31; _oldMapPosY = _mapPosY = 31; _unkRelatedToAnimImageSetId = 0; - _unk2C8AA = 0; + _alertDelay = 0; } void EfhEngine::computeMapAnimation() { @@ -1500,7 +1500,7 @@ bool EfhEngine::checkMonsterMovementType(int16 id, bool teamFlag) { if ((curMapMonst->_additionalInfo & 0xF) >= 8) // Check hostility return true; - if (_unk2C8AA != 0 && (curMapMonst->_additionalInfo & 0x80) != 0) + if (_alertDelay != 0 && (curMapMonst->_additionalInfo & 0x80) != 0) return true; return false; @@ -1572,7 +1572,7 @@ void EfhEngine::handleMapMonsterMoves() { int8 monsterMoveType = curMapMonst->_additionalInfo & 0xF; // 0000 1111 - if (_unk2C8AA != 0 && (curMapMonst->_additionalInfo & 0x80)) // 1000 0000 + if (_alertDelay != 0 && (curMapMonst->_additionalInfo & 0x80)) // 1000 0000 monsterMoveType = 9; // Hostility + Move type 1 int16 randomModPct = curMapMonst->_additionalInfo & 0x70; // 0111 0000 @@ -2005,7 +2005,7 @@ void EfhEngine::displayImp1Text(int16 textId) { if (firstChar == 0x5E || firstChar == 0) { if (firstChar == 0x5E) { nextTextId = script_parse(_messageToBePrinted, 0, 0, 319, 199, true); - _word2C87A = false; + _textBoxDisabledByScriptFl = false; } } else { for (uint counter = 0; counter < 2; ++counter) { @@ -2144,8 +2144,8 @@ int8 EfhEngine::checkTileStatus(int16 mapPosX, int16 mapPosY, bool arg4) { handleInteractionText(mapPosX, mapPosY, -1, 0x7FFF, 0, tileFactId); } - if (_word2C880) { - _word2C880 = false; + if (_checkTileDisabledByScriptFl) { + _checkTileDisabledByScriptFl = false; return -1; } if (_tileFact[tileFactId]._tileId != 0xFF && !_dbgForceMonsterBlock) { @@ -2494,7 +2494,7 @@ void EfhEngine::loadEfhGame() { _teamSize = f.readSint16LE(); - _unk2C8AA = f.readSint16LE(); + _alertDelay = f.readSint16LE(); _word2C872 = f.readSint16LE(); diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 5d0aa3aca5ab..f5b5a340f047 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -583,15 +583,15 @@ class EfhEngine : public Engine { int16 _teamMonsterIdArray[5]; CharStatus _teamCharStatus[3]; - int16 _unk2C8AA; + int16 _alertDelay; int16 _teamLastAction[3]; int16 _teamSize; int16 _word2C872; - bool _word2C880; + bool _checkTileDisabledByScriptFl; bool _redrawNeededFl; bool _drawHeroOnMapFl; bool _drawMonstersOnMapFl; - bool _word2C87A; + bool _textBoxDisabledByScriptFl; int16 _imageSetSubFilesIdx; int16 _oldImageSetSubFilesIdx; diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index 1647a7c640ac..9df8db83cdc3 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -37,10 +37,11 @@ void EfhEngine::createOpponentList(int16 monsterTeamId) { break; for (uint monsterId = 0; monsterId < 64; ++monsterId) { - if (_mapMonsters[_techId][monsterId]._fullPlaceId == 0xFF) + MapMonster *curMapMonst = &_mapMonsters[_techId][monsterId]; + if (curMapMonst->_fullPlaceId == 0xFF) continue; - if (((_mapMonsters[_techId][monsterId]._possessivePronounSHL6 & 0x3F) != 0x3F || isNpcATeamMember(_mapMonsters[_techId][monsterId]._npcId)) && (_mapMonsters[_techId][monsterId]._possessivePronounSHL6 & 0x3F) > 0x3D) + if (((curMapMonst->_possessivePronounSHL6 & 0x3F) != 0x3F || isNpcATeamMember(curMapMonst->_npcId)) && (curMapMonst->_possessivePronounSHL6 & 0x3F) > 0x3D) continue; if (!checkIfMonsterOnSameLargeMapPlace(monsterId)) @@ -48,7 +49,7 @@ void EfhEngine::createOpponentList(int16 monsterTeamId) { bool found = false; for (uint subId = 0; subId < 9; ++subId) { - if (_mapMonsters[_techId][monsterId]._hitPoints[subId] > 0) { + if (curMapMonst->_hitPoints[subId] > 0) { found = true; break; } @@ -252,7 +253,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { bool noticedFl; if (!checkMonsterMovementType(groupId, true)) { setMapMonsterAggressivenessAndMovementType(groupId, 9); - _unk2C8AA += 500; + _alertDelay += 500; noticedFl = true; } else noticedFl = false; diff --git a/engines/efh/init.cpp b/engines/efh/init.cpp index 39ce01765ca9..51c2c31d7c59 100644 --- a/engines/efh/init.cpp +++ b/engines/efh/init.cpp @@ -303,7 +303,7 @@ EfhEngine::EfhEngine(OSystem *syst, const ADGameDescription *gd) : Engine(syst), _fullPlaceId = 0xFF; _guessAnimationAmount = 9; _largeMapFlag = 0xFFFF; - _unk2C8AA = 0; + _alertDelay = 0; _teamCharId[0] = 0; _teamCharId[1] = _teamCharId[2] = -1; @@ -337,11 +337,11 @@ EfhEngine::EfhEngine(OSystem *syst, const ADGameDescription *gd) : Engine(syst), _lastMainPlaceId = 0; _tempTextDelay = 0; _tempTextPtr = nullptr; - _word2C880 = false; + _checkTileDisabledByScriptFl = false; _redrawNeededFl = false; _drawHeroOnMapFl = true; _drawMonstersOnMapFl = true; - _word2C87A = false; + _textBoxDisabledByScriptFl = false; _dbgForceMonsterBlock = false; _ongoingFightFl = false; _statusMenuActive = false; diff --git a/engines/efh/menu.cpp b/engines/efh/menu.cpp index eefdfc6aeef9..38a570a51db2 100644 --- a/engines/efh/menu.cpp +++ b/engines/efh/menu.cpp @@ -70,8 +70,8 @@ int16 EfhEngine::displayBoxWithText(Common::String str, int16 menuType, int16 di if (displayOption != 0) { displayFctFullScreen(); - if (_word2C87A) - _word2C87A = false; + if (_textBoxDisabledByScriptFl) + _textBoxDisabledByScriptFl = false; else { drawColoredRect(minX, minY, maxX, maxY, 0); if (!str.empty()) @@ -983,7 +983,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in displayStringInSmallWindowWithBorder("A serene feeling passes through the air...", false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += " The combat pauses...as there is a moment of forgiveness..."; - _unk2C8AA = 0; + _alertDelay = 0; } objectUsedFl = true; diff --git a/engines/efh/savegames.cpp b/engines/efh/savegames.cpp index 6e43acc9d797..46fb5b5c681c 100644 --- a/engines/efh/savegames.cpp +++ b/engines/efh/savegames.cpp @@ -138,7 +138,7 @@ void EfhEngine::synchronize(Common::Serializer &s) { } s.syncAsSint16LE(_teamSize); - s.syncAsSint16LE(_unk2C8AA); + s.syncAsSint16LE(_alertDelay); s.syncAsSint16LE(_word2C872); s.syncAsSint16LE(_imageSetSubFilesIdx); s.syncAsSint16LE(_mapPosX); diff --git a/engines/efh/script.cpp b/engines/efh/script.cpp index 298e960cf05d..164050d4b947 100644 --- a/engines/efh/script.cpp +++ b/engines/efh/script.cpp @@ -132,7 +132,7 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos _oldMapPosX = _mapPosX = scriptNumberArray[1]; _oldMapPosY = _mapPosY = scriptNumberArray[2]; loadPlacesFile(scriptNumberArray[0], false); - _word2C880 = true; + _checkTileDisabledByScriptFl = true; _redrawNeededFl = true; } break; @@ -142,7 +142,7 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos _largeMapFlag = true; _oldMapPosX = _mapPosX = _techDataId_MapPosX; _oldMapPosY = _mapPosY = _techDataId_MapPosY; - _word2C880 = true; + _checkTileDisabledByScriptFl = true; _redrawNeededFl = true; } break; @@ -155,7 +155,7 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos _oldMapPosY = _mapPosY = scriptNumberArray[2]; loadTechMapImp(scriptNumberArray[0]); _largeMapFlag = true; - _word2C880 = true; + _checkTileDisabledByScriptFl = true; _redrawNeededFl = true; doneFlag = true; } @@ -168,7 +168,7 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos _mapPosX = getRandom(rangeX) + scriptNumberArray[0] - 1; _mapPosY = getRandom(rangeY) + scriptNumberArray[1] - 1; - _word2C880 = true; + _checkTileDisabledByScriptFl = true; _redrawNeededFl = true; } break; @@ -177,7 +177,7 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos if (scriptExecuteFlag) { _mapPosX = scriptNumberArray[0]; _mapPosY = scriptNumberArray[1]; - _word2C880 = true; + _checkTileDisabledByScriptFl = true; _redrawNeededFl = true; } break; @@ -308,7 +308,7 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos break; case 0x11: if (scriptExecuteFlag) - _unk2C8AA = 0; + _alertDelay = 0; break; case 0x12: // Disable special tile @@ -321,7 +321,7 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos case 0x13: buffer = script_readNumberArray(buffer, 3, scriptNumberArray); if (scriptExecuteFlag && _largeMapFlag) { - _word2C87A = true; + _textBoxDisabledByScriptFl = true; loadPlacesFile(scriptNumberArray[0], false); transitionMap(scriptNumberArray[1], scriptNumberArray[2]); setSpecialTechZone(scriptNumberArray[0], scriptNumberArray[1], scriptNumberArray[2]); @@ -464,7 +464,7 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos case 0x1F: buffer = script_readNumberArray(buffer, 1, scriptNumberArray); if (scriptExecuteFlag) - _unk2C8AA = scriptNumberArray[0]; + _alertDelay = scriptNumberArray[0]; break; case 0x20: From 4e8c31e90ead7336fb09218093207fa3bfc29dc9 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Wed, 1 Feb 2023 07:11:40 +0100 Subject: [PATCH 283/412] EFH: Remove unused original debug code, start grouping team and teamMonster variables --- engines/efh/efh.cpp | 10 +++++----- engines/efh/efh.h | 14 +++++++------- engines/efh/init.cpp | 1 - 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index a8db6b39956f..76cfc876aeb1 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -227,7 +227,7 @@ Common::Error EfhEngine::run() { if ((_mapPosX != _oldMapPosX || _mapPosY != _oldMapPosY) && !_shouldQuit) { bool collisionFl = checkMonsterCollision(); - if (_dbgForceMonsterBlock || collisionFl) { + if (collisionFl) { _oldMapPosX = _mapPosX; _oldMapPosY = _mapPosY; _oldImageSetSubFilesIdx = _imageSetSubFilesIdx; @@ -2148,13 +2148,13 @@ int8 EfhEngine::checkTileStatus(int16 mapPosX, int16 mapPosY, bool arg4) { _checkTileDisabledByScriptFl = false; return -1; } - if (_tileFact[tileFactId]._tileId != 0xFF && !_dbgForceMonsterBlock) { + + if (_tileFact[tileFactId]._tileId != 0xFF) { if ((arg4) || (!arg4 && tileFactId != 128 && tileFactId != 121)) { - if (_largeMapFlag) { + if (_largeMapFlag) _mapGameMaps[_techId][mapPosX][mapPosY] = _tileFact[tileFactId]._tileId; - } else { + else _curPlace[mapPosX][mapPosY] = _tileFact[tileFactId]._tileId; - } _redrawNeededFl = true; if (_tileFact[tileFactId]._field0 == 0) diff --git a/engines/efh/efh.h b/engines/efh/efh.h index f5b5a340f047..c55d3f2b52a1 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -573,7 +573,6 @@ class EfhEngine : public Engine { uint16 _fullPlaceId; int16 _guessAnimationAmount; uint16 _largeMapFlag; // CHECKME: bool? - int16 _teamCharId[3]; int16 _textPosX; int16 _textPosY; @@ -581,10 +580,7 @@ class EfhEngine : public Engine { bool _engineInitPending; bool _protectionPassed; - int16 _teamMonsterIdArray[5]; - CharStatus _teamCharStatus[3]; int16 _alertDelay; - int16 _teamLastAction[3]; int16 _teamSize; int16 _word2C872; bool _checkTileDisabledByScriptFl; @@ -603,20 +599,24 @@ class EfhEngine : public Engine { uint16 _tempTextDelay; uint8 *_tempTextPtr; - // TODO: Remove those useless debug flags - bool _dbgForceMonsterBlock; // Original debug flag? Always false. bool _ongoingFightFl; bool _statusMenuActive; + int16 _menuStatItemArr[15]; int16 _menuDepth; int16 _menuItemCounter; + + int16 _teamCharId[3]; + CharStatus _teamCharStatus[3]; int16 _teamPctVisible[3]; int16 _teamPctDodgeMiss[3]; int16 _teamNextAttack[3]; int16 _teamLastInventoryUsed[3]; + int16 _teamLastAction[3]; - int16 _menuStatItemArr[15]; + int16 _teamMonsterIdArray[5]; TeamMonsterEffect _teamMonsterEffects[5]; + InitiativeStruct _initiatives[8]; int16 _regenCounter; diff --git a/engines/efh/init.cpp b/engines/efh/init.cpp index 51c2c31d7c59..3caf788835b4 100644 --- a/engines/efh/init.cpp +++ b/engines/efh/init.cpp @@ -342,7 +342,6 @@ EfhEngine::EfhEngine(OSystem *syst, const ADGameDescription *gd) : Engine(syst), _drawHeroOnMapFl = true; _drawMonstersOnMapFl = true; _textBoxDisabledByScriptFl = false; - _dbgForceMonsterBlock = false; _ongoingFightFl = false; _statusMenuActive = false; _menuDepth = 0; From 598a669091a74146592bce1eb2d11a56e666a57b Mon Sep 17 00:00:00 2001 From: Strangerke Date: Thu, 2 Feb 2023 14:02:52 +0100 Subject: [PATCH 284/412] EFH: Refactor TeamChar --- engines/efh/constants.h | 6 ++ engines/efh/efh.cpp | 98 +++++++++++------------ engines/efh/efh.h | 20 +++-- engines/efh/fight.cpp | 164 +++++++++++++++++++------------------- engines/efh/init.cpp | 18 ++--- engines/efh/menu.cpp | 68 ++++++++-------- engines/efh/savegames.cpp | 10 +-- engines/efh/script.cpp | 28 +++---- 8 files changed, 211 insertions(+), 201 deletions(-) diff --git a/engines/efh/constants.h b/engines/efh/constants.h index a0ba37c442ac..1a28145f4939 100644 --- a/engines/efh/constants.h +++ b/engines/efh/constants.h @@ -48,6 +48,12 @@ enum EfhReactionType { kEfhReactionLaughs = 6 }; +enum EfhStatusType { + kEfhStatusNormal = 0, + kEfhStatusSleeping = 1, + kEfhStatusFrozen = 2 +}; + struct Font { uint8 _lines[8]; }; diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 76cfc876aeb1..942f657378bf 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -136,24 +136,24 @@ Common::Error EfhEngine::run() { _imageSetSubFilesIdx = 147; break; case Common::KEYCODE_F1: - if (_teamCharId[0] != -1) { - handleStatusMenu(1, _teamCharId[0]); + if (_teamChar[0]._id != -1) { + handleStatusMenu(1, _teamChar[0]._id); _tempTextPtr = nullptr; drawGameScreenAndTempText(true); _redrawNeededFl = true; } break; case Common::KEYCODE_F2: - if (_teamCharId[1] != -1) { - handleStatusMenu(1, _teamCharId[1]); + if (_teamChar[1]._id != -1) { + handleStatusMenu(1, _teamChar[1]._id); _tempTextPtr = nullptr; drawGameScreenAndTempText(true); _redrawNeededFl = true; } break; case Common::KEYCODE_F3: - if (_teamCharId[2] != -1) { - handleStatusMenu(1, _teamCharId[2]); + if (_teamChar[2]._id != -1) { + handleStatusMenu(1, _teamChar[2]._id); _tempTextPtr = nullptr; drawGameScreenAndTempText(true); _redrawNeededFl = true; @@ -701,9 +701,9 @@ void EfhEngine::displayLowStatusScreen(bool flag) { setTextColorRed(); for (int i = 0; i < 3; ++i) { - if (_teamCharId[i] == -1) + if (_teamChar[i]._id == -1) continue; - int16 charId = _teamCharId[i]; + int16 charId = _teamChar[i]._id; int16 textPosY = 161 + 9 * i; Common::String buffer = _npcBuf[charId]._name; setTextPos(16, textPosY); @@ -720,8 +720,8 @@ void EfhEngine::displayLowStatusScreen(bool flag) { continue; } - switch (_teamCharStatus[i]._status) { - case 0: { + switch (_teamChar[i]._status._type) { + case kEfhStatusNormal: { uint16 exclusiveItemId = getEquippedExclusiveType(charId, 9, true); if (exclusiveItemId == 0x7FFF) _nameBuffer = "(NONE)"; @@ -729,10 +729,10 @@ void EfhEngine::displayLowStatusScreen(bool flag) { _nameBuffer = _items[exclusiveItemId]._name; } break; - case 1: + case kEfhStatusSleeping: _nameBuffer = "* ASLEEP *"; break; - case 2: + case kEfhStatusFrozen: _nameBuffer = "* FROZEN *"; break; default: @@ -763,7 +763,7 @@ void EfhEngine::totalPartyKill() { debugC(6, kDebugEngine, "totalPartyKill"); for (uint counter = 0; counter < 3; ++counter) { - if (_teamCharId[counter] != -1) + if (_teamChar[counter]._id != -1) _npcBuf[counter]._hitPoints = 0; } } @@ -771,25 +771,25 @@ void EfhEngine::totalPartyKill() { void EfhEngine::removeCharacterFromTeam(int16 teamMemberId) { debugC(6, kDebugEngine, "removeCharacterFromTeam %d", teamMemberId); - int16 charId = _teamCharId[teamMemberId]; + int16 charId = _teamChar[teamMemberId]._id; _npcBuf[charId].field12_textId = _npcBuf[charId].fieldB_textId; _npcBuf[charId].field14_textId = _npcBuf[charId].fieldE_textId; _npcBuf[charId].field_10 = _npcBuf[charId].field_C; _npcBuf[charId].field11_NpcId = _npcBuf[charId].field_D; - _teamCharId[teamMemberId] = -1; - _teamCharStatus[teamMemberId]._status = 0; - _teamCharStatus[teamMemberId]._duration = 0; + _teamChar[teamMemberId]._id = -1; + _teamChar[teamMemberId]._status._type = kEfhStatusNormal; + _teamChar[teamMemberId]._status._duration = 0; for (int var4 = teamMemberId; var4 < 2; ++var4) { - _teamCharId[var4] = _teamCharId[var4 + 1]; + _teamChar[var4]._id = _teamChar[var4 + 1]._id; // The original isn't doing that, resulting in losing its altered status and remaining duration - _teamCharStatus[var4]._status = _teamCharStatus[var4 + 1]._status; - _teamCharStatus[var4]._duration = _teamCharStatus[var4 + 1]._duration; + _teamChar[var4]._status._type = _teamChar[var4 + 1]._status._type; + _teamChar[var4]._status._duration = _teamChar[var4 + 1]._status._duration; // - _teamCharId[var4 + 1] = -1; + _teamChar[var4 + 1]._id = -1; } refreshTeamSize(); @@ -800,7 +800,7 @@ void EfhEngine::refreshTeamSize() { _teamSize = 0; for (uint charId = 0; charId < 3; ++charId) { - if (_teamCharId[charId] != -1) + if (_teamChar[charId]._id != -1) ++_teamSize; } } @@ -809,7 +809,7 @@ bool EfhEngine::isNpcATeamMember(int16 id) { debugC(6, kDebugEngine,"isNpcATeamMember %d", id); for (int charId = 0; charId < _teamSize; ++charId) { - if (_teamCharId[charId] == id) + if (_teamChar[charId]._id == id) return true; } @@ -944,7 +944,7 @@ int16 EfhEngine::handleCharacterJoining() { debugC(3, kDebugEngine, "handleCharacterJoining"); for (uint counter = 0; counter < 3; ++counter) { - if (_teamCharId[counter] == -1) { + if (_teamChar[counter]._id == -1) { return counter; } } @@ -1231,12 +1231,12 @@ void EfhEngine::handleNewRoundEffects() { debugC(6, kDebugEngine, "handleNewRoundEffects"); for (int counter = 0; counter < _teamSize; ++counter) { - CharStatus *curStatus = &_teamCharStatus[counter]; - if (curStatus->_status == 0) // normal + CharStatus *curStatus = &_teamChar[counter]._status; + if (curStatus->_type == kEfhStatusNormal) continue; if (--curStatus->_duration <= 0) { - curStatus->_status = 0; + curStatus->_type = kEfhStatusNormal; curStatus->_duration = 0; } } @@ -1245,7 +1245,7 @@ void EfhEngine::handleNewRoundEffects() { return; for (int counter = 0; counter < _teamSize; ++counter) { - NPCStruct *curNpc = &_npcBuf[_teamCharId[counter]]; + NPCStruct *curNpc = &_npcBuf[_teamChar[counter]._id]; if (++curNpc->_hitPoints > curNpc->_maxHP) curNpc->_hitPoints = curNpc->_maxHP; } @@ -1823,8 +1823,8 @@ bool EfhEngine::handleTalk(int16 monsterId, int16 arg2, int16 itemId) { case 4: for (int charId = 0; charId < _teamSize; ++charId) { for (uint inventoryId = 0; inventoryId < 10; ++inventoryId) { - if (_npcBuf[_teamCharId[charId]]._inventory[inventoryId]._ref == _npcBuf[npcId].field11_NpcId) { - removeObject(_teamCharId[charId], inventoryId); + if (_npcBuf[_teamChar[charId]._id]._inventory[inventoryId]._ref == _npcBuf[npcId].field11_NpcId) { + removeObject(_teamChar[charId]._id, inventoryId); displayMonsterAnim(monsterId); displayImp1Text(_npcBuf[npcId].field14_textId); displayAnimFrames(0xFE, true); @@ -1844,7 +1844,7 @@ bool EfhEngine::handleTalk(int16 monsterId, int16 arg2, int16 itemId) { case 6: for (int charId = 0; charId < _teamSize; ++charId) { for (uint inventoryId = 0; inventoryId < 10; ++inventoryId) { - if (_npcBuf[_teamCharId[charId]]._inventory[inventoryId]._ref == _npcBuf[npcId].field11_NpcId) { + if (_npcBuf[_teamChar[charId]._id]._inventory[inventoryId]._ref == _npcBuf[npcId].field11_NpcId) { displayMonsterAnim(monsterId); displayImp1Text(_npcBuf[npcId].field14_textId); displayAnimFrames(0xFE, true); @@ -1855,7 +1855,7 @@ bool EfhEngine::handleTalk(int16 monsterId, int16 arg2, int16 itemId) { break; case 7: for (int charId = 0; charId < _teamSize; ++charId) { - if (_npcBuf[npcId].field11_NpcId == _teamCharId[charId]) { + if (_npcBuf[npcId].field11_NpcId == _teamChar[charId]._id) { removeCharacterFromTeam(charId); displayMonsterAnim(monsterId); displayImp1Text(_npcBuf[npcId].field14_textId); @@ -1866,10 +1866,10 @@ bool EfhEngine::handleTalk(int16 monsterId, int16 arg2, int16 itemId) { break; case 8: for (int charId = 0; charId < _teamSize; ++charId) { - if (_npcBuf[npcId].field11_NpcId == _teamCharId[charId]) { + if (_npcBuf[npcId].field11_NpcId == _teamChar[charId]._id) { displayMonsterAnim(monsterId); _enemyNamePt2 = _npcBuf[npcId]._name; - _characterNamePt2 = _npcBuf[_teamCharId[charId]]._name; + _characterNamePt2 = _npcBuf[_teamChar[charId]._id]._name; Common::String buffer = Common::String::format("%s asks that %s leave your party.", _enemyNamePt2.c_str(), _characterNamePt2.c_str()); for (uint i = 0; i < 2; ++i) { clearBottomTextZone(0); @@ -1893,7 +1893,7 @@ bool EfhEngine::handleTalk(int16 monsterId, int16 arg2, int16 itemId) { break; case 9: for (int charId = 0; charId < _teamSize; ++charId) { - if (_npcBuf[npcId].field11_NpcId == _teamCharId[charId]) { + if (_npcBuf[npcId].field11_NpcId == _teamChar[charId]._id) { displayMonsterAnim(monsterId); displayImp1Text(_npcBuf[npcId].field14_textId); displayAnimFrames(0xFE, true); @@ -2062,20 +2062,20 @@ bool EfhEngine::handleInteractionText(int16 mapPosX, int16 mapPosY, int16 charId if (_mapSpecialTiles[_techId][tileId]._field3 == 0xFE) { for (int counter = 0; counter < _teamSize; ++counter) { - if (_teamCharId[counter] == -1) + if (_teamChar[counter]._id == -1) continue; - if (_teamCharId[counter] == _mapSpecialTiles[_techId][tileId]._triggerId) { + if (_teamChar[counter]._id == _mapSpecialTiles[_techId][tileId]._triggerId) { displayImp1Text(_mapSpecialTiles[_techId][tileId]._field5_textId); return true; } } } else if (_mapSpecialTiles[_techId][tileId]._field3 == 0xFD) { for (int counter = 0; counter < _teamSize; ++counter) { - if (_teamCharId[counter] == -1) + if (_teamChar[counter]._id == -1) continue; for (uint var2 = 0; var2 < 10; ++var2) { - if (_npcBuf[_teamCharId[counter]]._inventory[var2]._ref == _mapSpecialTiles[_techId][tileId]._triggerId) { + if (_npcBuf[_teamChar[counter]._id]._inventory[var2]._ref == _mapSpecialTiles[_techId][tileId]._triggerId) { displayImp1Text(_mapSpecialTiles[_techId][tileId]._field5_textId); return true; } @@ -2085,14 +2085,14 @@ bool EfhEngine::handleInteractionText(int16 mapPosX, int16 mapPosY, int16 charId } else if (_mapSpecialTiles[_techId][tileId]._field3 <= 0x77) { int16 scoreId = _mapSpecialTiles[_techId][tileId]._field3; for (int counter = 0; counter < _teamSize; ++counter) { - if (_teamCharId[counter] == -1) + if (_teamChar[counter]._id == -1) continue; for (uint var2 = 0; var2 < 39; ++var2) { // CHECKME : the whole loop doesn't make much sense as it's using scoreId instead of var2, plus _activeScore is an array of 15 bytes, not 0x77... // Also, 39 correspond to the size of activeScore + passiveScore + infoScore + the 2 remaining bytes of the struct warning("handleInteractionText - _activeScore[%d]", scoreId); - if (_npcBuf[_teamCharId[counter]]._activeScore[scoreId] >= _mapSpecialTiles[_techId][tileId]._triggerId) { + if (_npcBuf[_teamChar[counter]._id]._activeScore[scoreId] >= _mapSpecialTiles[_techId][tileId]._triggerId) { displayImp1Text(_mapSpecialTiles[_techId][tileId]._field5_textId); return true; } @@ -2170,9 +2170,9 @@ void EfhEngine::computeInitiatives() { debugC(6, kDebugEngine, "computeInitiatives"); for (int counter = 0; counter < 3; ++counter) { - if (counter < _teamSize && _teamCharId[counter] != -1) { + if (counter < _teamSize && _teamChar[counter]._id != -1) { _initiatives[counter]._id = counter + 1000; // Magic value added to detect it's a member of the team - _initiatives[counter]._initiative = _npcBuf[_teamCharId[counter]]._infoScore[3]; // "Agility" + _initiatives[counter]._initiative = _npcBuf[_teamChar[counter]._id]._infoScore[3]; // "Agility" } else { _initiatives[counter]._id = -1; _initiatives[counter]._initiative = -1; @@ -2406,7 +2406,7 @@ bool EfhEngine::checkMonsterCollision() { endLoop = true; break; case Common::KEYCODE_s: // Status - handleStatusMenu(1, _teamCharId[0]); + handleStatusMenu(1, _teamChar[0]._id); endLoop = true; _tempTextPtr = nullptr; drawGameScreenAndTempText(true); @@ -2483,13 +2483,13 @@ void EfhEngine::loadEfhGame() { _fullPlaceId = f.readUint16LE(); _guessAnimationAmount = f.readSint16LE(); _largeMapFlag = f.readUint16LE(); - _teamCharId[0] = f.readSint16LE(); - _teamCharId[1] = f.readSint16LE(); - _teamCharId[2] = f.readSint16LE(); + _teamChar[0]._id = f.readSint16LE(); + _teamChar[1]._id = f.readSint16LE(); + _teamChar[2]._id = f.readSint16LE(); for (int i = 0; i < 3; ++i) { - _teamCharStatus[i]._status = f.readSint16LE(); - _teamCharStatus[i]._duration = f.readSint16LE(); + _teamChar[i]._status._type = f.readSint16LE(); + _teamChar[i]._status._duration = f.readSint16LE(); } _teamSize = f.readSint16LE(); diff --git a/engines/efh/efh.h b/engines/efh/efh.h index c55d3f2b52a1..9b7676a8a7c2 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -203,7 +203,7 @@ struct BufferBM { }; struct CharStatus { - int16 _status; + int16 _type; int16 _duration; }; @@ -245,6 +245,16 @@ struct TileFactStruct { void init(); }; +struct TeamChar { + int16 _id; + CharStatus _status; + int16 _pctVisible; + int16 _pctDodgeMiss; + int16 _nextAttack; + int16 _lastInventoryUsed; + int16 _lastAction; +}; + class EfhEngine : public Engine { public: EfhEngine(OSystem *syst, const ADGameDescription *gd); @@ -606,13 +616,7 @@ class EfhEngine : public Engine { int16 _menuDepth; int16 _menuItemCounter; - int16 _teamCharId[3]; - CharStatus _teamCharStatus[3]; - int16 _teamPctVisible[3]; - int16 _teamPctDodgeMiss[3]; - int16 _teamNextAttack[3]; - int16 _teamLastInventoryUsed[3]; - int16 _teamLastAction[3]; + TeamChar _teamChar[3]; int16 _teamMonsterIdArray[5]; TeamMonsterEffect _teamMonsterEffects[5]; diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index 9df8db83cdc3..d5ebd27c0558 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -111,8 +111,8 @@ bool EfhEngine::handleFight(int16 monsterId) { displayAnimFrames(getTeamMonsterAnimId(), true); for (int counter = 0; counter < _teamSize; ++counter) { - _teamPctVisible[counter] = 100; - _teamPctDodgeMiss[counter] = 65; + _teamChar[counter]._pctVisible = 100; + _teamChar[counter]._pctDodgeMiss = 65; } if (!getTeamAttackRoundPlans()) { @@ -124,7 +124,7 @@ bool EfhEngine::handleFight(int16 monsterId) { } for (int counter = 0; counter < _teamSize; ++counter) { - if (_teamLastAction[counter] == 0x52) // 'R' + if (_teamChar[counter]._lastAction == 0x52) // 'R' mainLoopCond = true; } @@ -140,7 +140,7 @@ bool EfhEngine::handleFight(int16 monsterId) { if (!isTeamMemberStatusNormal(monsterGroupIdOrMonsterId)) { handleFight_checkEndEffect(monsterGroupIdOrMonsterId); } else { - switch (_teamLastAction[monsterGroupIdOrMonsterId]) { + switch (_teamChar[monsterGroupIdOrMonsterId]._lastAction) { case 0x41: // 'A'ttack handleFight_lastAction_A(monsterGroupIdOrMonsterId); break; @@ -177,21 +177,21 @@ void EfhEngine::handleFight_checkEndEffect(int16 charId) { // In the original, this function is part of handleFight. // It has been split for readability purposes. - if (_teamCharStatus[charId]._status == 0) + if (_teamChar[charId]._status._type == kEfhStatusNormal) return; - if (--_teamCharStatus[charId]._duration != 0) + if (--_teamChar[charId]._status._duration > 0) return; // At this point : The status is different to 0 (normal) and the effect duration is finally 0 (end of effect) - _enemyNamePt2 = _npcBuf[_teamCharId[charId]]._name; - _enemyNamePt1 = getArticle(_npcBuf[_teamCharId[charId]].getPronoun()); + _enemyNamePt2 = _npcBuf[_teamChar[charId]._id]._name; + _enemyNamePt1 = getArticle(_npcBuf[_teamChar[charId]._id].getPronoun()); // End of effect message depends on the type of effect - switch (_teamCharStatus[charId]._status) { - case 1: + switch (_teamChar[charId]._status._type) { + case kEfhStatusSleeping: _messageToBePrinted = Common::String::format("%s%s wakes up!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str()); break; - case 2: + case kEfhStatusFrozen: _messageToBePrinted = Common::String::format("%s%s thaws out!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str()); break; default: @@ -200,7 +200,7 @@ void EfhEngine::handleFight_checkEndEffect(int16 charId) { } // The character status is back to normal - _teamCharStatus[charId]._status = 0; + _teamChar[charId]._status._type = kEfhStatusNormal; // Finally, display the message displayBoxWithText(_messageToBePrinted, 1, 2, true); @@ -212,10 +212,10 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { // In the original, this function is part of handleFight. // It has been split for readability purposes. - int16 teamCharItemId = getEquippedExclusiveType(_teamCharId[teamCharId], 9, true); + int16 teamCharItemId = getEquippedExclusiveType(_teamChar[teamCharId]._id, 9, true); if (teamCharItemId == 0x7FFF) teamCharItemId = 0x3F; - int16 minMonsterGroupId = _teamNextAttack[teamCharId]; + int16 minMonsterGroupId = _teamChar[teamCharId]._nextAttack; if (minMonsterGroupId == 0x64) minMonsterGroupId = 0; @@ -259,15 +259,15 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { noticedFl = false; int16 randomDamageAbsorbed = getRandom(_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._maxDamageAbsorption); - int16 enemyPronoun = _npcBuf[_teamCharId[teamCharId]].getPronoun(); + int16 enemyPronoun = _npcBuf[_teamChar[teamCharId]._id].getPronoun(); int16 monsterId = _teamMonsterIdArray[groupId]; int16 characterPronoun = kEncounters[_mapMonsters[_techId][monsterId]._monsterRef]._nameArticle; - int16 charScore = getCharacterScore(_teamCharId[teamCharId], teamCharItemId); + int16 charScore = getCharacterScore(_teamChar[teamCharId]._id, teamCharItemId); int16 hitPointsBefore = _mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId]; int16 hitCount = 0; int16 originalDamage = 0; int16 damagePointsAbsorbed = 0; - int16 attackSpeed = _items[teamCharItemId]._attacks * _npcBuf[_teamCharId[teamCharId]]._speed; + int16 attackSpeed = _items[teamCharItemId]._attacks * _npcBuf[_teamChar[teamCharId]._id]._speed; // Action A - Loop attackCounter - Start for (int attackCounter = 0; attackCounter < attackSpeed; ++attackCounter) { @@ -309,7 +309,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { _characterNamePt2 = kEncounters[_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._monsterRef]._name; _enemyNamePt1 = getArticle(enemyPronoun); - _enemyNamePt2 = _npcBuf[_teamCharId[teamCharId]]._name; + _enemyNamePt2 = _npcBuf[_teamChar[teamCharId]._id]._name; _nameBuffer = _items[teamCharItemId]._name; if (checkSpecialItemsOnCurrentPlace(teamCharItemId)) { @@ -322,7 +322,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s for 1 point", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[verbId], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[enemyPronoun], _nameBuffer.c_str()); if (_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] <= 0) { getDeathTypeDescription(groupId, teamCharId + 1000); - getXPAndSearchCorpse(_teamCharId[teamCharId], _enemyNamePt1, _enemyNamePt2, _teamMonsterIdArray[groupId]); + getXPAndSearchCorpse(_teamChar[teamCharId]._id, _enemyNamePt1, _enemyNamePt2, _teamMonsterIdArray[groupId]); } else { _messageToBePrinted += "!"; } @@ -330,7 +330,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s for %d points", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[verbId], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[enemyPronoun], _nameBuffer.c_str(), hitPoints); if (_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] <= 0) { getDeathTypeDescription(groupId, teamCharId + 1000); - getXPAndSearchCorpse(_teamCharId[teamCharId], _enemyNamePt1, _enemyNamePt2, _teamMonsterIdArray[groupId]); + getXPAndSearchCorpse(_teamChar[teamCharId]._id, _enemyNamePt1, _enemyNamePt2, _teamMonsterIdArray[groupId]); } else { _messageToBePrinted += "!"; } @@ -372,7 +372,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { _messageToBePrinted += Common::String(" Your actions do not go un-noticed..."); // Action A - Check item durability - Start - int16 npcId = _teamCharId[teamCharId]; + int16 npcId = _teamChar[teamCharId]._id; // get equipped inventory slot with exclusiveType == 9 uint16 exclusiveInventoryId = getEquippedExclusiveType(npcId, 9, false); @@ -418,11 +418,11 @@ void EfhEngine::handleFight_lastAction_D(int16 teamCharId) { // It has been split for readability purposes. debugC(3, kDebugFight, "handleFight_lastAction_D %d", teamCharId); - _teamPctDodgeMiss[teamCharId] -= 40; + _teamChar[teamCharId]._pctDodgeMiss -= 40; - uint8 pronoun = _npcBuf[_teamCharId[teamCharId]].getPronoun(); + uint8 pronoun = _npcBuf[_teamChar[teamCharId]._id].getPronoun(); _enemyNamePt1 = getArticle(pronoun); - _enemyNamePt2 = _npcBuf[_teamCharId[teamCharId]]._name; + _enemyNamePt2 = _npcBuf[_teamChar[teamCharId]._id]._name; _messageToBePrinted = Common::String::format("%s%s prepares to defend %sself!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPersonal[pronoun]); displayBoxWithText(_messageToBePrinted, 1, 2, true); @@ -434,11 +434,11 @@ void EfhEngine::handleFight_lastAction_H(int16 teamCharId) { // It has been split for readability purposes. debugC(3, kDebugFight, "handleFight_lastAction_H %d", teamCharId); - _teamPctVisible[teamCharId] -= 50; + _teamChar[teamCharId]._pctVisible -= 50; - int16 pronoun = _npcBuf[_teamCharId[teamCharId]].getPronoun(); + int16 pronoun = _npcBuf[_teamChar[teamCharId]._id].getPronoun(); _enemyNamePt1 = getArticle(pronoun); - _enemyNamePt2 = _npcBuf[_teamCharId[teamCharId]]._name; + _enemyNamePt2 = _npcBuf[_teamChar[teamCharId]._id]._name; _messageToBePrinted = Common::String::format("%s%s attempts to hide %sself!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPersonal[pronoun]); displayBoxWithText(_messageToBePrinted, 1, 2, true); @@ -450,15 +450,15 @@ bool EfhEngine::handleFight_lastAction_U(int16 teamCharId) { // It has been split for readability purposes. debugC(3, kDebugFight, "handleFight_lastAction_U %d", teamCharId); - int16 itemId = _npcBuf[_teamCharId[teamCharId]]._inventory[_teamLastInventoryUsed[teamCharId]]._ref; + int16 itemId = _npcBuf[_teamChar[teamCharId]._id]._inventory[_teamChar[teamCharId]._lastInventoryUsed]._ref; _nameBuffer = _items[itemId]._name; - int16 pronoun = _npcBuf[_teamCharId[teamCharId]].getPronoun(); + int16 pronoun = _npcBuf[_teamChar[teamCharId]._id].getPronoun(); _enemyNamePt1 = getArticle(pronoun); - _enemyNamePt2 = _npcBuf[_teamCharId[teamCharId]]._name; + _enemyNamePt2 = _npcBuf[_teamChar[teamCharId]._id]._name; _messageToBePrinted = Common::String::format("%s%s uses %s %s! ", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kPossessive[pronoun], _nameBuffer.c_str()); - bool retVal = useObject(_teamCharId[teamCharId], _teamLastInventoryUsed[teamCharId], _teamNextAttack[teamCharId], teamCharId, 0, 3); + bool retVal = useObject(_teamChar[teamCharId]._id, _teamChar[teamCharId]._lastInventoryUsed, _teamChar[teamCharId]._nextAttack, teamCharId, 0, 3); displayBoxWithText(_messageToBePrinted, 1, 2, true); return retVal; @@ -480,7 +480,7 @@ void EfhEngine::handleFight_MobstersAttack(int groupId) { if (_items[monsterWeaponItemId]._range < 3) { for (uint attackTry = 0; attackTry < 10; ++attackTry) { minTeamMemberId = getRandom(_teamSize) - 1; - if (checkWeaponRange(_teamMonsterIdArray[groupId], monsterWeaponItemId) && isTeamMemberStatusNormal(minTeamMemberId) && getRandom(100) < _teamPctVisible[minTeamMemberId]) { + if (checkWeaponRange(_teamMonsterIdArray[groupId], monsterWeaponItemId) && isTeamMemberStatusNormal(minTeamMemberId) && getRandom(100) < _teamChar[minTeamMemberId]._pctVisible) { break; } minTeamMemberId = -1; @@ -496,15 +496,15 @@ void EfhEngine::handleFight_MobstersAttack(int groupId) { // handleFight - Loop on targetId - Start for (int16 targetId = minTeamMemberId; targetId < maxTeamMemberId; ++targetId) { - if (_teamCharId[targetId] == -1 || !isTeamMemberStatusNormal(targetId)) + if (_teamChar[targetId]._id == -1 || !isTeamMemberStatusNormal(targetId)) continue; - int16 randomDefense = getRandom(getEquipmentDefense(_teamCharId[targetId])); + int16 randomDefense = getRandom(getEquipmentDefense(_teamChar[targetId]._id)); int16 enemyPronoun = kEncounters[_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._monsterRef]._nameArticle; - int16 characterPronoun = _npcBuf[_teamCharId[targetId]].getPronoun(); + int16 characterPronoun = _npcBuf[_teamChar[targetId]._id].getPronoun(); - _teamPctDodgeMiss[targetId] += (_items[monsterWeaponItemId].field_13 * 5); + _teamChar[targetId]._pctDodgeMiss += (_items[monsterWeaponItemId].field_13 * 5); int16 hitCount = 0; int16 originalDamage = 0; int16 damagePointsAbsorbed = 0; @@ -512,12 +512,12 @@ void EfhEngine::handleFight_MobstersAttack(int groupId) { int16 var64 = _mapMonsters[_techId][_teamMonsterIdArray[groupId]]._npcId * _items[monsterWeaponItemId]._attacks; for (int var84 = 0; var84 < var64; ++var84) { // handleFight - Loop var84 on var64 (objectId) - Start - if (getRandom(100) > _teamPctDodgeMiss[targetId]) + if (getRandom(100) > _teamChar[targetId]._pctDodgeMiss) continue; ++hitCount; - if (hasAdequateDefenseNPC(_teamCharId[targetId], _items[monsterWeaponItemId]._attackType)) + if (hasAdequateDefenseNPC(_teamChar[targetId]._id, _items[monsterWeaponItemId]._attackType)) continue; int16 baseDamage = getRandom(_items[monsterWeaponItemId]._damage); @@ -540,7 +540,7 @@ void EfhEngine::handleFight_MobstersAttack(int groupId) { hitCount = 0; if (hitCount > 0) { - _npcBuf[_teamCharId[targetId]]._hitPoints -= originalDamage; + _npcBuf[_teamChar[targetId]._id]._hitPoints -= originalDamage; if (hitCount > 1) _attackBuffer = Common::String::format("%d times ", hitCount); else @@ -554,7 +554,7 @@ void EfhEngine::handleFight_MobstersAttack(int groupId) { _enemyNamePt2 = kEncounters[_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._monsterRef]._name; _characterNamePt1 = getArticle(characterPronoun); - _characterNamePt2 = _npcBuf[_teamCharId[targetId]]._name; + _characterNamePt2 = _npcBuf[_teamChar[targetId]._id]._name; _nameBuffer = _items[monsterWeaponItemId]._name; if (checkSpecialItemsOnCurrentPlace(monsterWeaponItemId)) { @@ -565,13 +565,13 @@ void EfhEngine::handleFight_MobstersAttack(int groupId) { _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s, but does no damage!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[enemyPronoun], _nameBuffer.c_str()); } else if (hitPoints == 1) { _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s for 1 point", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[enemyPronoun], _nameBuffer.c_str()); - if (_npcBuf[_teamCharId[targetId]]._hitPoints <= 0) + if (_npcBuf[_teamChar[targetId]._id]._hitPoints <= 0) getDeathTypeDescription(targetId + 1000, groupId); else _messageToBePrinted += "!"; } else { _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s for %d points", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[var68 * 3 + var6A], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[enemyPronoun], _nameBuffer.c_str(), hitPoints); - if (_npcBuf[_teamCharId[targetId]]._hitPoints <= 0) + if (_npcBuf[_teamChar[targetId]._id]._hitPoints <= 0) getDeathTypeDescription(targetId + 1000, groupId); else _messageToBePrinted += "!"; @@ -579,19 +579,19 @@ void EfhEngine::handleFight_MobstersAttack(int groupId) { // handleFight - check damages - End // handleFight - Add reaction text - start - if (hitCount != 0 && originalDamage > 0 && getRandom(100) <= 35 && _npcBuf[_teamCharId[targetId]]._hitPoints > 0) { - if (_npcBuf[_teamCharId[targetId]]._hitPoints - 5 <= originalDamage) { + if (hitCount != 0 && originalDamage > 0 && getRandom(100) <= 35 && _npcBuf[_teamChar[targetId]._id]._hitPoints > 0) { + if (_npcBuf[_teamChar[targetId]._id]._hitPoints - 5 <= originalDamage) { addReactionText(kEfhReactionReels); - } else if (_npcBuf[_teamCharId[targetId]]._hitPoints < _npcBuf[_teamCharId[targetId]]._maxHP / 8) { + } else if (_npcBuf[_teamChar[targetId]._id]._hitPoints < _npcBuf[_teamChar[targetId]._id]._maxHP / 8) { addReactionText(kEfhReactionCriesOut); - } else if (_npcBuf[_teamCharId[targetId]]._hitPoints < _npcBuf[_teamCharId[targetId]]._maxHP / 4) { + } else if (_npcBuf[_teamChar[targetId]._id]._hitPoints < _npcBuf[_teamChar[targetId]._id]._maxHP / 4) { addReactionText(kEfhReactionFalters); - } else if (_npcBuf[_teamCharId[targetId]]._hitPoints < _npcBuf[_teamCharId[targetId]]._maxHP / 2) { + } else if (_npcBuf[_teamChar[targetId]._id]._hitPoints < _npcBuf[_teamChar[targetId]._id]._maxHP / 2) { addReactionText(kEfhReactionWinces); - } else if (_npcBuf[_teamCharId[targetId]]._hitPoints < _npcBuf[_teamCharId[targetId]]._maxHP / 3) { + } else if (_npcBuf[_teamChar[targetId]._id]._hitPoints < _npcBuf[_teamChar[targetId]._id]._maxHP / 3) { // CHECKME: Doesn't make any sense to check /3 after /2... I don't get it. Looks like an original bug addReactionText(kEfhReactionScreams); - } else if (_npcBuf[_teamCharId[targetId]]._maxHP / 8 >= originalDamage) { + } else if (_npcBuf[_teamChar[targetId]._id]._maxHP / 8 >= originalDamage) { addReactionText(kEfhReactionChortles); } else if (originalDamage == 0 && getRandom(100) < 35) { // CHECKME: "originalDamage == 0" is always false as it's checked beforehand. Looks like another original bug @@ -601,14 +601,14 @@ void EfhEngine::handleFight_MobstersAttack(int groupId) { // handleFight - Add reaction text - end // handleFight - Check armor - start - if (randomDefense != 0 && hitCount != 0 && _npcBuf[_teamCharId[targetId]]._hitPoints > 0) { + if (randomDefense != 0 && hitCount != 0 && _npcBuf[_teamChar[targetId]._id]._hitPoints > 0) { if (damagePointsAbsorbed <= 1) _messageToBePrinted += Common::String::format(" %s%s's armor absorbs 1 point!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); else _messageToBePrinted += Common::String::format(" %s%s's armor absorbs %d points!", _characterNamePt1.c_str(), _characterNamePt2.c_str(), damagePointsAbsorbed); int armorDamage = (originalDamage + damagePointsAbsorbed) / 10; - handleDamageOnArmor(_teamCharId[targetId], armorDamage); + handleDamageOnArmor(_teamChar[targetId]._id, armorDamage); } // handleFight - Check armor - end @@ -616,15 +616,15 @@ void EfhEngine::handleFight_MobstersAttack(int groupId) { switch (_items[monsterWeaponItemId]._specialEffect) { case 1: if (getRandom(100) < 20) { - _teamCharStatus[targetId]._status = 1; - _teamCharStatus[targetId]._duration = getRandom(10); + _teamChar[targetId]._status._type = kEfhStatusSleeping; + _teamChar[targetId]._status._duration = getRandom(10); _messageToBePrinted += Common::String::format(" %s%s falls asleep!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); } break; case 2: if (getRandom(100) < 20) { - _teamCharStatus[targetId]._status = 2; - _teamCharStatus[targetId]._duration = getRandom(10); + _teamChar[targetId]._status._type = kEfhStatusFrozen; + _teamChar[targetId]._status._duration = getRandom(10); _messageToBePrinted += Common::String::format(" %s%s is frozen!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); } break; @@ -632,7 +632,7 @@ void EfhEngine::handleFight_MobstersAttack(int groupId) { case 6: if (getRandom(100) < 20) { _messageToBePrinted += Common::String::format(" %s%s's life energy is gone!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); - _npcBuf[_teamCharId[targetId]]._hitPoints = 0; + _npcBuf[_teamChar[targetId]._id]._hitPoints = 0; } break; default: @@ -676,7 +676,7 @@ bool EfhEngine::isTPK() { int16 zeroedChar = 0; for (int counter = 0; counter < _teamSize; ++counter) { - if (_npcBuf[_teamCharId[counter]]._hitPoints <= 0) + if (_npcBuf[_teamChar[counter]._id]._hitPoints <= 0) ++zeroedChar; } @@ -714,7 +714,7 @@ void EfhEngine::resetTeamMonsterIdArray() { bool EfhEngine::isTeamMemberStatusNormal(int16 teamMemberId) { debugC(6, kDebugFight, "isTeamMemberStatusNormal %d", teamMemberId); - if (_npcBuf[_teamCharId[teamMemberId]]._hitPoints > 0 && _teamCharStatus[teamMemberId]._status == 0) + if (_npcBuf[_teamChar[teamMemberId]._id]._hitPoints > 0 && _teamChar[teamMemberId]._status._type == kEfhStatusNormal) return true; return false; @@ -726,7 +726,7 @@ void EfhEngine::getDeathTypeDescription(int16 victimId, int16 attackerId) { uint8 pronoun; if (victimId >= 1000) { // Magic value for team members - int16 charId = _teamCharId[victimId - 1000]; + int16 charId = _teamChar[victimId - 1000]._id; pronoun = _npcBuf[charId].getPronoun(); } else { int16 charId = _teamMonsterIdArray[victimId]; @@ -740,7 +740,7 @@ void EfhEngine::getDeathTypeDescription(int16 victimId, int16 attackerId) { if (getRandom(100) < 20) { deathType = 0; } else if (attackerId >= 1000) { - int16 charId = _teamCharId[attackerId - 1000]; + int16 charId = _teamChar[attackerId - 1000]._id; if (charId == -1) deathType = 0; else { @@ -1031,41 +1031,41 @@ bool EfhEngine::getTeamAttackRoundPlans() { bool retVal = false; for (int charId = 0; charId < _teamSize; ++charId) { - _teamLastAction[charId] = 0; + _teamChar[charId]._lastAction = 0; if (!isTeamMemberStatusNormal(charId)) continue; retVal = true; do { - drawCombatScreen(_teamCharId[charId], false, true); + drawCombatScreen(_teamChar[charId]._id, false, true); switch (handleAndMapInput(true)) { case Common::KEYCODE_a: // Attack - _teamLastAction[charId] = 'A'; - _teamNextAttack[charId] = determineTeamTarget(_teamCharId[charId], 9, true); - if (_teamNextAttack[charId] == -1) - _teamLastAction[charId] = 0; + _teamChar[charId]._lastAction = 'A'; + _teamChar[charId]._nextAttack = determineTeamTarget(_teamChar[charId]._id, 9, true); + if (_teamChar[charId]._nextAttack == -1) + _teamChar[charId]._lastAction = 0; break; case Common::KEYCODE_d: // Defend - _teamLastAction[charId] = 'D'; + _teamChar[charId]._lastAction = 'D'; break; case Common::KEYCODE_h: // Hide - _teamLastAction[charId] = 'H'; + _teamChar[charId]._lastAction = 'H'; break; case Common::KEYCODE_r: // Run for (int counter2 = 0; counter2 < _teamSize; ++counter2) { - _teamLastAction[counter2] = 'R'; + _teamChar[counter2]._lastAction = 'R'; } return true; case Common::KEYCODE_s: { // Status - int16 lastInvId = handleStatusMenu(2, _teamCharId[charId]); - redrawCombatScreenWithTempText(_teamCharId[charId]); + int16 lastInvId = handleStatusMenu(2, _teamChar[charId]._id); + redrawCombatScreenWithTempText(_teamChar[charId]._id); if (lastInvId >= 999) { if (lastInvId == 0x7D00) // Result of Equip, Give and Drop in combat mode(2) - _teamLastAction[charId] = 'S'; + _teamChar[charId]._lastAction = 'S'; } else { - _teamLastAction[charId] = 'U'; - _teamLastInventoryUsed[charId] = lastInvId; - int16 invEffect = _items[_npcBuf[_teamCharId[charId]]._inventory[lastInvId]._ref]._specialEffect; + _teamChar[charId]._lastAction = 'U'; + _teamChar[charId]._lastInventoryUsed = lastInvId; + int16 invEffect = _items[_npcBuf[_teamChar[charId]._id]._inventory[lastInvId]._ref]._specialEffect; switch (invEffect - 1) { case 0: case 1: @@ -1079,7 +1079,7 @@ bool EfhEngine::getTeamAttackRoundPlans() { case 10: case 12: case 13: - _teamNextAttack[charId] = determineTeamTarget(_teamCharId[charId], 9, false); + _teamChar[charId]._nextAttack = determineTeamTarget(_teamChar[charId]._id, 9, false); break; case 9: @@ -1094,13 +1094,13 @@ bool EfhEngine::getTeamAttackRoundPlans() { case 29: case 30: displayBoxWithText("Select Character:", 3, 1, false); - _teamNextAttack[charId] = selectOtherCharFromTeam(); + _teamChar[charId]._nextAttack = selectOtherCharFromTeam(); break; case 16: case 17: case 26: - _teamNextAttack[charId] = 0xC8; + _teamChar[charId]._nextAttack = 0xC8; break; case 19: @@ -1109,8 +1109,8 @@ bool EfhEngine::getTeamAttackRoundPlans() { case 22: case 23: default: - _teamLastInventoryUsed[charId] = lastInvId; - _teamNextAttack[charId] = -1; + _teamChar[charId]._lastInventoryUsed = lastInvId; + _teamChar[charId]._nextAttack = -1; break; } } @@ -1119,12 +1119,12 @@ bool EfhEngine::getTeamAttackRoundPlans() { case Common::KEYCODE_t: // Terrain redrawScreenForced(); getInputBlocking(); - drawCombatScreen(_teamCharId[charId], false, true); + drawCombatScreen(_teamChar[charId]._id, false, true); break; default: break; } - } while (_teamLastAction[charId] == 0); + } while (_teamChar[charId]._lastAction == 0); } return retVal; diff --git a/engines/efh/init.cpp b/engines/efh/init.cpp index 3caf788835b4..59b2ff80cfc4 100644 --- a/engines/efh/init.cpp +++ b/engines/efh/init.cpp @@ -304,17 +304,17 @@ EfhEngine::EfhEngine(OSystem *syst, const ADGameDescription *gd) : Engine(syst), _guessAnimationAmount = 9; _largeMapFlag = 0xFFFF; _alertDelay = 0; - _teamCharId[0] = 0; - _teamCharId[1] = _teamCharId[2] = -1; + _teamChar[0]._id = 0; + _teamChar[1]._id = _teamChar[2]._id = -1; for (int i = 0; i < 3; ++i) { - _teamCharStatus[i]._status = 0; - _teamCharStatus[i]._duration = 0; - _teamPctVisible[i] = 0; - _teamPctDodgeMiss[i] = 0; - _teamNextAttack[i] = -1; - _teamLastInventoryUsed[i] = 0; - _teamLastAction[i] = 0; + _teamChar[i]._status._type = kEfhStatusNormal; + _teamChar[i]._status._duration = 0; + _teamChar[i]._pctVisible = 0; + _teamChar[i]._pctDodgeMiss = 0; + _teamChar[i]._nextAttack = -1; + _teamChar[i]._lastInventoryUsed = 0; + _teamChar[i]._lastAction = 0; } for (int i = 0; i < 5; ++i) { diff --git a/engines/efh/menu.cpp b/engines/efh/menu.cpp index 38a570a51db2..79722cbcb14d 100644 --- a/engines/efh/menu.cpp +++ b/engines/efh/menu.cpp @@ -745,23 +745,23 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) { bool givenFl; int16 destCharId; do { - if (_teamCharId[2] != -1) { + if (_teamChar[2]._id != -1) { displayStringInSmallWindowWithBorder("Who will you give the item to?", false, charId, windowId, menuId, curMenuLine); destCharId = selectOtherCharFromTeam(); var2 = false; - } else if (_teamCharId[1] == -1) { + } else if (_teamChar[1]._id == -1) { destCharId = 0x1A; var2 = false; } else { var2 = true; - if (_teamCharId[0] == charId) + if (_teamChar[0]._id == charId) destCharId = 1; else destCharId = 0; } if (destCharId != 0x1A && destCharId != 0x1B) { - givenFl = giveItemTo(_teamCharId[destCharId], objectId, charId); + givenFl = giveItemTo(_teamChar[destCharId]._id, objectId, charId); if (!givenFl) { displayStringInSmallWindowWithBorder("That character cannot carry anymore!", false, charId, windowId, menuId, curMenuLine); getLastCharAfterAnimCount(_guessAnimationAmount); @@ -1058,9 +1058,9 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in } else { _messageToBePrinted += buffer1; } - _teamPctDodgeMiss[teamCharId] -= 50; - if (_teamPctDodgeMiss[teamCharId] < 0) - _teamPctDodgeMiss[teamCharId] = 0; + _teamChar[teamCharId]._pctDodgeMiss -= 50; + if (_teamChar[teamCharId]._pctDodgeMiss < 0) + _teamChar[teamCharId]._pctDodgeMiss = 0; } objectUsedFl = true; @@ -1082,9 +1082,9 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in _messageToBePrinted += buffer1; } - _teamPctVisible[teamCharId] -= 50; - if (_teamPctVisible[teamCharId] < 0) - _teamPctVisible[teamCharId] = 0; + _teamChar[teamCharId]._pctVisible -= 50; + if (_teamChar[teamCharId]._pctVisible < 0) + _teamChar[teamCharId]._pctVisible = 0; } objectUsedFl = true; @@ -1166,10 +1166,10 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in } else { int16 teamCharId = teamMonsterId; if (teamCharId != 0x1B) { - if (_teamCharStatus[teamCharId]._status == 2) { // frozen + if (_teamChar[teamCharId]._status._type == kEfhStatusFrozen) { // frozen _messageToBePrinted += " The item makes a loud noise, awakening the character!"; - _teamCharStatus[teamCharId]._status = 0; - _teamCharStatus[teamCharId]._duration = 0; + _teamChar[teamCharId]._status._type = kEfhStatusNormal; + _teamChar[teamCharId]._status._duration = 0; } else { _messageToBePrinted += " The item makes a loud noise, but has no effect!"; } @@ -1236,9 +1236,9 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in if (teamCharId != 0x1B) { uint8 varAE = _items[itemId]._field17_attackTypeDefense; uint8 effectPoints = getRandom(_items[itemId]._field19_mapPosX_or_maxDeltaPoints); - _npcBuf[_teamCharId[teamCharId]]._activeScore[varAE] += effectPoints; - if (_npcBuf[_teamCharId[teamCharId]]._activeScore[varAE] > 20) { - _npcBuf[_teamCharId[teamCharId]]._activeScore[varAE] = 20; + _npcBuf[_teamChar[teamCharId]._id]._activeScore[varAE] += effectPoints; + if (_npcBuf[_teamChar[teamCharId]._id]._activeScore[varAE] > 20) { + _npcBuf[_teamChar[teamCharId]._id]._activeScore[varAE] = 20; } if (effectPoints > 1) buffer1 = Common::String::format("%s increased %d points!", kSkillArray[varAE], effectPoints); @@ -1266,9 +1266,9 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in if (teamCharId != 0x1B) { uint8 varAE = _items[itemId]._field17_attackTypeDefense; uint8 effectPoints = getRandom(_items[itemId]._field19_mapPosX_or_maxDeltaPoints); - _npcBuf[_teamCharId[teamCharId]]._activeScore[varAE] -= effectPoints; - if (_npcBuf[_teamCharId[teamCharId]]._activeScore[varAE] > 20 || _npcBuf[_teamCharId[teamCharId]]._activeScore[varAE] < 0) { - _npcBuf[_teamCharId[teamCharId]]._activeScore[varAE] = 1; + _npcBuf[_teamChar[teamCharId]._id]._activeScore[varAE] -= effectPoints; + if (_npcBuf[_teamChar[teamCharId]._id]._activeScore[varAE] > 20 || _npcBuf[_teamChar[teamCharId]._id]._activeScore[varAE] < 0) { + _npcBuf[_teamChar[teamCharId]._id]._activeScore[varAE] = 1; } if (effectPoints > 1) buffer1 = Common::String::format("%s lowered %d points!", kSkillArray[varAE], effectPoints); @@ -1306,8 +1306,8 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in } if (teamCharId != 0x1B) { - _npcBuf[_teamCharId[teamCharId]]._hitPoints = 0; - buffer1 = Common::String::format("%s collapses, dead!!!", _npcBuf[_teamCharId[teamCharId]]._name); + _npcBuf[_teamChar[teamCharId]._id]._hitPoints = 0; + buffer1 = Common::String::format("%s collapses, dead!!!", _npcBuf[_teamChar[teamCharId]._id]._name); if (gameMode == 2) { displayStringInSmallWindowWithBorder(buffer1, false, charId, teamMonsterId, menuId, curMenuLine); } else { @@ -1324,10 +1324,10 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in } else { int16 teamCharId = teamMonsterId; if (teamCharId != 0x1B) { - if (_teamCharStatus[teamCharId]._status == 0) { + if (_teamChar[teamCharId]._status._type == kEfhStatusNormal) { // BUG (likely) _messageToBePrinted += " The item makes a loud noise, awakening the character!"; - _teamCharStatus[teamCharId]._status = 0; - _teamCharStatus[teamCharId]._duration = 0; + _teamChar[teamCharId]._status._type = kEfhStatusNormal; + _teamChar[teamCharId]._status._duration = 0; } else { _messageToBePrinted += " The item makes a loud noise, but has no effect!"; } @@ -1347,14 +1347,14 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in if (teamCharId != 0x1B) { int16 effectPoints = getRandom(_items[itemId]._field17_attackTypeDefense); - _npcBuf[_teamCharId[teamCharId]]._hitPoints += effectPoints; - if (_npcBuf[_teamCharId[teamCharId]]._hitPoints > _npcBuf[_teamCharId[teamCharId]]._maxHP) - _npcBuf[_teamCharId[teamCharId]]._hitPoints = _npcBuf[_teamCharId[teamCharId]]._maxHP; + _npcBuf[_teamChar[teamCharId]._id]._hitPoints += effectPoints; + if (_npcBuf[_teamChar[teamCharId]._id]._hitPoints > _npcBuf[_teamChar[teamCharId]._id]._maxHP) + _npcBuf[_teamChar[teamCharId]._id]._hitPoints = _npcBuf[_teamChar[teamCharId]._id]._maxHP; if (effectPoints > 1) - buffer1 = Common::String::format("%s is healed %d points!", _npcBuf[_teamCharId[teamCharId]]._name, effectPoints); + buffer1 = Common::String::format("%s is healed %d points!", _npcBuf[_teamChar[teamCharId]._id]._name, effectPoints); else - buffer1 = Common::String::format("%s is healed 1 point!", _npcBuf[_teamCharId[teamCharId]]._name); + buffer1 = Common::String::format("%s is healed 1 point!", _npcBuf[_teamChar[teamCharId]._id]._name); } if (gameMode == 2) { @@ -1377,14 +1377,14 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in if (teamCharId != 0x1B) { int16 effectPoints = getRandom(_items[itemId]._field17_attackTypeDefense); - _npcBuf[_teamCharId[teamCharId]]._hitPoints -= effectPoints; - if (_npcBuf[_teamCharId[teamCharId]]._hitPoints < 0) - _npcBuf[_teamCharId[teamCharId]]._hitPoints = 0; + _npcBuf[_teamChar[teamCharId]._id]._hitPoints -= effectPoints; + if (_npcBuf[_teamChar[teamCharId]._id]._hitPoints < 0) + _npcBuf[_teamChar[teamCharId]._id]._hitPoints = 0; if (effectPoints > 1) - buffer1 = Common::String::format("%s is harmed for %d points!", _npcBuf[_teamCharId[teamCharId]]._name, effectPoints); + buffer1 = Common::String::format("%s is harmed for %d points!", _npcBuf[_teamChar[teamCharId]._id]._name, effectPoints); else - buffer1 = Common::String::format("%s is harmed for 1 point!", _npcBuf[_teamCharId[teamCharId]]._name); + buffer1 = Common::String::format("%s is harmed for 1 point!", _npcBuf[_teamChar[teamCharId]._id]._name); } if (gameMode == 2) { diff --git a/engines/efh/savegames.cpp b/engines/efh/savegames.cpp index 46fb5b5c681c..b0045e64a8bb 100644 --- a/engines/efh/savegames.cpp +++ b/engines/efh/savegames.cpp @@ -128,13 +128,13 @@ void EfhEngine::synchronize(Common::Serializer &s) { s.syncAsUint16LE(_fullPlaceId); s.syncAsSint16LE(_guessAnimationAmount); s.syncAsUint16LE(_largeMapFlag); - s.syncAsSint16LE(_teamCharId[0]); - s.syncAsSint16LE(_teamCharId[1]); - s.syncAsSint16LE(_teamCharId[2]); + s.syncAsSint16LE(_teamChar[0]._id); + s.syncAsSint16LE(_teamChar[1]._id); + s.syncAsSint16LE(_teamChar[2]._id); for (int i = 0; i < 3; ++i) { - s.syncAsSint16LE(_teamCharStatus[i]._status); - s.syncAsSint16LE(_teamCharStatus[i]._duration); + s.syncAsSint16LE(_teamChar[i]._status._type); + s.syncAsSint16LE(_teamChar[i]._status._duration); } s.syncAsSint16LE(_teamSize); diff --git a/engines/efh/script.cpp b/engines/efh/script.cpp index 164050d4b947..02710da2989b 100644 --- a/engines/efh/script.cpp +++ b/engines/efh/script.cpp @@ -184,7 +184,7 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos case 0x05: buffer = script_readNumberArray(buffer, 4, scriptNumberArray); if (scriptExecuteFlag) { - int16 npcId = _teamCharId[scriptNumberArray[0]]; + int16 npcId = _teamChar[scriptNumberArray[0]]._id; if (npcId != -1) { int16 scoreId = scriptNumberArray[1]; _npcBuf[npcId]._activeScore[scoreId] += scriptNumberArray[2] & 0xFF; @@ -195,7 +195,7 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos case 0x06: buffer = script_readNumberArray(buffer, 2, scriptNumberArray); if (scriptExecuteFlag) { - int16 npcId = _teamCharId[scriptNumberArray[0]]; + int16 npcId = _teamChar[scriptNumberArray[0]]._id; if (npcId != -1) { int16 scoreId = scriptNumberArray[1]; _npcBuf[npcId]._activeScore[scoreId] = scriptNumberArray[2] & 0xFF; @@ -210,13 +210,13 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos case 0x08: buffer = script_readNumberArray(buffer, 1, scriptNumberArray); if (scriptExecuteFlag && scriptNumberArray[0] != -1) { - _npcBuf[_teamCharId[scriptNumberArray[0]]]._hitPoints = 0; + _npcBuf[_teamChar[scriptNumberArray[0]]._id]._hitPoints = 0; } break; case 0x09: buffer = script_readNumberArray(buffer, 2, scriptNumberArray); if (scriptExecuteFlag) { - int16 npcId = _teamCharId[scriptNumberArray[0]]; + int16 npcId = _teamChar[scriptNumberArray[0]]._id; if (npcId != -1) { _npcBuf[npcId]._hitPoints += getRandom(scriptNumberArray[1]); if (_npcBuf[npcId]._hitPoints > _npcBuf[npcId]._maxHP) @@ -227,7 +227,7 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos case 0x0A: buffer = script_readNumberArray(buffer, 1, scriptNumberArray); if (scriptExecuteFlag) { - int16 npcId = _teamCharId[scriptNumberArray[0]]; + int16 npcId = _teamChar[scriptNumberArray[0]]._id; if (npcId != -1) { _npcBuf[npcId]._hitPoints = _npcBuf[npcId]._maxHP; } @@ -236,7 +236,7 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos case 0x0B: buffer = script_readNumberArray(buffer, 2, scriptNumberArray); if (scriptExecuteFlag) { - int16 npcId = _teamCharId[scriptNumberArray[0]]; + int16 npcId = _teamChar[scriptNumberArray[0]]._id; if (npcId != -1) { _npcBuf[npcId]._hitPoints -= getRandom(scriptNumberArray[1]); if (_npcBuf[npcId]._hitPoints < 0) @@ -251,8 +251,8 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos bool found = false; for (int counter = 0; counter < _teamSize && !found; ++counter) { for (uint objectId = 0; objectId < 10; ++objectId) { - if (_npcBuf[_teamCharId[counter]]._inventory[objectId]._ref == scriptItemId) { - removeObject(_teamCharId[counter], objectId); + if (_npcBuf[_teamChar[counter]._id]._inventory[objectId]._ref == scriptItemId) { + removeObject(_teamChar[counter]._id, objectId); found = true; break; } @@ -266,7 +266,7 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos if (scriptExecuteFlag) { int16 scriptObjectId = scriptNumberArray[0]; for (int counter = 0; counter < _teamSize; ++counter) { - if (giveItemTo(_teamCharId[counter], scriptObjectId, 0xFF)) + if (giveItemTo(_teamChar[counter]._id, scriptObjectId, 0xFF)) break; } } @@ -278,7 +278,7 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos bool found = false; for (int counter = 0; counter < _teamSize && !found; ++counter) { for (uint objectId = 0; objectId < 10; ++objectId) { - if (_npcBuf[_teamCharId[counter]]._inventory[objectId]._ref == scriptItemId) { + if (_npcBuf[_teamChar[counter]._id]._inventory[objectId]._ref == scriptItemId) { found = true; break; } @@ -354,7 +354,7 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos // TODO: This "if" is useless, it's doing just the same loop and if statement. Consider removing it. if (isNpcATeamMember(scriptNpcId)) { for (uint counter = 0; counter < 3; ++counter) { - if (_teamCharId[counter] == scriptNpcId) { + if (_teamChar[counter]._id == scriptNpcId) { removeCharacterFromTeam(counter); break; } @@ -376,7 +376,7 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos int16 scriptRandomItemId = getRandom(scriptNumberArray[1] - scriptNumberArray[0] + 1) + scriptNumberArray[0] - 1; int16 counter; for (counter = 0; counter < _teamSize; ++counter) { - if (giveItemTo(_teamCharId[counter], scriptRandomItemId, 0xFF)) { + if (giveItemTo(_teamChar[counter]._id, scriptRandomItemId, 0xFF)) { found = true; break; } @@ -389,7 +389,7 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos scriptRandomItemId = displayBoxWithText("Nothing...", 1, 2, true); displayFctFullScreen(); } else { - _enemyNamePt2 = _npcBuf[_teamCharId[counter]]._name; + _enemyNamePt2 = _npcBuf[_teamChar[counter]._id]._name; _nameBuffer = _items[scriptRandomItemId]._name; curLine = Common::String::format("%s finds a %s!", _enemyNamePt2.c_str(), _nameBuffer.c_str()); drawMapWindow(); @@ -484,7 +484,7 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos displayLowStatusScreen(true); int16 teamSlot = handleCharacterJoining(); if (teamSlot > -1) { - _teamCharId[teamSlot] = joiningNpcId; + _teamChar[teamSlot]._id = joiningNpcId; } refreshTeamSize(); } From 41e39d27cf75b575118137e5ef48b50c268dde9a Mon Sep 17 00:00:00 2001 From: Strangerke Date: Thu, 2 Feb 2023 14:09:16 +0100 Subject: [PATCH 285/412] EFH: Fix bug when using bugle --- engines/efh/menu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engines/efh/menu.cpp b/engines/efh/menu.cpp index 79722cbcb14d..3e9d586d2795 100644 --- a/engines/efh/menu.cpp +++ b/engines/efh/menu.cpp @@ -1324,7 +1324,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in } else { int16 teamCharId = teamMonsterId; if (teamCharId != 0x1B) { - if (_teamChar[teamCharId]._status._type == kEfhStatusNormal) { // BUG (likely) + if (_teamChar[teamCharId]._status._type == kEfhStatusSleeping) { _messageToBePrinted += " The item makes a loud noise, awakening the character!"; _teamChar[teamCharId]._status._type = kEfhStatusNormal; _teamChar[teamCharId]._status._duration = 0; From fdd742bfbfba09001247242524a64b79a77e1bf8 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Thu, 2 Feb 2023 22:47:20 +0100 Subject: [PATCH 286/412] EFH: refactor TeamMonster --- engines/efh/efh.cpp | 12 ++-- engines/efh/efh.h | 18 +++-- engines/efh/fight.cpp | 150 +++++++++++++++++++++--------------------- engines/efh/init.cpp | 10 +-- engines/efh/menu.cpp | 32 ++++----- 5 files changed, 110 insertions(+), 112 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 942f657378bf..de0cdc44673c 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -1494,7 +1494,7 @@ bool EfhEngine::checkWeaponRange(int16 monsterId, int16 weaponId) { bool EfhEngine::checkMonsterMovementType(int16 id, bool teamFlag) { debugC(6, kDebugEngine, "checkMonsterMovementType %d %s", id, teamFlag ? "True" : "False"); - int16 monsterId = teamFlag ? _teamMonsterIdArray[id] : id; + int16 monsterId = teamFlag ? _teamMonster[id]._id : id; MapMonster *curMapMonst = &_mapMonsters[_techId][monsterId]; if ((curMapMonst->_additionalInfo & 0xF) >= 8) // Check hostility @@ -1513,7 +1513,7 @@ bool EfhEngine::checkTeamWeaponRange(int16 monsterId) { return true; for (uint counter = 0; counter < 5; ++counter) { - if (_teamMonsterIdArray[counter] == monsterId && checkMonsterMovementType(monsterId, false) && checkWeaponRange(monsterId, _mapMonsters[_techId][monsterId]._weaponItemId)) + if (_teamMonster[counter]._id == monsterId && checkMonsterMovementType(monsterId, false) && checkWeaponRange(monsterId, _mapMonsters[_techId][monsterId]._weaponItemId)) return false; } @@ -2180,12 +2180,12 @@ void EfhEngine::computeInitiatives() { } for (int counter = 0; counter < 5; ++counter) { - if (_teamMonsterIdArray[counter] == -1) { + if (_teamMonster[counter]._id == -1) { _initiatives[counter + 3]._id = -1; _initiatives[counter + 3]._initiative = -1; } else { _initiatives[counter + 3]._id = counter; - _initiatives[counter + 3]._initiative = _mapMonsters[_techId][_teamMonsterIdArray[counter]]._npcId + getRandom(20); + _initiatives[counter + 3]._initiative = _mapMonsters[_techId][_teamMonster[counter]._id]._npcId + getRandom(20); } } @@ -2261,7 +2261,7 @@ bool EfhEngine::hasObjectEquipped(int16 charId, int16 objectId) { void EfhEngine::setMapMonsterAggressivenessAndMovementType(int16 id, uint8 mask) { debugC(2, kDebugEngine, "setMapMonsterAggressivenessAndMovementType %d 0x%X", id, mask); - int16 monsterId = _teamMonsterIdArray[id]; + int16 monsterId = _teamMonster[id]._id; MapMonster *curMapMonst = &_mapMonsters[_techId][monsterId]; mask &= 0x0F; @@ -2272,7 +2272,7 @@ void EfhEngine::setMapMonsterAggressivenessAndMovementType(int16 id, uint8 mask) bool EfhEngine::isMonsterActive(int16 groupId, int16 id) { debugC(5, kDebugEngine, "isMonsterActive %d %d", groupId, id); - if (_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[id] > 0 && _teamMonsterEffects[groupId]._effect[id] == 0) + if (_mapMonsters[_techId][_teamMonster[groupId]._id]._hitPoints[id] > 0 && _teamMonster[groupId]._mobsterStatus[id]._type == kEfhStatusNormal) return true; return false; } diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 9b7676a8a7c2..f402f5d5247c 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -224,13 +224,6 @@ struct MapMonster { uint8 getPronoun(); }; -struct TeamMonsterEffect { - int16 _effect[9]; - int16 _duration[9]; - - void init(); -}; - struct InitiativeStruct { int16 _id; int16 _initiative; @@ -255,6 +248,13 @@ struct TeamChar { int16 _lastAction; }; +struct TeamMonster { + int16 _id; + CharStatus _mobsterStatus[9]; + + void init(); +}; + class EfhEngine : public Engine { public: EfhEngine(OSystem *syst, const ADGameDescription *gd); @@ -617,9 +617,7 @@ class EfhEngine : public Engine { int16 _menuItemCounter; TeamChar _teamChar[3]; - - int16 _teamMonsterIdArray[5]; - TeamMonsterEffect _teamMonsterEffects[5]; + TeamMonster _teamMonster[5]; InitiativeStruct _initiatives[8]; diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index d5ebd27c0558..d53e2cb6f812 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -29,7 +29,7 @@ void EfhEngine::createOpponentList(int16 monsterTeamId) { int16 counter = 0; if (monsterTeamId != -1 && countAliveMonsters(monsterTeamId) > 0) { counter = 1; - _teamMonsterIdArray[0] = monsterTeamId; + _teamMonster[0]._id = monsterTeamId; } for (int counter2 = 1; counter2 <= 3; ++counter2) { @@ -57,7 +57,7 @@ void EfhEngine::createOpponentList(int16 monsterTeamId) { if (found) { if (computeMonsterGroupDistance(monsterId) <= counter2 && !isMonsterAlreadyFighting(monsterId, counter)) { - _teamMonsterIdArray[counter] = monsterId; + _teamMonster[counter]._id = monsterId; if (++counter >= 5) break; } @@ -69,7 +69,7 @@ void EfhEngine::createOpponentList(int16 monsterTeamId) { return; for (uint id = counter; id < 5; ++id) - _teamMonsterIdArray[id] = -1; + _teamMonster[id]._id = -1; } void EfhEngine::initFight(int16 monsterId) { @@ -85,7 +85,7 @@ bool EfhEngine::handleFight(int16 monsterId) { initFight(monsterId); - if (_teamMonsterIdArray[0] == -1) { + if (_teamMonster[0]._id == -1) { resetTeamMonsterIdArray(); _ongoingFightFl = false; displayAnimFrames(0xFE, true); @@ -102,7 +102,7 @@ bool EfhEngine::handleFight(int16 monsterId) { return false; } - if (_teamMonsterIdArray[0] == -1) { + if (_teamMonster[0]._id == -1) { resetTeamMonsterIdArray(); _ongoingFightFl = false; displayAnimFrames(0xFE, true); @@ -243,7 +243,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { bool var6E = true; for (int16 groupId = minMonsterGroupId; groupId < maxMonsterGroupId; ++groupId) { - if (_teamMonsterIdArray[groupId] == -1) + if (_teamMonster[groupId]._id == -1) continue; for (int16 ctrMobsterId = minTeamMemberId; ctrMobsterId < maxTeamMemberId; ++ctrMobsterId) { @@ -258,12 +258,12 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { } else noticedFl = false; - int16 randomDamageAbsorbed = getRandom(_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._maxDamageAbsorption); + int16 randomDamageAbsorbed = getRandom(_mapMonsters[_techId][_teamMonster[groupId]._id]._maxDamageAbsorption); int16 enemyPronoun = _npcBuf[_teamChar[teamCharId]._id].getPronoun(); - int16 monsterId = _teamMonsterIdArray[groupId]; + int16 monsterId = _teamMonster[groupId]._id; int16 characterPronoun = kEncounters[_mapMonsters[_techId][monsterId]._monsterRef]._nameArticle; int16 charScore = getCharacterScore(_teamChar[teamCharId]._id, teamCharItemId); - int16 hitPointsBefore = _mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId]; + int16 hitPointsBefore = _mapMonsters[_techId][_teamMonster[groupId]._id]._hitPoints[ctrMobsterId]; int16 hitCount = 0; int16 originalDamage = 0; int16 damagePointsAbsorbed = 0; @@ -273,7 +273,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { for (int attackCounter = 0; attackCounter < attackSpeed; ++attackCounter) { if (getRandom(100) < charScore) { ++hitCount; - if (!hasAdequateDefense(_teamMonsterIdArray[groupId], _items[teamCharItemId]._attackType)) { + if (!hasAdequateDefense(_teamMonster[groupId]._id, _items[teamCharItemId]._attackType)) { int16 randomDamage = getRandom(_items[teamCharItemId]._damage); int16 residualDamage = randomDamage - randomDamageAbsorbed; if (residualDamage > 0) { @@ -296,7 +296,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { hitCount = 0; if (hitCount > 0) { - _mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] -= originalDamage; + _mapMonsters[_techId][_teamMonster[groupId]._id]._hitPoints[ctrMobsterId] -= originalDamage; if (hitCount > 1) { _attackBuffer = Common::String::format("%d times ", hitCount); } else { @@ -306,7 +306,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { int16 verbId = (3 * _items[teamCharItemId]._attackType + 1) + getRandom(3) - 1; _characterNamePt1 = getArticle(characterPronoun); - _characterNamePt2 = kEncounters[_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._monsterRef]._name; + _characterNamePt2 = kEncounters[_mapMonsters[_techId][_teamMonster[groupId]._id]._monsterRef]._name; _enemyNamePt1 = getArticle(enemyPronoun); _enemyNamePt2 = _npcBuf[_teamChar[teamCharId]._id]._name; @@ -320,17 +320,17 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s, but does no damage!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[verbId], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[enemyPronoun], _nameBuffer.c_str()); } else if (hitPoints == 1) { _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s for 1 point", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[verbId], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[enemyPronoun], _nameBuffer.c_str()); - if (_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] <= 0) { + if (_mapMonsters[_techId][_teamMonster[groupId]._id]._hitPoints[ctrMobsterId] <= 0) { getDeathTypeDescription(groupId, teamCharId + 1000); - getXPAndSearchCorpse(_teamChar[teamCharId]._id, _enemyNamePt1, _enemyNamePt2, _teamMonsterIdArray[groupId]); + getXPAndSearchCorpse(_teamChar[teamCharId]._id, _enemyNamePt1, _enemyNamePt2, _teamMonster[groupId]._id); } else { _messageToBePrinted += "!"; } } else { _messageToBePrinted = Common::String::format("%s%s %s %s%s %swith %s %s for %d points", _enemyNamePt1.c_str(), _enemyNamePt2.c_str(), kAttackVerbs[verbId], _characterNamePt1.c_str(), _characterNamePt2.c_str(), _attackBuffer.c_str(), kPossessive[enemyPronoun], _nameBuffer.c_str(), hitPoints); - if (_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] <= 0) { + if (_mapMonsters[_techId][_teamMonster[groupId]._id]._hitPoints[ctrMobsterId] <= 0) { getDeathTypeDescription(groupId, teamCharId + 1000); - getXPAndSearchCorpse(_teamChar[teamCharId]._id, _enemyNamePt1, _enemyNamePt2, _teamMonsterIdArray[groupId]); + getXPAndSearchCorpse(_teamChar[teamCharId]._id, _enemyNamePt1, _enemyNamePt2, _teamMonster[groupId]._id); } else { _messageToBePrinted += "!"; } @@ -338,16 +338,16 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { // Action A - Check damages - End // Action A - Add reaction text - Start - if (hitCount != 0 && originalDamage > 0 && getRandom(100) <= 35 && _mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] > 0) { - if (_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] - 5 <= originalDamage) { + if (hitCount != 0 && originalDamage > 0 && getRandom(100) <= 35 && _mapMonsters[_techId][_teamMonster[groupId]._id]._hitPoints[ctrMobsterId] > 0) { + if (_mapMonsters[_techId][_teamMonster[groupId]._id]._hitPoints[ctrMobsterId] - 5 <= originalDamage) { addReactionText(kEfhReactionReels); - } else if (_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] < hitPointsBefore / 8) { + } else if (_mapMonsters[_techId][_teamMonster[groupId]._id]._hitPoints[ctrMobsterId] < hitPointsBefore / 8) { addReactionText(kEfhReactionCriesOut); - } else if (_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] < hitPointsBefore / 4) { + } else if (_mapMonsters[_techId][_teamMonster[groupId]._id]._hitPoints[ctrMobsterId] < hitPointsBefore / 4) { addReactionText(kEfhReactionFalters); - } else if (_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] < hitPointsBefore / 2) { + } else if (_mapMonsters[_techId][_teamMonster[groupId]._id]._hitPoints[ctrMobsterId] < hitPointsBefore / 2) { addReactionText(kEfhReactionWinces); - } else if (_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] < hitPointsBefore / 3) { + } else if (_mapMonsters[_techId][_teamMonster[groupId]._id]._hitPoints[ctrMobsterId] < hitPointsBefore / 3) { // CHECKME: Doesn't make any sense to check /3 after /2... I don't get it. Looks like an original bug addReactionText(kEfhReactionScreams); } else if (hitPointsBefore / 8 >= originalDamage) { @@ -360,7 +360,7 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { // Action A - Add reaction text - End // Action A - Add armor absorb text - Start - if (randomDamageAbsorbed && hitCount && _mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] > 0) { + if (randomDamageAbsorbed && hitCount && _mapMonsters[_techId][_teamMonster[groupId]._id]._hitPoints[ctrMobsterId] > 0) { if (damagePointsAbsorbed <= 1) _messageToBePrinted += Common::String::format(" %s%s's armor absorbs 1 point!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); else @@ -390,15 +390,15 @@ void EfhEngine::handleFight_lastAction_A(int16 teamCharId) { // Action A - Check item durability - End // Action A - Check effect - Start - if (_items[teamCharItemId]._specialEffect == 1 && _mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] > 0) { + if (_items[teamCharItemId]._specialEffect == 1 && _mapMonsters[_techId][_teamMonster[groupId]._id]._hitPoints[ctrMobsterId] > 0) { if (getRandom(100) < 35) { - _teamMonsterEffects[groupId]._effect[ctrMobsterId] = 1; - _teamMonsterEffects[groupId]._duration[ctrMobsterId] = getRandom(10); + _teamMonster[groupId]._mobsterStatus[ctrMobsterId]._type = kEfhStatusSleeping; + _teamMonster[groupId]._mobsterStatus[ctrMobsterId]._duration = getRandom(10); _messageToBePrinted += Common::String::format(" %s%s falls asleep!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); } - } else if (_items[teamCharItemId]._specialEffect == 2 && _mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] > 0) { - _teamMonsterEffects[groupId]._effect[ctrMobsterId] = 2; - _teamMonsterEffects[groupId]._duration[ctrMobsterId] = getRandom(10); + } else if (_items[teamCharItemId]._specialEffect == 2 && _mapMonsters[_techId][_teamMonster[groupId]._id]._hitPoints[ctrMobsterId] > 0) { + _teamMonster[groupId]._mobsterStatus[ctrMobsterId]._type = kEfhStatusFrozen; + _teamMonster[groupId]._mobsterStatus[ctrMobsterId]._duration = getRandom(10); _messageToBePrinted += Common::String::format(" %s%s is frozen!", _characterNamePt1.c_str(), _characterNamePt2.c_str()); } // Action A - Check effect - End @@ -472,7 +472,7 @@ void EfhEngine::handleFight_MobstersAttack(int groupId) { // handleFight - Loop on mobsterId - Start for (uint ctrMobsterId = 0; ctrMobsterId < 9; ++ctrMobsterId) { if (isMonsterActive(groupId, ctrMobsterId)) { - int16 monsterWeaponItemId = _mapMonsters[_techId][_teamMonsterIdArray[groupId]]._weaponItemId; + int16 monsterWeaponItemId = _mapMonsters[_techId][_teamMonster[groupId]._id]._weaponItemId; if (monsterWeaponItemId == 0xFF) monsterWeaponItemId = 0x3F; int16 minTeamMemberId = -1; @@ -480,7 +480,7 @@ void EfhEngine::handleFight_MobstersAttack(int groupId) { if (_items[monsterWeaponItemId]._range < 3) { for (uint attackTry = 0; attackTry < 10; ++attackTry) { minTeamMemberId = getRandom(_teamSize) - 1; - if (checkWeaponRange(_teamMonsterIdArray[groupId], monsterWeaponItemId) && isTeamMemberStatusNormal(minTeamMemberId) && getRandom(100) < _teamChar[minTeamMemberId]._pctVisible) { + if (checkWeaponRange(_teamMonster[groupId]._id, monsterWeaponItemId) && isTeamMemberStatusNormal(minTeamMemberId) && getRandom(100) < _teamChar[minTeamMemberId]._pctVisible) { break; } minTeamMemberId = -1; @@ -501,7 +501,7 @@ void EfhEngine::handleFight_MobstersAttack(int groupId) { int16 randomDefense = getRandom(getEquipmentDefense(_teamChar[targetId]._id)); - int16 enemyPronoun = kEncounters[_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._monsterRef]._nameArticle; + int16 enemyPronoun = kEncounters[_mapMonsters[_techId][_teamMonster[groupId]._id]._monsterRef]._nameArticle; int16 characterPronoun = _npcBuf[_teamChar[targetId]._id].getPronoun(); _teamChar[targetId]._pctDodgeMiss += (_items[monsterWeaponItemId].field_13 * 5); @@ -509,7 +509,7 @@ void EfhEngine::handleFight_MobstersAttack(int groupId) { int16 originalDamage = 0; int16 damagePointsAbsorbed = 0; - int16 var64 = _mapMonsters[_techId][_teamMonsterIdArray[groupId]]._npcId * _items[monsterWeaponItemId]._attacks; + int16 var64 = _mapMonsters[_techId][_teamMonster[groupId]._id]._npcId * _items[monsterWeaponItemId]._attacks; for (int var84 = 0; var84 < var64; ++var84) { // handleFight - Loop var84 on var64 (objectId) - Start if (getRandom(100) > _teamChar[targetId]._pctDodgeMiss) @@ -551,7 +551,7 @@ void EfhEngine::handleFight_MobstersAttack(int groupId) { int16 var6A = getRandom(3); _enemyNamePt1 = getArticle(enemyPronoun); - _enemyNamePt2 = kEncounters[_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._monsterRef]._name; + _enemyNamePt2 = kEncounters[_mapMonsters[_techId][_teamMonster[groupId]._id]._monsterRef]._name; _characterNamePt1 = getArticle(characterPronoun); _characterNamePt2 = _npcBuf[_teamChar[targetId]._id]._name; @@ -646,24 +646,24 @@ void EfhEngine::handleFight_MobstersAttack(int groupId) { displayBoxWithText(_messageToBePrinted, 1, 2, true); } // handleFight - Loop on targetId - End - } else if (_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._hitPoints[ctrMobsterId] > 0 && _teamMonsterEffects[groupId]._effect[ctrMobsterId] > 0) { - --_teamMonsterEffects[groupId]._duration[ctrMobsterId]; - if (_teamMonsterEffects[groupId]._duration[ctrMobsterId] <= 0) { - _enemyNamePt1 = getArticle(kEncounters[_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._monsterRef]._nameArticle); - _enemyNamePt2 = kEncounters[_mapMonsters[_techId][_teamMonsterIdArray[groupId]]._monsterRef]._name; - - switch (_teamMonsterEffects[groupId]._effect[ctrMobsterId]) { - case 1: + } else if (_mapMonsters[_techId][_teamMonster[groupId]._id]._hitPoints[ctrMobsterId] > 0 && _teamMonster[groupId]._mobsterStatus[ctrMobsterId]._type != kEfhStatusNormal) { + --_teamMonster[groupId]._mobsterStatus[ctrMobsterId]._duration; + if (_teamMonster[groupId]._mobsterStatus[ctrMobsterId]._duration <= 0) { + _enemyNamePt1 = getArticle(kEncounters[_mapMonsters[_techId][_teamMonster[groupId]._id]._monsterRef]._nameArticle); + _enemyNamePt2 = kEncounters[_mapMonsters[_techId][_teamMonster[groupId]._id]._monsterRef]._name; + + switch (_teamMonster[groupId]._mobsterStatus[ctrMobsterId]._type) { + case kEfhStatusSleeping: _messageToBePrinted = Common::String::format("%s%s wakes up!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str()); break; - case 2: + case kEfhStatusFrozen: _messageToBePrinted = Common::String::format("%s%s thaws out!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str()); break; default: _messageToBePrinted = Common::String::format("%s%s recovers!", _enemyNamePt1.c_str(), _enemyNamePt2.c_str()); break; } - _teamMonsterEffects[groupId]._effect[ctrMobsterId] = 0; + _teamMonster[groupId]._mobsterStatus[ctrMobsterId]._type = kEfhStatusNormal; displayBoxWithText(_messageToBePrinted, 1, 2, true); } } @@ -687,7 +687,7 @@ bool EfhEngine::isMonsterAlreadyFighting(int16 monsterId, int16 teamMonsterId) { debugC(6, kDebugFight, "isMonsterAlreadyFighting %d %d", monsterId, teamMonsterId); for (int counter = 0; counter < teamMonsterId; ++counter) { - if (_teamMonsterIdArray[counter] == monsterId) + if (_teamMonster[counter]._id == monsterId) return true; } return false; @@ -697,8 +697,8 @@ void EfhEngine::resetTeamMonsterEffects() { debugC(6, kDebugFight, "resetTeamMonsterEffects"); for (uint ctrGroupId = 0; ctrGroupId < 5; ++ctrGroupId) { for (uint ctrMobsterId = 0; ctrMobsterId < 9; ++ctrMobsterId) { - _teamMonsterEffects[ctrGroupId]._effect[ctrMobsterId] = 0; - _teamMonsterEffects[ctrGroupId]._duration[ctrMobsterId] = 0; + _teamMonster[ctrGroupId]._mobsterStatus[ctrMobsterId]._type = kEfhStatusNormal; + _teamMonster[ctrGroupId]._mobsterStatus[ctrMobsterId]._duration = 0; } } } @@ -707,7 +707,7 @@ void EfhEngine::resetTeamMonsterIdArray() { debugC(6, kDebugFight, "resetTeamMonsterIdArray"); for (int i = 0; i < 5; ++i) { - _teamMonsterIdArray[i] = -1; + _teamMonster[i]._id = -1; } } @@ -729,7 +729,7 @@ void EfhEngine::getDeathTypeDescription(int16 victimId, int16 attackerId) { int16 charId = _teamChar[victimId - 1000]._id; pronoun = _npcBuf[charId].getPronoun(); } else { - int16 charId = _teamMonsterIdArray[victimId]; + int16 charId = _teamMonster[victimId]._id; pronoun = _mapMonsters[_techId][charId].getPronoun(); } @@ -750,10 +750,10 @@ void EfhEngine::getDeathTypeDescription(int16 victimId, int16 attackerId) { else deathType = _items[exclusiveItemId]._attackType + 1; } - } else if (_teamMonsterIdArray[attackerId] == -1) { + } else if (_teamMonster[attackerId]._id == -1) { deathType = 0; } else { - int16 itemId = _mapMonsters[_techId][_teamMonsterIdArray[attackerId]]._weaponItemId; + int16 itemId = _mapMonsters[_techId][_teamMonster[attackerId]._id]._weaponItemId; deathType = _items[itemId]._attackType + 1; } @@ -998,20 +998,20 @@ int16 EfhEngine::determineTeamTarget(int16 charId, int16 unkFied18Val, bool chec do { for (uint counter = 0; counter < 2; ++counter) { drawCombatScreen(charId, true, false); - if (_teamMonsterIdArray[1] != -1) + if (_teamMonster[1]._id != -1) displayBoxWithText("Select Monster Group:", 3, 0, false); if (counter == 0) displayFctFullScreen(); } - retVal = (_teamMonsterIdArray[1] == -1) ? 0 : selectMonsterGroup(); + retVal = (_teamMonster[1]._id == -1) ? 0 : selectMonsterGroup(); if (!checkDistanceFl) { if (retVal == 27) // Esc retVal = 0; } else if (retVal != 27) { - int16 monsterGroupDistance = computeMonsterGroupDistance(_teamMonsterIdArray[retVal]); + int16 monsterGroupDistance = computeMonsterGroupDistance(_teamMonster[retVal]._id); if (monsterGroupDistance > realRange) { retVal = 27; displayBoxWithText("That Group Is Out Of Range!", 3, 1, false); @@ -1318,10 +1318,10 @@ void EfhEngine::displayEncounterInfo(bool whiteFl) { int16 textPosY = 20; for (uint counter = 0; counter < 5; ++counter) { - if (_teamMonsterIdArray[counter] == -1) + if (_teamMonster[counter]._id == -1) continue; - int16 monsterDistance = computeMonsterGroupDistance(_teamMonsterIdArray[counter]); + int16 monsterDistance = computeMonsterGroupDistance(_teamMonster[counter]._id); int16 mobsterCount = countMonsterGroupMembers(counter); if (whiteFl) setTextColorWhite(); @@ -1332,16 +1332,16 @@ void EfhEngine::displayEncounterInfo(bool whiteFl) { Common::String buffer = Common::String::format("%c)", 'A' + counter); displayStringAtTextPos(buffer); setTextColorRed(); - int16 var1 = _mapMonsters[_techId][_teamMonsterIdArray[counter]]._possessivePronounSHL6 & 0x3F; + int16 var1 = _mapMonsters[_techId][_teamMonster[counter]._id]._possessivePronounSHL6 & 0x3F; if (var1 <= 0x3D) { - buffer = Common::String::format("%d %s", mobsterCount, kEncounters[_mapMonsters[_techId][_teamMonsterIdArray[counter]]._monsterRef]._name); + buffer = Common::String::format("%d %s", mobsterCount, kEncounters[_mapMonsters[_techId][_teamMonster[counter]._id]._monsterRef]._name); displayStringAtTextPos(buffer); if (mobsterCount > 1) displayStringAtTextPos("s"); } else if (var1 == 0x3E) { displayStringAtTextPos("(NOT DEFINED)"); } else if (var1 == 0x3F) { - Common::String stringToDisplay = _npcBuf[_mapMonsters[_techId][_teamMonsterIdArray[counter]]._npcId]._name; + Common::String stringToDisplay = _npcBuf[_mapMonsters[_techId][_teamMonster[counter]._id]._npcId]._name; displayStringAtTextPos(stringToDisplay); } @@ -1378,7 +1378,7 @@ int16 EfhEngine::getWeakestMobster(int16 groupNumber) { debugC(3, kDebugFight, "getWeakestMobster %d", groupNumber); int16 weakestMobsterId = -1; - int16 monsterId = _teamMonsterIdArray[groupNumber]; + int16 monsterId = _teamMonster[groupNumber]._id; if (monsterId == -1) return -1; @@ -1545,28 +1545,28 @@ void EfhEngine::addNewOpponents(int16 monsterId) { continue; for (uint ctrMobster = 0; ctrMobster < 9; ++ctrMobster) { - _mapMonsters[_techId][_teamMonsterIdArray[ctrGroupId]]._hitPoints[ctrMobster] = 0; - _teamMonsterEffects[ctrGroupId]._effect[ctrMobster] = 0; - _teamMonsterEffects[ctrGroupId]._duration[ctrMobster] = 0; + _mapMonsters[_techId][_teamMonster[ctrGroupId]._id]._hitPoints[ctrMobster] = 0; + _teamMonster[ctrGroupId]._mobsterStatus[ctrMobster]._type = kEfhStatusNormal; + _teamMonster[ctrGroupId]._mobsterStatus[ctrMobster]._duration = 0; } - _teamMonsterIdArray[ctrGroupId] = -1; + _teamMonster[ctrGroupId]._id = -1; // CHECKME: ctrGroupId is not incrementing, which is very, very suspicious as we are copying over and over to the same destination // if the purpose is compact the array, it should be handle differently for (uint counter2 = ctrGroupId + 1; counter2 < 5; ++counter2) { for (uint ctrMobsterId = 0; ctrMobsterId < 9; ++ctrMobsterId) { - _teamMonsterEffects[ctrGroupId]._effect[ctrMobsterId] = _teamMonsterEffects[counter2]._effect[ctrMobsterId]; - _teamMonsterEffects[ctrGroupId]._duration[ctrMobsterId] = _teamMonsterEffects[counter2]._duration[ctrMobsterId]; + _teamMonster[ctrGroupId]._mobsterStatus[ctrMobsterId]._type = _teamMonster[counter2]._mobsterStatus[ctrMobsterId]._type; + _teamMonster[ctrGroupId]._mobsterStatus[ctrMobsterId]._duration = _teamMonster[counter2]._mobsterStatus[ctrMobsterId]._duration; } - _teamMonsterIdArray[ctrGroupId] = _teamMonsterIdArray[counter2]; + _teamMonster[ctrGroupId]._id = _teamMonster[counter2]._id; } } // addNewOpponents - 1rst loop counter1_monsterId - End int16 teamMonsterId = -1; for (uint counter1 = 0; counter1 < 5; ++counter1) { - if (_teamMonsterIdArray[counter1] == -1) { + if (_teamMonster[counter1]._id == -1) { teamMonsterId = counter1; break; } @@ -1601,13 +1601,13 @@ void EfhEngine::addNewOpponents(int16 monsterId) { if (isMonsterAlreadyFighting(ctrMapMonsterId, teamMonsterId)) continue; - _teamMonsterIdArray[teamMonsterId] = ctrMapMonsterId; + _teamMonster[teamMonsterId]._id = ctrMapMonsterId; // The original at this point was doing a loop on counter1, which is not a good idea as // it was resetting the counter1 to 9 whatever its value before the loop. // I therefore decided to use another counter as it looks like an original misbehavior/bug. for (uint ctrMobsterId = 0; ctrMobsterId < 9; ++ctrMobsterId) { - _teamMonsterEffects[teamMonsterId]._effect[ctrMobsterId] = 0; + _teamMonster[teamMonsterId]._mobsterStatus[ctrMobsterId]._type = kEfhStatusNormal; } if (++teamMonsterId >= 5) @@ -1624,9 +1624,9 @@ void EfhEngine::addNewOpponents(int16 monsterId) { // addNewOpponents - last loop counter1_monsterId - Start for (int16 ctrTeamMonsterId = teamMonsterId; ctrTeamMonsterId < 5; ++ctrTeamMonsterId) { - _teamMonsterIdArray[ctrTeamMonsterId] = -1; + _teamMonster[ctrTeamMonsterId]._id = -1; for (uint ctrEffectId = 0; ctrEffectId < 9; ++ctrEffectId) { - _teamMonsterEffects[ctrTeamMonsterId]._effect[ctrEffectId] = (int16)0x8000; + _teamMonster[ctrTeamMonsterId]._mobsterStatus[ctrEffectId]._type = (int16)0x8000; } } // addNewOpponents - last loop counter1_monsterId - End @@ -1637,7 +1637,7 @@ int16 EfhEngine::getTeamMonsterAnimId() { int16 retVal = 0xFF; for (uint counter = 0; counter < 5; ++counter) { - int16 monsterId = _teamMonsterIdArray[counter]; + int16 monsterId = _teamMonster[counter]._id; if (monsterId == -1) continue; @@ -1649,7 +1649,7 @@ int16 EfhEngine::getTeamMonsterAnimId() { } if (retVal == 0xFF) - retVal = kEncounters[_mapMonsters[_techId][_teamMonsterIdArray[0]]._monsterRef]._animId; + retVal = kEncounters[_mapMonsters[_techId][_teamMonster[0]._id]._monsterRef]._animId; return retVal; } @@ -1671,7 +1671,7 @@ int16 EfhEngine::selectMonsterGroup() { case Common::KEYCODE_d: case Common::KEYCODE_e: retVal = input - Common::KEYCODE_a; - if (_teamMonsterIdArray[retVal] == -1) + if (_teamMonster[retVal]._id == -1) retVal = -1; break; default: diff --git a/engines/efh/init.cpp b/engines/efh/init.cpp index 59b2ff80cfc4..37c13d0c43d7 100644 --- a/engines/efh/init.cpp +++ b/engines/efh/init.cpp @@ -201,10 +201,11 @@ uint8 MapMonster::getPronoun() { return _possessivePronounSHL6 >> 6; } -void TeamMonsterEffect::init() { +void TeamMonster::init() { + _id = -1; for (int ctrMobsterId = 0; ctrMobsterId < 9; ++ctrMobsterId) { - _effect[ctrMobsterId] = 0; - _duration[ctrMobsterId] = 0; + _mobsterStatus[ctrMobsterId]._type = 0; + _mobsterStatus[ctrMobsterId]._duration = 0; } } @@ -318,8 +319,7 @@ EfhEngine::EfhEngine(OSystem *syst, const ADGameDescription *gd) : Engine(syst), } for (int i = 0; i < 5; ++i) { - _teamMonsterIdArray[i] = -1; - _teamMonsterEffects[i].init(); + _teamMonster[i].init(); } _teamSize = 1; diff --git a/engines/efh/menu.cpp b/engines/efh/menu.cpp index 3e9d586d2795..087301cf0439 100644 --- a/engines/efh/menu.cpp +++ b/engines/efh/menu.cpp @@ -908,8 +908,8 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in for (uint ctrMobsterId = 0; ctrMobsterId < 9; ++ctrMobsterId) { if (isMonsterActive(teamMonsterId, ctrMobsterId)) { ++victims; - _teamMonsterEffects[teamMonsterId]._effect[ctrMobsterId] = 1; - _teamMonsterEffects[teamMonsterId]._duration[ctrMobsterId] = getRandom(8); + _teamMonster[teamMonsterId]._mobsterStatus[ctrMobsterId]._type = kEfhStatusSleeping; + _teamMonster[teamMonsterId]._mobsterStatus[ctrMobsterId]._duration = getRandom(8); } } } else { @@ -921,16 +921,16 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in if (isMonsterActive(teamMonsterId, ctrMobsterId)) { ++victims; --NumberOfTargets; - _teamMonsterEffects[teamMonsterId]._effect[ctrMobsterId] = 1; - _teamMonsterEffects[teamMonsterId]._duration[ctrMobsterId] = getRandom(8); + _teamMonster[teamMonsterId]._mobsterStatus[ctrMobsterId]._type = kEfhStatusSleeping; + _teamMonster[teamMonsterId]._mobsterStatus[ctrMobsterId]._duration = getRandom(8); } } } // The original was duplicating this code in each branch of the previous random check. if (victims > 1) { - buffer1 = Common::String::format("%d %ss fall asleep!", victims, kEncounters[_mapMonsters[_techId][_teamMonsterIdArray[teamMonsterId]]._monsterRef]._name); + buffer1 = Common::String::format("%d %ss fall asleep!", victims, kEncounters[_mapMonsters[_techId][_teamMonster[teamMonsterId]._id]._monsterRef]._name); } else { - buffer1 = Common::String::format("%d %s falls asleep!", victims, kEncounters[_mapMonsters[_techId][_teamMonsterIdArray[teamMonsterId]]._monsterRef]._name); + buffer1 = Common::String::format("%d %s falls asleep!", victims, kEncounters[_mapMonsters[_techId][_teamMonster[teamMonsterId]._id]._monsterRef]._name); } _messageToBePrinted += buffer1; } @@ -947,8 +947,8 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in for (uint ctrEffectId = 0; ctrEffectId < 9; ++ctrEffectId) { if (isMonsterActive(teamMonsterId, ctrEffectId)) { ++victim; - _teamMonsterEffects[teamMonsterId]._effect[ctrEffectId] = 2; - _teamMonsterEffects[teamMonsterId]._duration[ctrEffectId] = getRandom(8); + _teamMonster[teamMonsterId]._mobsterStatus[ctrEffectId]._type = kEfhStatusFrozen; + _teamMonster[teamMonsterId]._mobsterStatus[ctrEffectId]._duration = getRandom(8); } } } else { @@ -960,17 +960,17 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in if (isMonsterActive(teamMonsterId, ctrMobsterId)) { ++victim; --varAC; - _teamMonsterEffects[teamMonsterId]._effect[ctrMobsterId] = 2; - _teamMonsterEffects[teamMonsterId]._duration[ctrMobsterId] = getRandom(8); + _teamMonster[teamMonsterId]._mobsterStatus[ctrMobsterId]._type = kEfhStatusFrozen; + _teamMonster[teamMonsterId]._mobsterStatus[ctrMobsterId]._duration = getRandom(8); } } } // : This part is only present in the original in the case < 50, but for me // it's missing in the other case as there's an effect (frozen enemies) but no feedback to the player if (victim > 1) { - buffer1 = Common::String::format("%d %ss are frozen in place!", victim, kEncounters[_mapMonsters[_techId][_teamMonsterIdArray[teamMonsterId]]._monsterRef]._name); + buffer1 = Common::String::format("%d %ss are frozen in place!", victim, kEncounters[_mapMonsters[_techId][_teamMonster[teamMonsterId]._id]._monsterRef]._name); } else { - buffer1 = Common::String::format("%d %s is frozen in place!", victim, kEncounters[_mapMonsters[_techId][_teamMonsterIdArray[teamMonsterId]]._monsterRef]._name); + buffer1 = Common::String::format("%d %s is frozen in place!", victim, kEncounters[_mapMonsters[_techId][_teamMonster[teamMonsterId]._id]._monsterRef]._name); } _messageToBePrinted += buffer1; // @@ -996,14 +996,14 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in if (getRandom(100) < 50) { for (uint counter = 0; counter < 9; ++counter) { if (getRandom(100) < 50) { - _mapMonsters[_techId][_teamMonsterIdArray[teamMonsterId]]._hitPoints[counter] = 0; + _mapMonsters[_techId][_teamMonster[teamMonsterId]._id]._hitPoints[counter] = 0; } } } else { for (uint counter = 0; counter < 9; ++counter) { if (isMonsterActive(teamMonsterId, counter)) { if (getRandom(100) < 50) { - _mapMonsters[_techId][_teamMonsterIdArray[teamMonsterId]]._hitPoints[counter] = 0; + _mapMonsters[_techId][_teamMonster[teamMonsterId]._id]._hitPoints[counter] = 0; } break; } @@ -1019,13 +1019,13 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in if (getRandom(100) < 50) { _messageToBePrinted += " A dark fiery whirlwind surrounds the poor victim...the power fades and all targeted die!"; for (uint counter = 0; counter < 9; ++counter) { - _mapMonsters[_techId][_teamMonsterIdArray[teamMonsterId]]._hitPoints[counter] = 0; + _mapMonsters[_techId][_teamMonster[teamMonsterId]._id]._hitPoints[counter] = 0; } } else { _messageToBePrinted += " A dark fiery whirlwind surrounds the poor victim...the power fades and one victim dies!"; for (uint counter = 0; counter < 9; ++counter) { if (isMonsterActive(teamMonsterId, counter)) { - _mapMonsters[_techId][_teamMonsterIdArray[teamMonsterId]]._hitPoints[counter] = 0; + _mapMonsters[_techId][_teamMonster[teamMonsterId]._id]._hitPoints[counter] = 0; } } } From 3a68ef3cf1a8167bd7f1121301e40a498aabe3f7 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Fri, 3 Feb 2023 09:04:13 +0100 Subject: [PATCH 287/412] EFH: Simplify code in addNewOpponents, add a comment in useObject() about the description of a cure to being frozen --- engines/efh/fight.cpp | 11 +++-------- engines/efh/init.cpp | 2 +- engines/efh/menu.cpp | 4 +++- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index d53e2cb6f812..fb9372236f70 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -1622,14 +1622,9 @@ void EfhEngine::addNewOpponents(int16 monsterId) { if (teamMonsterId == -1 || teamMonsterId > 4) return; - // addNewOpponents - last loop counter1_monsterId - Start - for (int16 ctrTeamMonsterId = teamMonsterId; ctrTeamMonsterId < 5; ++ctrTeamMonsterId) { - _teamMonster[ctrTeamMonsterId]._id = -1; - for (uint ctrEffectId = 0; ctrEffectId < 9; ++ctrEffectId) { - _teamMonster[ctrTeamMonsterId]._mobsterStatus[ctrEffectId]._type = (int16)0x8000; - } - } - // addNewOpponents - last loop counter1_monsterId - End + // Reset the unused groups + for (int16 ctrTeamMonsterId = teamMonsterId; ctrTeamMonsterId < 5; ++ctrTeamMonsterId) + _teamMonster[ctrTeamMonsterId].init(); } int16 EfhEngine::getTeamMonsterAnimId() { diff --git a/engines/efh/init.cpp b/engines/efh/init.cpp index 37c13d0c43d7..b93b8b49a6b3 100644 --- a/engines/efh/init.cpp +++ b/engines/efh/init.cpp @@ -204,7 +204,7 @@ uint8 MapMonster::getPronoun() { void TeamMonster::init() { _id = -1; for (int ctrMobsterId = 0; ctrMobsterId < 9; ++ctrMobsterId) { - _mobsterStatus[ctrMobsterId]._type = 0; + _mobsterStatus[ctrMobsterId]._type = kEfhStatusNormal; _mobsterStatus[ctrMobsterId]._duration = 0; } } diff --git a/engines/efh/menu.cpp b/engines/efh/menu.cpp index 087301cf0439..61cd1fc3a3b3 100644 --- a/engines/efh/menu.cpp +++ b/engines/efh/menu.cpp @@ -1166,7 +1166,9 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in } else { int16 teamCharId = teamMonsterId; if (teamCharId != 0x1B) { - if (_teamChar[teamCharId]._status._type == kEfhStatusFrozen) { // frozen + if (_teamChar[teamCharId]._status._type == kEfhStatusFrozen) { + // The message is weird because it's a duplicate of case 28, which is about "curing" sleep... But it's about being frozen. + // We could improve the description, but that's the way the original deals with it _messageToBePrinted += " The item makes a loud noise, awakening the character!"; _teamChar[teamCharId]._status._type = kEfhStatusNormal; _teamChar[teamCharId]._status._duration = 0; From 9c02a5b55f0c2c9fb2b47c9b38f4703ad967a2b7 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Fri, 3 Feb 2023 23:29:49 +0100 Subject: [PATCH 288/412] EFH: rename _tileBankSubFileArray, move teamChar initialization to its own init() --- engines/efh/efh.cpp | 10 +++++----- engines/efh/efh.h | 4 +++- engines/efh/init.cpp | 28 ++++++++++++++++------------ 3 files changed, 24 insertions(+), 18 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index de0cdc44673c..d3734cd694e5 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -610,10 +610,10 @@ void EfhEngine::drawMap(bool largeMapFl, int16 mapPosX, int16 mapPosY, int16 map for (int16 counterX = minX; counterX <= maxX; ++counterX) { if (largeMapFl) { int16 curTile = _mapGameMaps[_techId][counterX][counterY]; - displayRawDataAtPos(_imageSetSubFilesArray[curTile], drawPosX, drawPosY); + displayRawDataAtPos(_tileBankSubFilesArray[curTile], drawPosX, drawPosY); } else { int16 curTile = _curPlace[counterX][counterY]; - displayRawDataAtPos(_imageSetSubFilesArray[curTile], drawPosX, drawPosY); + displayRawDataAtPos(_tileBankSubFilesArray[curTile], drawPosX, drawPosY); } drawPosX += 16; } @@ -624,7 +624,7 @@ void EfhEngine::drawMap(bool largeMapFl, int16 mapPosX, int16 mapPosY, int16 map // Draw hero int16 drawPosX = 128 + shiftPosX * 16; drawPosY = 8 + shiftPosY * 16; - displayRawDataAtPos(_imageSetSubFilesArray[_imageSetSubFilesIdx], drawPosX, drawPosY); + displayRawDataAtPos(_tileBankSubFilesArray[_imageSetSubFilesIdx], drawPosX, drawPosY); } if (drawMonstersFl) { @@ -653,7 +653,7 @@ void EfhEngine::drawMap(bool largeMapFl, int16 mapPosX, int16 mapPosY, int16 map int16 drawPosX = 128 + (posX - minX) * 16; drawPosY = 8 + (posY - minY) * 16; - displayRawDataAtPos(_imageSetSubFilesArray[imageSetIdx], drawPosX, drawPosY); + displayRawDataAtPos(_tileBankSubFilesArray[imageSetIdx], drawPosX, drawPosY); } } } @@ -2447,7 +2447,7 @@ void EfhEngine::loadImageSetToTileBank(int16 tileBankId, int16 imageSetId) { _mapBitmapRefArr[_techId]._setId2 = setId; int16 ptrIndex = bankId * 72; - loadImageSet(setId, _tileBank[bankId], &_imageSetSubFilesArray[ptrIndex], _decompBuf); + loadImageSet(setId, _tileBank[bankId], &_tileBankSubFilesArray[ptrIndex], _decompBuf); } void EfhEngine::restoreAnimImageSetId() { diff --git a/engines/efh/efh.h b/engines/efh/efh.h index f402f5d5247c..0d790c87bd75 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -246,6 +246,8 @@ struct TeamChar { int16 _nextAttack; int16 _lastInventoryUsed; int16 _lastAction; + + void init(); }; struct TeamMonster { @@ -570,7 +572,7 @@ class EfhEngine : public Engine { int16 _animImageSetId; uint8 _paletteTransformationConstant; uint8 *_circleImageSubFileArray[12]; - uint8 *_imageSetSubFilesArray[214]; // CHECKME : logically it should be 216 + uint8 *_tileBankSubFilesArray[214]; // CHECKME : logically it should be 216 BufferBM _imageDataPtr; int16 _currentTileBankImageSetId[3]; int16 _unkRelatedToAnimImageSetId; diff --git a/engines/efh/init.cpp b/engines/efh/init.cpp index b93b8b49a6b3..cce48b89214f 100644 --- a/engines/efh/init.cpp +++ b/engines/efh/init.cpp @@ -217,6 +217,17 @@ void TileFactStruct::init() { _field0 = _tileId = 0; } +void TeamChar::init() { + _id = -1; + _status._type = kEfhStatusNormal; + _status._duration = 0; + _pctVisible = 0; + _pctDodgeMiss = 0; + _nextAttack = -1; + _lastInventoryUsed = 0; + _lastAction = 0; +} + EfhEngine::EfhEngine(OSystem *syst, const ADGameDescription *gd) : Engine(syst), _gameDescription(gd) { const Common::FSNode gameDataDir(ConfMan.get("path")); @@ -305,18 +316,11 @@ EfhEngine::EfhEngine(OSystem *syst, const ADGameDescription *gd) : Engine(syst), _guessAnimationAmount = 9; _largeMapFlag = 0xFFFF; _alertDelay = 0; + + for (int i = 0; i < 3; ++i) + _teamChar[i].init(); + _teamChar[0]._id = 0; - _teamChar[1]._id = _teamChar[2]._id = -1; - - for (int i = 0; i < 3; ++i) { - _teamChar[i]._status._type = kEfhStatusNormal; - _teamChar[i]._status._duration = 0; - _teamChar[i]._pctVisible = 0; - _teamChar[i]._pctDodgeMiss = 0; - _teamChar[i]._nextAttack = -1; - _teamChar[i]._lastInventoryUsed = 0; - _teamChar[i]._lastAction = 0; - } for (int i = 0; i < 5; ++i) { _teamMonster[i].init(); @@ -380,7 +384,7 @@ EfhEngine::EfhEngine(OSystem *syst, const ADGameDescription *gd) : Engine(syst), memset(_mapMonsters[i], 0, ARRAYSIZE(_mapMonsters[i])); memset(_mapGameMaps[i], 0, ARRAYSIZE(_mapGameMaps[i])); } - memset(_imageSetSubFilesArray, 0, ARRAYSIZE(_imageSetSubFilesArray)); + memset(_tileBankSubFilesArray, 0, ARRAYSIZE(_tileBankSubFilesArray)); _regenCounter = 0; // If requested, load a savegame instead of showing the intro From a24acf909de73f985de6fa88b170911635eb8f51 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Sun, 5 Feb 2023 11:13:14 +0100 Subject: [PATCH 289/412] EFH: Some renaming and comments --- engines/efh/efh.cpp | 31 +++++++++++++++-------------- engines/efh/efh.h | 18 ++++++++--------- engines/efh/fight.cpp | 10 +++++----- engines/efh/files.cpp | 42 +++++++++++++++++++-------------------- engines/efh/graphics.cpp | 4 ++-- engines/efh/init.cpp | 21 ++++++++++---------- engines/efh/menu.cpp | 10 +++++----- engines/efh/savegames.cpp | 4 ++-- 8 files changed, 71 insertions(+), 69 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index d3734cd694e5..96850e94d6d7 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -2055,35 +2055,35 @@ bool EfhEngine::handleInteractionText(int16 mapPosX, int16 mapPosY, int16 charId if (imageSetId != -1 && *_imp2PtrArray[imageSetId] != 0x30) displayMiddleLeftTempText(_imp2PtrArray[imageSetId], true); } else if (arg8 == 0) { - if (_mapSpecialTiles[_techId][tileId]._field3 == 0xFF) { + if (_mapSpecialTiles[_techId][tileId]._triggerType == 0xFF) { displayImp1Text(_mapSpecialTiles[_techId][tileId]._field5_textId); return true; } - if (_mapSpecialTiles[_techId][tileId]._field3 == 0xFE) { + if (_mapSpecialTiles[_techId][tileId]._triggerType == 0xFE) { for (int counter = 0; counter < _teamSize; ++counter) { if (_teamChar[counter]._id == -1) continue; - if (_teamChar[counter]._id == _mapSpecialTiles[_techId][tileId]._triggerId) { + if (_teamChar[counter]._id == _mapSpecialTiles[_techId][tileId]._triggerValue) { displayImp1Text(_mapSpecialTiles[_techId][tileId]._field5_textId); return true; } } - } else if (_mapSpecialTiles[_techId][tileId]._field3 == 0xFD) { + } else if (_mapSpecialTiles[_techId][tileId]._triggerType == 0xFD) { for (int counter = 0; counter < _teamSize; ++counter) { if (_teamChar[counter]._id == -1) continue; for (uint var2 = 0; var2 < 10; ++var2) { - if (_npcBuf[_teamChar[counter]._id]._inventory[var2]._ref == _mapSpecialTiles[_techId][tileId]._triggerId) { + if (_npcBuf[_teamChar[counter]._id]._inventory[var2]._ref == _mapSpecialTiles[_techId][tileId]._triggerValue) { displayImp1Text(_mapSpecialTiles[_techId][tileId]._field5_textId); return true; } } } - // original makes a useless check on (_mapSpecialTile[tileId]._field3 > 0x7F) - } else if (_mapSpecialTiles[_techId][tileId]._field3 <= 0x77) { - int16 scoreId = _mapSpecialTiles[_techId][tileId]._field3; + // original makes a useless check on (_mapSpecialTile[tileId]._triggerType > 0x7F) + } else if (_mapSpecialTiles[_techId][tileId]._triggerType <= 0x77) { + int16 scoreId = _mapSpecialTiles[_techId][tileId]._triggerType; for (int counter = 0; counter < _teamSize; ++counter) { if (_teamChar[counter]._id == -1) continue; @@ -2092,25 +2092,26 @@ bool EfhEngine::handleInteractionText(int16 mapPosX, int16 mapPosY, int16 charId // CHECKME : the whole loop doesn't make much sense as it's using scoreId instead of var2, plus _activeScore is an array of 15 bytes, not 0x77... // Also, 39 correspond to the size of activeScore + passiveScore + infoScore + the 2 remaining bytes of the struct warning("handleInteractionText - _activeScore[%d]", scoreId); - if (_npcBuf[_teamChar[counter]._id]._activeScore[scoreId] >= _mapSpecialTiles[_techId][tileId]._triggerId) { + if (_npcBuf[_teamChar[counter]._id]._activeScore[scoreId] >= _mapSpecialTiles[_techId][tileId]._triggerValue) { displayImp1Text(_mapSpecialTiles[_techId][tileId]._field5_textId); return true; } } } } - } else if ((_mapSpecialTiles[_techId][tileId]._field3 == 0xFA && arg8 == 1) || (_mapSpecialTiles[_techId][tileId]._field3 == 0xFC && arg8 == 2) || (_mapSpecialTiles[_techId][tileId]._field3 == 0xFB && arg8 == 3)) { - if (_mapSpecialTiles[_techId][tileId]._triggerId == itemId) { + } else if ((_mapSpecialTiles[_techId][tileId]._triggerType == 0xFA && arg8 == 1) || (_mapSpecialTiles[_techId][tileId]._triggerType == 0xFC && arg8 == 2) || (_mapSpecialTiles[_techId][tileId]._triggerType == 0xFB && arg8 == 3)) { + if (_mapSpecialTiles[_techId][tileId]._triggerValue == itemId) { displayImp1Text(_mapSpecialTiles[_techId][tileId]._field5_textId); return true; } } else if (arg8 == 4) { - int16 var6 = _mapSpecialTiles[_techId][tileId]._field3; + int16 var6 = _mapSpecialTiles[_techId][tileId]._triggerType; if (var6 >= 0x78 && var6 <= 0xEF) { var6 -= 0x78; warning("handleInteractionText - _activeScore[%d]", var6); - // The 2 checks on var6 are useless, as [0x78..0xEF] - 0x78 => [0x00..0x77] - if (var6 >= 0 && var6 <= 0x8B && var6 == itemId && _mapSpecialTiles[_techId][tileId]._triggerId <= _npcBuf[charId]._activeScore[itemId]) { + // Note: The 2 checks on var6 are useless, as [0x78..0xEF] - 0x78 => [0x00..0x77] + // Note: In the data,all resulting values are between 2 and 14, so it's working + if (var6 >= 0 && var6 <= 0x8B && var6 == itemId && _mapSpecialTiles[_techId][tileId]._triggerValue <= _npcBuf[charId]._activeScore[itemId]) { displayImp1Text(_mapSpecialTiles[_techId][tileId]._field5_textId); return true; } @@ -2123,7 +2124,7 @@ bool EfhEngine::handleInteractionText(int16 mapPosX, int16 mapPosY, int16 charId } // CHECKME: there's suspiciously no check on tileId - if ((arg8 == 4 && _mapSpecialTiles[_techId][tileId]._field3 < 0xFA) || arg8 != 4) { + if ((arg8 == 4 && _mapSpecialTiles[_techId][tileId]._triggerType < 0xFA) || arg8 != 4) { if (_mapSpecialTiles[_techId][tileId]._field7_textId > 0xFE) return false; displayImp1Text(_mapSpecialTiles[_techId][tileId]._field7_textId); diff --git a/engines/efh/efh.h b/engines/efh/efh.h index 0d790c87bd75..3bf5fbd7ad0c 100644 --- a/engines/efh/efh.h +++ b/engines/efh/efh.h @@ -94,23 +94,23 @@ struct MapSpecialTileStruct { uint8 _placeId; uint8 _posX; uint8 _posY; - uint8 _field3; - uint8 _triggerId; + uint8 _triggerType; // 0xFD = Check inventory 0xFE = Check Character in team 0xFF Display description <= 0x77 = check score (all values in this case in data are <= 0xF) + uint8 _triggerValue; uint16 _field5_textId; uint16 _field7_textId; void init(); }; -struct UnkAnimStruct { - int8 _field[4]; +struct FrameList { + int8 _subFileId[4]; void init(); }; struct AnimInfo { - UnkAnimStruct _unkAnimArray[15]; - uint8 _field3C_startY[10]; - uint16 _field46_startX[10]; + uint16 _posX[10]; + uint8 _posY[10]; + FrameList _frameList[15]; void init(); }; @@ -121,11 +121,11 @@ struct ItemStruct { uint8 _defense; uint8 _attacks; uint8 _uses; - int8 field_13; // data contains values from -8 to +8 + int8 _agilityModifier; // data contains values from -8 to +8 uint8 _range; uint8 _attackType; uint8 _specialEffect; - uint8 _field17_attackTypeDefense; + uint8 _defenseType; uint8 _exclusiveType; uint8 _field19_mapPosX_or_maxDeltaPoints; uint8 _mapPosY; diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index fb9372236f70..c36361fb05bb 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -504,7 +504,7 @@ void EfhEngine::handleFight_MobstersAttack(int groupId) { int16 enemyPronoun = kEncounters[_mapMonsters[_techId][_teamMonster[groupId]._id]._monsterRef]._nameArticle; int16 characterPronoun = _npcBuf[_teamChar[targetId]._id].getPronoun(); - _teamChar[targetId]._pctDodgeMiss += (_items[monsterWeaponItemId].field_13 * 5); + _teamChar[targetId]._pctDodgeMiss += (_items[monsterWeaponItemId]._agilityModifier * 5); int16 hitCount = 0; int16 originalDamage = 0; int16 damagePointsAbsorbed = 0; @@ -1480,7 +1480,7 @@ int16 EfhEngine::getCharacterScore(int16 charId, int16 itemId) { break; } - extraScore += _items[itemId].field_13; + extraScore += _items[itemId]._agilityModifier; int16 grandTotalScore = CLIP(totalScore + extraScore + 30, 5, 90); @@ -1513,7 +1513,7 @@ bool EfhEngine::hasAdequateDefense(int16 monsterId, uint8 attackType) { if (_items[itemId]._specialEffect != 0) return false; - return _items[itemId]._field17_attackTypeDefense == attackType; + return _items[itemId]._defenseType == attackType; } bool EfhEngine::hasAdequateDefenseNPC(int16 charId, uint8 attackType) { @@ -1521,7 +1521,7 @@ bool EfhEngine::hasAdequateDefenseNPC(int16 charId, uint8 attackType) { int16 itemId = _npcBuf[charId]._defaultDefenseItemId; - if (_items[itemId]._specialEffect == 0 && _items[itemId]._field17_attackTypeDefense == attackType) + if (_items[itemId]._specialEffect == 0 && _items[itemId]._defenseType == attackType) return true; for (uint counter = 0; counter < 10; ++counter) { @@ -1529,7 +1529,7 @@ bool EfhEngine::hasAdequateDefenseNPC(int16 charId, uint8 attackType) { continue; itemId = _npcBuf[charId]._inventory[counter]._ref; - if (_items[itemId]._specialEffect == 0 && _items[itemId]._field17_attackTypeDefense == attackType) + if (_items[itemId]._specialEffect == 0 && _items[itemId]._defenseType == attackType) return true; } return false; diff --git a/engines/efh/files.cpp b/engines/efh/files.cpp index 909e41be2cf5..3ab9ffa1ad4c 100644 --- a/engines/efh/files.cpp +++ b/engines/efh/files.cpp @@ -45,27 +45,28 @@ void EfhEngine::readAnimInfo() { for (int i = 0; i < 100; ++i) { for (int id = 0; id < 15; ++id) { - _animInfo[i]._unkAnimArray[id]._field[0] = f.readByte(); - _animInfo[i]._unkAnimArray[id]._field[1] = f.readByte(); - _animInfo[i]._unkAnimArray[id]._field[2] = f.readByte(); - _animInfo[i]._unkAnimArray[id]._field[3] = f.readByte(); + Common::String txtBuffer = "->"; + for (int frameId = 0; frameId < 4; ++frameId) { + _animInfo[i]._frameList[id]._subFileId[frameId] = f.readByte(); + txtBuffer += Common::String::format(" %d", _animInfo[i]._frameList[id]._subFileId[frameId]); + } - debugC(6, kDebugEngine, "%d %d %d %d", _animInfo[i]._unkAnimArray[id]._field[0], _animInfo[i]._unkAnimArray[id]._field[1], _animInfo[i]._unkAnimArray[id]._field[2], _animInfo[i]._unkAnimArray[id]._field[3]); + debugC(6, kDebugEngine, txtBuffer.c_str()); } Common::String debugStr = ""; for (int id = 0; id < 10; ++id) { - _animInfo[i]._field3C_startY[id] = f.readByte(); - debugStr += Common::String::format("%d ", _animInfo[i]._field3C_startY[id]); + _animInfo[i]._posY[id] = f.readByte(); + debugStr += Common::String::format("%d ", _animInfo[i]._posY[id]); } - debugC(6, kDebugEngine, "%s", debugStr.c_str()); + debugC(6, kDebugEngine, debugStr.c_str()); debugStr = ""; for (int id = 0; id < 10; ++id) { - _animInfo[i]._field46_startX[id] = f.readUint16LE(); - debugStr += Common::String::format("%d ", _animInfo[i]._field46_startX[id]); + _animInfo[i]._posX[id] = f.readUint16LE(); + debugStr += Common::String::format("%d ", _animInfo[i]._posX[id]); } - debugC(6, kDebugEngine, "%s", debugStr.c_str()); + debugC(6, kDebugEngine, debugStr.c_str()); debugC(6, kDebugEngine, "---------"); } } @@ -144,16 +145,16 @@ void EfhEngine::readItems() { _items[i]._defense = f.readByte(); _items[i]._attacks = f.readByte(); _items[i]._uses = f.readByte(); - _items[i].field_13 = f.readByte(); + _items[i]._agilityModifier = f.readByte(); _items[i]._range = f.readByte(); _items[i]._attackType = f.readByte(); _items[i]._specialEffect = f.readByte(); - _items[i]._field17_attackTypeDefense = f.readByte(); + _items[i]._defenseType = f.readByte(); _items[i]._exclusiveType = f.readByte(); _items[i]._field19_mapPosX_or_maxDeltaPoints = f.readByte(); _items[i]._mapPosY = f.readByte(); - debugC(7, kDebugEngine, "%s\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x", _items[i]._name, _items[i]._damage, _items[i]._defense, _items[i]._attacks, _items[i]._uses, _items[i].field_13, _items[i]._range, _items[i]._attackType, _items[i]._specialEffect, _items[i]._field17_attackTypeDefense, _items[i]._exclusiveType, _items[i]._field19_mapPosX_or_maxDeltaPoints, _items[i]._mapPosY); + debugC(7, kDebugEngine, "%s\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x", _items[i]._name, _items[i]._damage, _items[i]._defense, _items[i]._attacks, _items[i]._uses, _items[i]._agilityModifier, _items[i]._range, _items[i]._attackType, _items[i]._specialEffect, _items[i]._defenseType, _items[i]._exclusiveType, _items[i]._field19_mapPosX_or_maxDeltaPoints, _items[i]._mapPosY); } } @@ -323,9 +324,8 @@ void EfhEngine::loadNPCS() { */ void EfhEngine::preLoadMaps() { Common::DumpFile dump; - if (ConfMan.getBool("dump_scripts")) { + if (ConfMan.getBool("dump_scripts")) dump.open("efhMaps.dump"); - } for (int idx = 0; idx < 19; ++idx) { Common::String fileName = Common::String::format("tech.%d", idx); @@ -345,16 +345,16 @@ void EfhEngine::preLoadMaps() { _mapSpecialTiles[idx][i]._placeId = mapSpecialTilePtr[9 * i]; _mapSpecialTiles[idx][i]._posX = mapSpecialTilePtr[9 * i + 1]; _mapSpecialTiles[idx][i]._posY = mapSpecialTilePtr[9 * i + 2]; - _mapSpecialTiles[idx][i]._field3 = mapSpecialTilePtr[9 * i + 3]; - _mapSpecialTiles[idx][i]._triggerId = mapSpecialTilePtr[9 * i + 4]; + _mapSpecialTiles[idx][i]._triggerType = mapSpecialTilePtr[9 * i + 3]; + _mapSpecialTiles[idx][i]._triggerValue = mapSpecialTilePtr[9 * i + 4]; _mapSpecialTiles[idx][i]._field5_textId = READ_LE_UINT16(&mapSpecialTilePtr[9 * i + 5]); _mapSpecialTiles[idx][i]._field7_textId = READ_LE_UINT16(&mapSpecialTilePtr[9 * i + 7]); if (ConfMan.getBool("dump_scripts") && _mapSpecialTiles[idx][i]._placeId != 0xFF) { // dump a decoded version of the maps - Common::String buffer = Common::String::format("[%d][%d] _ placeId: 0x%02X _pos: %d, %d _field3: 0x%02X (%d), triggerId: %d, _field5/7: %d %d\n" - , idx, i, _mapSpecialTiles[idx][i]._placeId, _mapSpecialTiles[idx][i]._posX, _mapSpecialTiles[idx][i]._posX, _mapSpecialTiles[idx][i]._field3 - , _mapSpecialTiles[idx][i]._field3, _mapSpecialTiles[idx][i]._triggerId, _mapSpecialTiles[idx][i]._field5_textId, _mapSpecialTiles[idx][i]._field7_textId); + Common::String buffer = Common::String::format("[%d][%d] _ placeId: 0x%02X _pos: %d, %d _triggerType: 0x%02X (%d), triggerId: %d, _field5/7: %d %d\n" + , idx, i, _mapSpecialTiles[idx][i]._placeId, _mapSpecialTiles[idx][i]._posX, _mapSpecialTiles[idx][i]._posX, _mapSpecialTiles[idx][i]._triggerType + , _mapSpecialTiles[idx][i]._triggerType, _mapSpecialTiles[idx][i]._triggerValue, _mapSpecialTiles[idx][i]._field5_textId, _mapSpecialTiles[idx][i]._field7_textId); dump.write(buffer.c_str(), buffer.size()); } } diff --git a/engines/efh/graphics.cpp b/engines/efh/graphics.cpp index 2ac0736e1b40..7460a660f3bb 100644 --- a/engines/efh/graphics.cpp +++ b/engines/efh/graphics.cpp @@ -79,10 +79,10 @@ void EfhEngine::displayAnimFrame() { displayRawDataAtPos(_portraitSubFilesArray[0], 16, 8); for (int i = 0; i < 4; ++i) { - int8 var2 = _animInfo[_animImageSetId]._unkAnimArray[_unkAnimRelatedIndex]._field[i]; + int8 var2 = _animInfo[_animImageSetId]._frameList[_unkAnimRelatedIndex]._subFileId[i]; if (var2 == -1) continue; - displayRawDataAtPos(_portraitSubFilesArray[var2 + 1], _animInfo[_animImageSetId]._field46_startX[var2] + 16, _animInfo[_animImageSetId]._field3C_startY[var2] + 8); + displayRawDataAtPos(_portraitSubFilesArray[var2 + 1], _animInfo[_animImageSetId]._posX[var2] + 16, _animInfo[_animImageSetId]._posY[var2] + 8); } } diff --git a/engines/efh/init.cpp b/engines/efh/init.cpp index cce48b89214f..448650c72018 100644 --- a/engines/efh/init.cpp +++ b/engines/efh/init.cpp @@ -45,22 +45,23 @@ void InvObject::init() { } void MapSpecialTileStruct::init() { - _placeId = _posX = _posY = _field3 = _triggerId = 0; + _placeId = _posX = _posY = _triggerType = _triggerValue = 0; _field5_textId = _field7_textId = 0; } -void UnkAnimStruct::init() { - memset(_field, 0, 4); +void FrameList::init() { + for (int i = 0; i < 4; ++i) + _subFileId[i] = -1; } void AnimInfo::init() { - for (int i = 0; i < 15; ++i) - _unkAnimArray[i].init(); - for (int i = 0; i < 10; ++i) { - _field3C_startY[i] = 0; - _field46_startX[i] = 0; + _posX[i] = 0; + _posY[i] = 0; } + + for (int i = 0; i < 15; ++i) + _frameList[i].init(); } void ItemStruct::init() { @@ -71,11 +72,11 @@ void ItemStruct::init() { _defense = 0; _attacks = 0; _uses = 0; - field_13 = 0; + _agilityModifier = 0; _range = 0; _attackType = 0; _specialEffect = 0; - _field17_attackTypeDefense = 0; + _defenseType = 0; _exclusiveType = 0; _field19_mapPosX_or_maxDeltaPoints = 0; _mapPosY = 0; diff --git a/engines/efh/menu.cpp b/engines/efh/menu.cpp index 61cd1fc3a3b3..a939521a0051 100644 --- a/engines/efh/menu.cpp +++ b/engines/efh/menu.cpp @@ -1038,7 +1038,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in displayStringInSmallWindowWithBorder("There is no apparent affect!", false, charId, teamMonsterId, menuId, curMenuLine); } else { _messageToBePrinted += " The magic sparkles brilliant hues in the air!"; - setMapMonsterAggressivenessAndMovementType(teamMonsterId, _items[itemId]._field17_attackTypeDefense); + setMapMonsterAggressivenessAndMovementType(teamMonsterId, _items[itemId]._defenseType); } objectUsedFl = true; break; @@ -1236,7 +1236,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in teamCharId = teamMonsterId; if (teamCharId != 0x1B) { - uint8 varAE = _items[itemId]._field17_attackTypeDefense; + uint8 varAE = _items[itemId]._defenseType; uint8 effectPoints = getRandom(_items[itemId]._field19_mapPosX_or_maxDeltaPoints); _npcBuf[_teamChar[teamCharId]._id]._activeScore[varAE] += effectPoints; if (_npcBuf[_teamChar[teamCharId]._id]._activeScore[varAE] > 20) { @@ -1266,7 +1266,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in teamCharId = teamMonsterId; if (teamCharId != 0x1B) { - uint8 varAE = _items[itemId]._field17_attackTypeDefense; + uint8 varAE = _items[itemId]._defenseType; uint8 effectPoints = getRandom(_items[itemId]._field19_mapPosX_or_maxDeltaPoints); _npcBuf[_teamChar[teamCharId]._id]._activeScore[varAE] -= effectPoints; if (_npcBuf[_teamChar[teamCharId]._id]._activeScore[varAE] > 20 || _npcBuf[_teamChar[teamCharId]._id]._activeScore[varAE] < 0) { @@ -1348,7 +1348,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in } if (teamCharId != 0x1B) { - int16 effectPoints = getRandom(_items[itemId]._field17_attackTypeDefense); + int16 effectPoints = getRandom(_items[itemId]._defenseType); _npcBuf[_teamChar[teamCharId]._id]._hitPoints += effectPoints; if (_npcBuf[_teamChar[teamCharId]._id]._hitPoints > _npcBuf[_teamChar[teamCharId]._id]._maxHP) _npcBuf[_teamChar[teamCharId]._id]._hitPoints = _npcBuf[_teamChar[teamCharId]._id]._maxHP; @@ -1378,7 +1378,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in } if (teamCharId != 0x1B) { - int16 effectPoints = getRandom(_items[itemId]._field17_attackTypeDefense); + int16 effectPoints = getRandom(_items[itemId]._defenseType); _npcBuf[_teamChar[teamCharId]._id]._hitPoints -= effectPoints; if (_npcBuf[_teamChar[teamCharId]._id]._hitPoints < 0) _npcBuf[_teamChar[teamCharId]._id]._hitPoints = 0; diff --git a/engines/efh/savegames.cpp b/engines/efh/savegames.cpp index b0045e64a8bb..33ab3d7fa29b 100644 --- a/engines/efh/savegames.cpp +++ b/engines/efh/savegames.cpp @@ -157,8 +157,8 @@ void EfhEngine::synchronize(Common::Serializer &s) { s.syncAsByte(_mapSpecialTiles[i][idx]._placeId); s.syncAsByte(_mapSpecialTiles[i][idx]._posX); s.syncAsByte(_mapSpecialTiles[i][idx]._posY); - s.syncAsByte(_mapSpecialTiles[i][idx]._field3); - s.syncAsByte(_mapSpecialTiles[i][idx]._triggerId); + s.syncAsByte(_mapSpecialTiles[i][idx]._triggerType); + s.syncAsByte(_mapSpecialTiles[i][idx]._triggerValue); s.syncAsUint16LE(_mapSpecialTiles[i][idx]._field5_textId); s.syncAsUint16LE(_mapSpecialTiles[i][idx]._field7_textId); } From c28da3a729c4df1b265e264f8595f7c94eaa5124 Mon Sep 17 00:00:00 2001 From: Eugene Sandulenko Date: Sun, 5 Feb 2023 21:33:55 +0100 Subject: [PATCH 290/412] EFH: Fix warnings --- engines/efh/efh.cpp | 14 +++++++------- engines/efh/files.cpp | 7 +++---- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 96850e94d6d7..5c167b68172a 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -50,7 +50,7 @@ int8 InvObject::getUsesLeft() { EfhEngine::~EfhEngine() { _mainSurface->free(); delete _mainSurface; - + delete _rnd; delete _graphicsStruct; delete _vgaGraphicsStruct1; @@ -467,7 +467,7 @@ void EfhEngine::initMapMonsters() { if (groupSize == 0) continue; - + for (uint counter = 0; counter < groupSize; ++counter) { uint rand100 = getRandom(100); uint16 pictureRef = kEncounters[curMons->_monsterRef]._pictureRef; @@ -484,7 +484,7 @@ void EfhEngine::initMapMonsters() { } void EfhEngine::loadMapArrays(int idx) { - // No longer required as everything is in memory. + // No longer required as everything is in memory. } void EfhEngine::saveAnimImageSetId() { @@ -495,7 +495,7 @@ void EfhEngine::saveAnimImageSetId() { } int16 EfhEngine::getEquipmentDefense(int16 charId) { - debugC(2, kDebugGraphics, "getEquipmentDefense %d %s", charId); + debugC(2, kDebugGraphics, "getEquipmentDefense %d", charId); int16 altDef = 0; @@ -1082,7 +1082,7 @@ int16 EfhEngine::findMapSpecialTileIndex(int16 posX, int16 posY) { debugC(5, kDebugEngine, "findMapSpecialTileIndex %d %d", posX, posY); uint16 searchPlaceId = _largeMapFlag ? 0xFE : _fullPlaceId; - + for (uint counter = 0; counter < 100; ++counter) { MapSpecialTileStruct *curTile = &_mapSpecialTiles[_techId][counter]; if (curTile->_posX == posX && curTile->_posY == posY && curTile->_placeId == searchPlaceId) @@ -2001,7 +2001,7 @@ void EfhEngine::displayImp1Text(int16 textId) { maxReached = false; stringIdx = 0; charCounter = 0; - uint8 firstChar = _messageToBePrinted.firstChar(); + uint8 firstChar = _messageToBePrinted.firstChar(); if (firstChar == 0x5E || firstChar == 0) { if (firstChar == 0x5E) { nextTextId = script_parse(_messageToBePrinted, 0, 0, 319, 199, true); @@ -2319,7 +2319,7 @@ bool EfhEngine::checkMonsterCollision() { continue; MapMonster *curMapMonst = &_mapMonsters[_techId][monsterId]; - + if (!(_largeMapFlag && curMapMonst->_fullPlaceId == 0xFE) && !(!_largeMapFlag && curMapMonst->_fullPlaceId == _fullPlaceId)) continue; diff --git a/engines/efh/files.cpp b/engines/efh/files.cpp index 3ab9ffa1ad4c..a5e87fbc8771 100644 --- a/engines/efh/files.cpp +++ b/engines/efh/files.cpp @@ -51,7 +51,7 @@ void EfhEngine::readAnimInfo() { txtBuffer += Common::String::format(" %d", _animInfo[i]._frameList[id]._subFileId[frameId]); } - debugC(6, kDebugEngine, txtBuffer.c_str()); + debugC(6, kDebugEngine, "%s", txtBuffer.c_str()); } Common::String debugStr = ""; @@ -59,14 +59,14 @@ void EfhEngine::readAnimInfo() { _animInfo[i]._posY[id] = f.readByte(); debugStr += Common::String::format("%d ", _animInfo[i]._posY[id]); } - debugC(6, kDebugEngine, debugStr.c_str()); + debugC(6, kDebugEngine, "%s", debugStr.c_str()); debugStr = ""; for (int id = 0; id < 10; ++id) { _animInfo[i]._posX[id] = f.readUint16LE(); debugStr += Common::String::format("%d ", _animInfo[i]._posX[id]); } - debugC(6, kDebugEngine, debugStr.c_str()); + debugC(6, kDebugEngine, "%s", debugStr.c_str()); debugC(6, kDebugEngine, "---------"); } } @@ -390,4 +390,3 @@ void EfhEngine::preLoadMaps() { } } // End of namespace Efh - From 650e0ce7a6db4ba3df12bf73d50cd4d8b6b4d411 Mon Sep 17 00:00:00 2001 From: Quote58 Date: Mon, 6 Jun 2022 16:50:13 -0400 Subject: [PATCH 291/412] IMMORTAL: Initial skeleton for Immortal engine --- engines/immortal/configure.engine | 3 + engines/immortal/credits.pl | 4 + engines/immortal/detection.cpp | 45 ++++++++++++ engines/immortal/detection.h | 62 ++++++++++++++++ engines/immortal/detection_tables.h | 43 +++++++++++ engines/immortal/immortal.cpp | 90 +++++++++++++++++++++++ engines/immortal/immortal.h | 110 ++++++++++++++++++++++++++++ engines/immortal/metaengine.cpp | 51 +++++++++++++ engines/immortal/metaengine.h | 43 +++++++++++ engines/immortal/module.mk | 16 ++++ 10 files changed, 467 insertions(+) create mode 100644 engines/immortal/configure.engine create mode 100644 engines/immortal/credits.pl create mode 100644 engines/immortal/detection.cpp create mode 100644 engines/immortal/detection.h create mode 100644 engines/immortal/detection_tables.h create mode 100644 engines/immortal/immortal.cpp create mode 100644 engines/immortal/immortal.h create mode 100644 engines/immortal/metaengine.cpp create mode 100644 engines/immortal/metaengine.h create mode 100644 engines/immortal/module.mk diff --git a/engines/immortal/configure.engine b/engines/immortal/configure.engine new file mode 100644 index 000000000000..835d5bdc5f61 --- /dev/null +++ b/engines/immortal/configure.engine @@ -0,0 +1,3 @@ +# This file is included from the main "configure" script +# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] +add_engine immortal "The Immortal" no "" "" "" diff --git a/engines/immortal/credits.pl b/engines/immortal/credits.pl new file mode 100644 index 000000000000..c9fc8d7affd6 --- /dev/null +++ b/engines/immortal/credits.pl @@ -0,0 +1,4 @@ +begin_section("Immortal"); + add_person("Michael Hayman", "Quote58", ""); + #add_person("Eugene ?", "JoeFish", ""); +end_section(); diff --git a/engines/immortal/detection.cpp b/engines/immortal/detection.cpp new file mode 100644 index 000000000000..3f3615cfe766 --- /dev/null +++ b/engines/immortal/detection.cpp @@ -0,0 +1,45 @@ +/* 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 "base/plugins.h" +#include "engines/advancedDetector.h" +#include "immortal/immortal.h" + +#include "common/config-manager.h" +#include "common/file.h" +#include "common/md5.h" +#include "common/str-array.h" +#include "common/translation.h" +#include "common/util.h" + +#include "immortal/detection.h" +#include "immortal/detection_tables.h" + +const DebugChannelDef ImmortalMetaEngineDetection::debugFlagList[] = { + { Immortal::kDebugTest, "Test", "Test debug channel" }, + DEBUG_CHANNEL_END +}; + +ImmortalMetaEngineDetection::ImmortalMetaEngineDetection() : AdvancedMetaEngineDetection(Immortal::gameDescriptions, + sizeof(ADGameDescription), Immortal::immortalGames) { +} + +REGISTER_PLUGIN_STATIC(IMMORTAL_DETECTION, PLUGIN_TYPE_ENGINE_DETECTION, ImmortalMetaEngineDetection); diff --git a/engines/immortal/detection.h b/engines/immortal/detection.h new file mode 100644 index 000000000000..fa4c3fcbf9a8 --- /dev/null +++ b/engines/immortal/detection.h @@ -0,0 +1,62 @@ +/* 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 . + * + */ + +#ifndef IMMORTAL_DETECTION_H +#define IMMORTAL_DETECTION_H + +#include "engines/advancedDetector.h" + +namespace Immortal { + +enum ImmortalDebugChannels { + kDebugTest = 1 << 0 +}; + +extern const PlainGameDescriptor immortalGames[]; +extern const ADGameDescription gameDescriptions[]; + +} // namespace Immortal + +class ImmortalMetaEngineDetection : public AdvancedMetaEngineDetection { + static const DebugChannelDef debugFlagList[]; + +public: + ImmortalMetaEngineDetection(); + ~ImmortalMetaEngineDetection() override {} + + const char *getName() const override { + return "immortal"; + } + + const char *getEngineName() const override { + return "The Immortal"; + } + + const char *getOriginalCopyright() const override { + return "(c)1990 Will Harvey & Electronic Arts"; + } + + const DebugChannelDef *getDebugChannels() const override { + return debugFlagList; + } +}; + +#endif diff --git a/engines/immortal/detection_tables.h b/engines/immortal/detection_tables.h new file mode 100644 index 000000000000..d1d9bfcd430a --- /dev/null +++ b/engines/immortal/detection_tables.h @@ -0,0 +1,43 @@ +/* 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 . + * + */ + +namespace Immortal { + +const PlainGameDescriptor immortalGames[] = { + { "immortal", "The Immortal" }, + { 0, 0 } +}; + +const ADGameDescription gameDescriptions[] = { + { + "immortal", + nullptr, + AD_ENTRY1s("IMMORTAL.dsk", "094941fd71e6d2cdaa96c9664d32329e", 819200), + Common::EN_ANY, + Common::kPlatformApple2GS, + ADGF_UNSTABLE, + GUIO1(GUIO_NONE) + }, + + AD_TABLE_END_MARKER +}; + +} // namespace Immortal diff --git a/engines/immortal/immortal.cpp b/engines/immortal/immortal.cpp new file mode 100644 index 000000000000..b5c664242d84 --- /dev/null +++ b/engines/immortal/immortal.cpp @@ -0,0 +1,90 @@ +/* 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 "immortal/immortal.h" +#include "immortal/detection.h" + +#include "common/scummsys.h" +#include "common/config-manager.h" +#include "common/debug-channels.h" +#include "common/events.h" +#include "common/system.h" +#include "common/debug.h" +#include "common/debug-channels.h" +#include "common/error.h" + +#include "engines/util.h" +#include "audio/mixer.h" + +#include "graphics/palette.h" +#include "graphics/surface.h" + +namespace Immortal { + +ImmortalEngine *g_engine; + +ImmortalEngine::ImmortalEngine(OSystem *syst, const ADGameDescription *gameDesc) + : Engine(syst) + , _gameDescription(gameDesc) + , _randomSource("Immortal") { + g_engine = this; + debug("ImmortalEngine::ImmortalEngine"); +} + +ImmortalEngine::~ImmortalEngine() { + debug("ImmortalEngine::~ImmortalEngine"); +} + +uint32 ImmortalEngine::getFeatures() const { + return _gameDescription->flags; +} + +Common::String ImmortalEngine::getGameId() const { + return _gameDescription->gameId; +} + +Common::Error ImmortalEngine::run() { + initGraphics(320, 200); + + while (!shouldQuit()) { + int64 loopStart = g_system->getMillis(); + + int64 loopEnd = 16 - (g_system->getMillis() - loopStart); + if (loopEnd > 0) + g_system->delayMillis(loopEnd); + } + + return Common::kNoError; + +} + +Common::Error ImmortalEngine::syncGame(Common::Serializer &s) { + // The Serializer has methods isLoading() and isSaving() + // if you need to specific steps; for example setting + // an array size after reading it's length, whereas + // for saving it would write the existing array's length + int dummy = 0; + s.syncAsUint32LE(dummy); + + return Common::kNoError; +} + +} // namespace Immortal diff --git a/engines/immortal/immortal.h b/engines/immortal/immortal.h new file mode 100644 index 000000000000..291cbc93def5 --- /dev/null +++ b/engines/immortal/immortal.h @@ -0,0 +1,110 @@ +/* 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 . + * + */ + +#ifndef IMMORTAL_IMMORTAL_H +#define IMMORTAL_IMMORTAL_H + +#include "audio/mixer.h" + +#include "common/scummsys.h" +#include "common/system.h" +#include "common/error.h" +#include "common/fs.h" +#include "common/hash-str.h" +#include "common/random.h" +#include "common/serializer.h" +#include "common/util.h" +#include "common/platform.h" + +#include "engines/engine.h" +#include "engines/savestate.h" +#include "graphics/screen.h" + +#include "immortal/detection.h" + +namespace Immortal { + +struct ImmortalGameDescription; + +class ImmortalEngine : public Engine { +private: + Common::RandomSource _randomSource; +protected: + // Engine APIs + Common::Error run() override; +public: + const ADGameDescription *_gameDescription; + +public: + ImmortalEngine(OSystem *syst, const ADGameDescription *gameDesc); + ~ImmortalEngine() override; + + uint32 getFeatures() const; + + /** + * Returns the game Id + */ + Common::String getGameId() const; + + /** + * Gets a random number + */ + uint32 getRandomNumber(uint maxNum) { + return _randomSource.getRandomNumber(maxNum); + } + + bool hasFeature(EngineFeature f) const override { + return + (f == kSupportsLoadingDuringRuntime) || + (f == kSupportsSavingDuringRuntime) || + (f == kSupportsReturnToLauncher); + }; + + bool canLoadGameStateCurrently() override { + return true; + } + bool canSaveGameStateCurrently() override { + return true; + } + + /** + * Uses a serializer to allow implementing savegame + * loading and saving using a single method + */ + Common::Error syncGame(Common::Serializer &s); + + /* Common::Error saveGameStream(Common::WriteStream *stream, bool isAutosave = false) { + Common::Serializer s(nullptr, stream); + return syncGame(s); + } */ + + /* Common::Error loadGameStream(Common::SeekableReadStream *stream) { + Common::Serializer s(stream, nullptr); + return syncGame(s); + } */ +}; + +extern ImmortalEngine *g_engine; +#define SHOULD_QUIT ::Immortal::g_engine->shouldQuit() + +} // namespace Immortal + +#endif diff --git a/engines/immortal/metaengine.cpp b/engines/immortal/metaengine.cpp new file mode 100644 index 000000000000..b736f5f80424 --- /dev/null +++ b/engines/immortal/metaengine.cpp @@ -0,0 +1,51 @@ +/* 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 "immortal/metaengine.h" +#include "immortal/detection.h" +#include "immortal/immortal.h" + +const char *ImmortalMetaEngine::getName() const { + return "immortal"; +} + +Common::Error ImmortalMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const { + *engine = new Immortal::ImmortalEngine(syst, desc); + return Common::kNoError; +} + +bool ImmortalMetaEngine::hasFeature(MetaEngineFeature f) const { + return false; +/* return + (f == kSavesUseExtendedFormat) || + (f == kSimpleSavesNames) || + (f == kSupportsListSaves) || + (f == kSupportsDeleteSave) || + (f == kSavesSupportMetaInfo) || + (f == kSavesSupportThumbnail) || + (f == kSupportsLoadingDuringStartup); */ +} + +#if PLUGIN_ENABLED_DYNAMIC(IMMORTAL) +REGISTER_PLUGIN_DYNAMIC(IMMORTAL, PLUGIN_TYPE_ENGINE, ImmortalMetaEngine); +#else +REGISTER_PLUGIN_STATIC(IMMORTAL, PLUGIN_TYPE_ENGINE, ImmortalMetaEngine); +#endif diff --git a/engines/immortal/metaengine.h b/engines/immortal/metaengine.h new file mode 100644 index 000000000000..cb80691c010e --- /dev/null +++ b/engines/immortal/metaengine.h @@ -0,0 +1,43 @@ +/* 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 . + * + */ + +#ifndef IMMORTAL_METAENGINE_H +#define IMMORTAL_METAENGINE_H + +#include "base/plugins.h" +#include "engines/achievements.h" +#include "engines/advancedDetector.h" + +class ImmortalMetaEngine : public AdvancedMetaEngine { +public: + const char *getName() const override; + + Common::Error createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const override; + + /** + * Determine whether the engine supports the specified MetaEngine feature. + * + * Used by e.g. the launcher to determine whether to enable the Load button. + */ + bool hasFeature(MetaEngineFeature f) const override; +}; + +#endif diff --git a/engines/immortal/module.mk b/engines/immortal/module.mk new file mode 100644 index 000000000000..a0aa13f38418 --- /dev/null +++ b/engines/immortal/module.mk @@ -0,0 +1,16 @@ +MODULE := engines/immortal + +MODULE_OBJS = \ + immortal.o \ + metaengine.o + +# This module can be built as a plugin +ifeq ($(ENABLE_IMMORTAL), DYNAMIC_PLUGIN) +PLUGIN := 1 +endif + +# Include common rules +include $(srcdir)/rules.mk + +# Detection objects +DETECT_OBJS += $(MODULE)/detection.o From 4c30f057331df05e5d5f481e9eae781b36b7002c Mon Sep 17 00:00:00 2001 From: Quote58 Date: Fri, 17 Jun 2022 23:00:33 -0400 Subject: [PATCH 292/412] IMMORTAL: ProDos disk file support with implementation of Archive --- engines/immortal/disk.cpp | 462 +++++++++++++++++++++++++++++++++++++ engines/immortal/disk.h | 250 ++++++++++++++++++++ engines/immortal/module.mk | 1 + 3 files changed, 713 insertions(+) create mode 100644 engines/immortal/disk.cpp create mode 100644 engines/immortal/disk.h diff --git a/engines/immortal/disk.cpp b/engines/immortal/disk.cpp new file mode 100644 index 000000000000..35f516a95826 --- /dev/null +++ b/engines/immortal/disk.cpp @@ -0,0 +1,462 @@ +/* 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/debug.h" +#include "common/file.h" + +#include "immortal/immortal.h" +#include "immortal/disk.h" + +namespace Immortal { + +// --- ProDosFile methods --- + +ProDosFile::ProDosFile(char name[15], uint8 type, uint16 tBlk, uint32 eof, uint16 bPtr, Common::File *disk) + : _type(type) + , _totalBlocks(tBlk) + , _eof(eof) + , _blockPtr(bPtr) + , _disk(disk) { + strcpy(_name, name); + } + +/* For debugging purposes, this prints the meta data of a file */ + +void ProDosFile::printInfo() { + debug("File: %s", _name); + debug("Type: %02X", _type); + debug("Blocks: %d", _totalBlocks); + debug("Size: %u", _eof); + debug(""); +} + +/* For Common::Archive, this method just returns a string of the name */ + +Common::String ProDosFile::getName() const { + return Common::String(_name); +} + +/* This method is used to get a single block of data from the disk, + * but is not strictly 512 bytes. This is so that it can get only what + * it needs when in the final block. It then adds it into the allocated + * memory starting at memOffset + */ + +void ProDosFile::getDataBlock(byte *memOffset, int offset, int size) const { + + // All this method needs to do is read (size) of data at (offset) into (memOffset) + _disk->seek(offset); + _disk->read(memOffset, size); +} + +/* To put together a sapling file, you need to loop through the index + * block, adding to the file data one block at a time. This method also + * returns the size of data it got, just to make it a little simpler to + * determine the new position within the byte data. + */ + +int ProDosFile::parseIndexBlock(byte *memOffset, int blockNum, int rem) const { + int dataSize; // For most of the blocks, this will be kBlockSize, but the last one will be the calculated remainder + int readSize = 0; // This keeps track of the new pointer position to read data to, by updating the size of data read last + int dataOffset; // Where in the disk to read from + int diskPos; // Current position of cursor + + for (int i = 0; i < blockNum; i++) { + dataSize = (i == (blockNum - 1)) ? rem : ProDosDisk::kBlockSize; + dataOffset = _disk->readByte(); // Low byte is first + + /* The cursor needs to know where to get the next pointer from in the index block, + * but it also needs to jump to the offset of data to read it, so we need to preserve + * the position in the index block it was in before. + */ + diskPos = _disk->pos(); + + _disk->skip(255); // The high bytes are stored at the end of the block instead because reasons??? + dataOffset += (_disk->readByte() << 8) * ProDosDisk::kBlockSize; // High byte is second + + getDataBlock(memOffset + readSize, dataOffset, dataSize); + readSize += dataSize; + + // And now we resume the position before this call + _disk->seek(diskPos); + } + return readSize; +} + +/* Extracting file data is a little tricky, as the blocks are spread out in the disk. There are 3 types + * of regular files. Seed, Sapling, and Tree. A Seed file only needs a single data block, while a + * Sapling needs an index block to manage up to 256 data blocks, and a Tree file needs an index block + * to manage up to 128 (only uses half the block) index blocks. This is also an Archive method as it + * returns a read stream of the file contents. + */ + +Common::SeekableReadStream *ProDosFile::createReadStream() const { + + // We know the total byte size of the data, so we can allocate the full amount right away + byte *finalData = (byte *)malloc(_eof); + + /* For a seed, this is a direct pointer to data. For a sapling it is an index file, + * and for a tree it is a master index file. + */ + int indexBlock = _blockPtr * ProDosDisk::kBlockSize; + + /* For a sapling or tree, the size needs to be calculated, as they are made from multiple blocks. + * _totalBlocks *includes* the index block, so the blocks before the oef block are _totalBlocks-2 + */ + int remainder = _eof - ((_totalBlocks - 2) * ProDosDisk::kBlockSize); + + // For a seed file, the end of file value is also the size in the block, because it's just the one block + if (_type == kFileTypeSeed) { + getDataBlock(finalData, indexBlock, _eof); + + } else if (_type == kFileTypeSapling) { + _disk->seek(indexBlock); + parseIndexBlock(finalData, _totalBlocks - 1, remainder); + + } else { + // If it's not a seed and not a sapling, it's a tree. + _disk->seek(indexBlock); + + /* A sapling can have an index block of up to 256, so if it is a tree, + * that means it has more than 256 blocks + */ + int indexNum = (_totalBlocks - 1) / 256; + int indexNumR = (_totalBlocks - 1) % 256; + + /* However, to know how many index blocks there are, we need to know the remainder + * so we can figure out if it's ex. 2 index blocks, or 2 and some portion of a 3rd + */ + indexNum += indexNumR; + int blockNum; + int indexOffset; + int readSize = 0; + + // Now we can loop through the master index file, parsing the individual index files similar to a sapling + for (int i = 0; i < indexNum; i++) { + blockNum = (i == indexNum - 1) ? indexNumR : 256; + + indexOffset = _disk->readByte(); + int diskPos = _disk->pos(); + + _disk->skip(255); + indexOffset += (_disk->readByte() << 8) * ProDosDisk::kBlockSize; + + _disk->seek(indexOffset); + readSize += parseIndexBlock(finalData + readSize, blockNum, remainder); + + _disk->seek(diskPos); + } + } + return new Common::MemoryReadStream(finalData, _eof, DisposeAfterUse::YES); +} + +// --- ProDosDisk methods --- + +/* The time and date are compressed into 16bit words, so to make them useable + * we have to decompress them by masking the other bits and then shifting + * to the lowest bit so that they can be stored in 8 bits each. + */ + +void ProDosDisk::getDate(Date *d, uint16 date) { + d->_day = date & 0x001f; + d->_month = (date & 0x01e0) >> 5; + d->_year = (date & 0xfe00) >> 9; +} + +void ProDosDisk::getTime(Time *t, uint16 time) { + t->_minute = time & 0x003f; + t->_hour = (time & 0x1f00) >> 8; +} + +/* Adds most of the header data to a directory header struct */ + +void ProDosDisk::getHeader(DirHeader *h) { + + /* The type and nameLen fields are stored in the same byte, + * so we need to split the byte, and shift the high bits to + * make it readable as an int + */ + uint8 tempByte = _disk.readByte(); + h->_nameLen = tempByte & 0xf; + h->_type = (tempByte & 0xf0) >> 4; + + // The name field is stored in 15 bytes with no null character (aside from unused chars being 00) + _disk.read(h->_name, 15); + _disk.read(h->_reserved, 8); + + // The time and date can be decompressed into structs right away + getDate(&(h->_date), _disk.readUint16LE()); + getTime(&(h->_time), _disk.readUint16LE()); + + h->_ver = _disk.readByte(); + h->_minVer = _disk.readByte(); + h->_access = _disk.readByte(); + h->_entryLen = _disk.readByte(); + h->_entriesPerBlock = _disk.readByte(); + h->_fileCount = _disk.readUint16LE(); +} + +/* Since a subdirectory header is mostly the same a volume header, we will reuse the code where we can */ + +void ProDosDisk::getDirectoryHeader(DirHeader *h) { + getHeader(h); + h->_parentBlockPtr = _disk.readUint16LE(); + h->_parentEntryIndex = _disk.readByte(); + h->_parentEntryLen = _disk.readUint16LE(); +} + +/* This is a little sneaky, but since the bulk of the header is the same, we're just going to pretend the volume header + * is a directory header for the purose of filling it out with the same code + */ + +void ProDosDisk::getVolumeHeader(VolHeader *h) { + getHeader((DirHeader *)h); + h->_bitmapPtr = _disk.readUint16LE(); + h->_volBlocks = _disk.readUint16LE(); + _volBlocks = h->_volBlocks; +} + +/* Getting a file entry header is very similar to getting a header, but with different data. */ + +void ProDosDisk::getFileEntry(FileEntry *f) { + uint8 tempByte = _disk.readByte(); + f->_nameLen = tempByte & 0xf; + f->_type = (tempByte & 0xf0) >> 4; + + _disk.read(f->_name, 15); + f->_ext = _disk.readByte(); + f->_blockPtr = _disk.readUint16LE(); + f->_totalBlocks = _disk.readUint16LE(); + + // The file size in bytes is stored as a long (3 bytes), lowest to highest + f->_eof = _disk.readByte() + (_disk.readByte() << 8) + (_disk.readByte() << 16); + + getDate(&(f->_date), _disk.readUint16LE()); + getTime(&(f->_time), _disk.readUint16LE()); + + f->_ver = _disk.readByte(); + f->_minVer = _disk.readByte(); + f->_access = _disk.readByte(); + f->_varUse = _disk.readUint16LE(); + + getDate(&(f->_modDate), _disk.readUint16LE()); + getTime(&(f->_modTime), _disk.readUint16LE()); + + f->_dirHeadPtr = _disk.readUint16LE(); +} + +/* This is basically a loop based on the number of total files indicated by the header (including deleted file entries), + * which parses the file entry, and if it is a regular file (ie. active and not a pascal area) then it will create a file object. + * If it is instead a subdirectory file entry, it will use this same function to search in that directory creating files + * and continue like that until all directories have been explored. Along the way it puts together the current file path, + * which is stored with the file object so that the engine can search by path name. + */ + +void ProDosDisk::searchDirectory(DirHeader *h, uint16 p, uint16 n, Common::String path) { + int currPos; + int parsedFiles = 0; + + for (int i = 0; i < h->_fileCount; i++) { + + // When we have read all the files for a given block (_entriesPerBlock), we need to change to the next block of the directory + if (parsedFiles > h->_entriesPerBlock) { + parsedFiles = 0; + _disk.seek(n * kBlockSize); + p = _disk.readUint16LE(); + n = _disk.readUint16LE(); + } + + FileEntry fileEntry; + getFileEntry(&fileEntry); + + parsedFiles++; + currPos = _disk.pos(); + + // It is a regular file if (dead < file type < pascal) and the file has a size + if ((kFileTypeDead < fileEntry._type) && (fileEntry._type < kFileTypePascal) && (fileEntry._eof > 0)) { + char cString[16]; + for (int j = 0; j < 15; j++) { + cString[j] = fileEntry._name[j]; + } + cString[15] = 0; + Common::String fileName = path + cString; + debug("%s", fileName.c_str()); + //debug("%s", fileName.c_str()); + ProDosFile *currFile = new ProDosFile(fileEntry._name, fileEntry._type, fileEntry._totalBlocks, fileEntry._eof, fileEntry._blockPtr, &_disk); + //debug("%s", currFile._name); + currFile->printInfo(); + + _files.setVal(fileName, Common::SharedPtr(currFile)); + _disk.seek(currPos); + + // Otherwise, if it is a subdirectory, we want to explore that subdirectory + } else if (fileEntry._type == kFileTypeSubDir) { + + _disk.seek(fileEntry._blockPtr * kBlockSize); + debug("--- diving into a subdirectory ---"); + + uint16 subP = _disk.readUint16LE(); + uint16 subN = _disk.readUint16LE(); + DirHeader subHead; + getDirectoryHeader(&subHead); + + path += Common::String(subHead._name); + path += '/'; + searchDirectory(&subHead, subP, subN, path); + + debug("--- surfacing to parent directory ---"); + _disk.seek(currPos); + } + } +} + +/* This just gets the volume bitmap by finding out how many blocks it takes up and then adding them to vector of the data. */ + +void ProDosDisk::getVolumeBitmap(VolHeader *h) { + int currPos = _disk.pos(); + _disk.seek(h->_bitmapPtr * kBlockSize); + int bitmapNum = 1; + if (_volBlocks >= 4096) { + bitmapNum = _volBlocks / 4096; + } + for (int i = 0; i < bitmapNum; i++) { + byte bitmapData[512]; + _disk.read(bitmapData, kBlockSize); + Common::Array volBitmapBlock = Common::Array(kBlockSize); + for (int j = 0; j < kBlockSize; j++) { + volBitmapBlock[j] = bitmapData[j]; + } + _volBitmap.push_back(volBitmapBlock); + } + _disk.seek(currPos); +} + +/* Gets the volume information and parses the filesystem, adding file objects to a map as it goes */ + +bool ProDosDisk::open(const Common::String filename) { + debug("opening %s", filename.c_str()); + + _disk.open(filename); + _disk.read(_loader1, kBlockSize); + _disk.read(_loader2, kBlockSize); + + uint16 prev = _disk.readUint16LE(); // This is always going to be 0 for the volume header, but there's also no reason to skip it + uint16 next = _disk.readUint16LE(); + + VolHeader header; + getVolumeHeader(&header); + debug("volume name: %s", header._name); + debug("volume created %d/%d/19%d", header._date._day, header._date._month, header._date._year); + + getVolumeBitmap(&header); + + Common::String pathName; // This is so that the path name starts blank, and then for every directory searched it adds the directory name to the path + searchDirectory((DirHeader *)&header, prev, next, pathName); + + return true; // When I get to error checking on this, the bool will be useful +} + +/* Constructor simply calls open(), and if it is successful it prints a statement */ + +ProDosDisk::ProDosDisk(const Common::String filename) { + if (open(filename)) { + debug ("%s has been loaded", filename.c_str()); + } +} + +/* Destructor closes the disk and clears the map of files */ + +ProDosDisk::~ProDosDisk() { + _disk.close(); + _files.clear(); +} + +// --- Common::Archive methods --- + +bool ProDosDisk::hasFile(const Common::Path &path) const { + Common::String name = path.toString(); + return _files.contains(name); +} + +int ProDosDisk::listMembers(Common::ArchiveMemberList &list) const { + int f = 0; + Common::HashMap>::const_iterator it; + for (it = _files.begin(); it != _files.end(); ++it) { + list.push_back(Common::ArchiveMemberList::value_type(it->_value)); + ++f; + } + return f; +} + +const Common::ArchiveMemberPtr ProDosDisk::getMember(const Common::Path &path) const { + Common::String name = path.toString(); + if (!_files.contains(name)) { + return Common::ArchiveMemberPtr(); + } + return _files.getValOrDefault(name); +} + +Common::SeekableReadStream *ProDosDisk::createReadStreamForMember(const Common::Path &path) const { + Common::String name = path.toString(); + Common::SharedPtr f = _files.getValOrDefault(name); + return f->createReadStream(); +} + +} // namespace Immortal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/engines/immortal/disk.h b/engines/immortal/disk.h new file mode 100644 index 000000000000..bc173ec3bf5b --- /dev/null +++ b/engines/immortal/disk.h @@ -0,0 +1,250 @@ +/* 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 . + * + */ + +#ifndef IMMORTAL_DSK_H +#define IMMORTAL_DSK_H + +#include "common/memstream.h" +#include "common/file.h" +#include "common/debug.h" + +/* Quick note about ProDos: + * This disk code handles inactive, seedling, sapling, tree, and subdirectory files. + * It does *not* handle sparse files at the moment. If a sparse file exists, it may not + * be read correctly. It also does not do anything with Pascal files, but those should not + * matter for game engines anyway. + */ + +/* There is also one thing that currently has an error. If a file size is the full 15 chars, + * it seems to add a char of some kind to the end and can't be looked up by that value. + * Probably just a difference in string encoding that I need to sort out + */ + +namespace Immortal { + +// These values define for ProDos how to read the file entry, and also whether it's a keyblock (if it is a directory header, it's the keyblock of that directory) +enum FileType : char { + kFileTypeDead = 0, + kFileTypeSeed = 1, + kFileTypeSapling = 2, + kFileTypeTree = 3, + kFileTypePascal = 4, + kFileTypeSubDir = 0x0D, + kFileTypeSubHead = 0x0E, + kFileTypeVolHead = 0x0F +}; + +/* File extensions for all the ProDos supported file types + * NOTE: ProDos user defined files are F1-F8. If they are ever required, + * they can be added to this enum. + */ +enum FileExt { + kFileExtNull = 0, + kFileExtBad = 1, + kFileExtTxt = 4, + kFileExtBin = 6, + kFileExtGfx = 8, + kFileExtDir = 0xF, + kFileExtDB = 0x19, + kFileExtWord = 0x1A, + kFileExtSpread = 0x1B, + kFileExtPascal = 0xEF, + kFileExtPDCI = 0xF0, + kFileExtPDRes = 0xF9, + kFileExtIBProg = 0xFA, + kFileExtIBVar = 0xFB, + kFileExtAPSProg = 0xFC, + kFileExtAPSVar = 0xFD, + kFileExtEDASM = 0xFE, + kFileExtPDSys = 0xFF +}; + +/* A ProDos file simply contains meta data about the file and the ability to + * find and put together the data blocks that make up the file contents. + * This implements Common::ArchiveMember so that it can be used directly in + * the Archive methods in ProDosDisk. + */ + +class ProDosFile : public Common::ArchiveMember { +public: + ProDosFile(char name[15], uint8 type, uint16 tBlk, uint32 eof, uint16 bPtr, Common::File *disk); + ~ProDosFile() {}; + + // These are the Common::ArchiveMember related functions + Common::String getName() const override; + Common::SeekableReadStream *createReadStream() const override; + void getDataBlock(byte *memOffset, int offset, int size) const; + int parseIndexBlock(byte *memOffset, int blockNum, int cSize) const; + void printInfo(); + +private: + char _name[15]; + uint8 _type; + uint16 _blockPtr; + uint16 _totalBlocks; + uint32 _eof; + Common::File *_disk; +}; + +/* This class defines the entire disk volume. Upon using the open() method, + * it will parse the volume and add them to a hashmap where the file path + * returns a file object. This implements Common::Archive to allow regular + * file operations to work with it. + */ + +class ProDosDisk : public Common::Archive { +public: + static const int kBlockSize = 512; // A ProDos block is always 512 bytes + + ProDosDisk(const Common::String filename); + ~ProDosDisk(); + + // Called from the constructor, parses the volume and fills the hashmap with files + bool open(const Common::String filename); + + // These are the Common::Archive related methods + bool hasFile(const Common::Path &path) const override; + int listMembers(Common::ArchiveMemberList &list) const override; + const Common::ArchiveMemberPtr getMember(const Common::Path &path) const override; + Common::SeekableReadStream *createReadStreamForMember(const Common::Path &path) const override; + +private: + byte _loader1[512]; // There's no reason these would be needed, but why not include them just in case + byte _loader2[512]; +Common::String _name; // Name of volume + Common::File _disk; // The volume file itself + int _volBlocks; // Total blocks in volume + +Common::Array _volBitmap; // Not super useful, but could be used with _totalBlocks to check whether the disk is corrupted +Common::HashMap> _files; // Hashmap of files in the volume, where key=Path, Value=ProDosFile + + struct Date { + uint8 _day; + uint8 _month; + uint8 _year; + }; + + struct Time { + uint8 _hour; + uint8 _minute; + }; + + struct VolHeader { + uint8 _type; // Not really important for a volume header, as this will always be F + uint8 _nameLen; + char _name[15]; + byte _reserved[8]; // Extra space reserved for possible future uses, not important + Date _date; + Time _time; + uint8 _ver; + uint8 _minVer; // Should pretty much always be 0 as far as I know + uint8 _access; // If this ends up useful, there should be an enum for the access values + uint8 _entryLen; // Always 27 in ProDos 1.0 + uint8 _entriesPerBlock; // Always 0D in ProDos 1.0 + uint16 _fileCount; // Number of files across all data blocks in this directory + uint16 _bitmapPtr; // Block pointer to the keyblock of the bitmap for the entire volume + uint16 _volBlocks; // Blocks in entire volume + }; + + struct DirHeader { + uint8 _type; + uint8 _nameLen; + char _name[15]; + byte _reserved[8]; + Date _date; + Time _time; + uint8 _ver; + uint8 _minVer; + uint8 _access; + uint8 _entryLen; + uint8 _entriesPerBlock; + uint16 _fileCount; + uint16 _parentBlockPtr; // These values allow ProDos to navigate back out of a directory, but they aren't really needed by the class to navigate + uint8 _parentEntryIndex; // Index in the current directory + uint8 _parentEntryLen; // This is always 27 in ProDos 1.0 + }; + + struct FileEntry { + uint8 _type; // 0 = inactive, 1-3 = file, 4 = pascal area, 14 = subdirectory, 15 = volume directory + uint8 _nameLen; + char _name[15]; + uint8 _ext; // File extension, uses the enum FileExt + uint16 _blockPtr; // Block pointer to data for seedling, index block for sapling, or master block for tree + uint16 _totalBlocks; // Really important to remember this is the total *including* the index block + uint32 _eof; // This is a long (3 bytes, read low to high) value representing the total readable data in a file (unless it's a sparse file, be careful!) + Date _date; + Time _time; + uint8 _ver; + uint8 _minVer; + uint8 _access; + uint16 _varUse; + Date _modDate; + Time _modTime; + uint16 _dirHeadPtr; // Pointer to the key block of the directory that contains this file entry + }; + + void getDate(Date *d, uint16 date); // Decompresses the date into a struct + void getTime(Time *t, uint16 time); // Decompresses the time into a struct + void getHeader(DirHeader *h); // Adds the main header values to the struct + void getDirectoryHeader(DirHeader *h); // Uses getHeader and then fills in the values for the parent directory + void getVolumeHeader(VolHeader *dir); // Uses getHeader and then fills in the volume related information (there is no parent directory to this one) + void getFileEntry(FileEntry *f); // Adds all of the file entry information to the struct + void searchDirectory(DirHeader *h, uint16 p, uint16 n, Common::String path); // Recursively searches all files within a directory, and dives into subdirectories to search them as well + void getVolumeBitmap(VolHeader *h); // Puts together the volume bitmap +}; + + +} // namespace Immortal + +#endif + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/engines/immortal/module.mk b/engines/immortal/module.mk index a0aa13f38418..684f8af133cf 100644 --- a/engines/immortal/module.mk +++ b/engines/immortal/module.mk @@ -2,6 +2,7 @@ MODULE := engines/immortal MODULE_OBJS = \ immortal.o \ + disk.o \ metaengine.o # This module can be built as a plugin From 9b7f4f37683254901f06fe0eeaecd0a560284f46 Mon Sep 17 00:00:00 2001 From: Quote58 Date: Fri, 17 Jun 2022 23:15:25 -0400 Subject: [PATCH 293/412] IMMORTAL: Add disk archive object to SearchMan --- engines/immortal/immortal.cpp | 42 +++++++++++++++++++++++++++++++++++ engines/immortal/immortal.h | 2 ++ 2 files changed, 44 insertions(+) diff --git a/engines/immortal/immortal.cpp b/engines/immortal/immortal.cpp index b5c664242d84..ffa043232924 100644 --- a/engines/immortal/immortal.cpp +++ b/engines/immortal/immortal.cpp @@ -21,6 +21,7 @@ #include "immortal/immortal.h" #include "immortal/detection.h" +#include "immortal/disk.h" #include "common/scummsys.h" #include "common/config-manager.h" @@ -30,6 +31,7 @@ #include "common/debug.h" #include "common/debug-channels.h" #include "common/error.h" +#include "common/file.h" #include "engines/util.h" #include "audio/mixer.h" @@ -46,6 +48,10 @@ ImmortalEngine::ImmortalEngine(OSystem *syst, const ADGameDescription *gameDesc) , _gameDescription(gameDesc) , _randomSource("Immortal") { g_engine = this; + + const Common::FSNode gameDataDir(ConfMan.get("path")); + SearchMan.addSubDirectoryMatching(gameDataDir, "game"); + debug("ImmortalEngine::ImmortalEngine"); } @@ -64,8 +70,44 @@ Common::String ImmortalEngine::getGameId() const { Common::Error ImmortalEngine::run() { initGraphics(320, 200); + if (SearchMan.hasFile("IMMORTAL.dsk")) { + ProDosDisk *diskBoot = new ProDosDisk("IMMORTAL.dsk"); + if (diskBoot) { + debug("Boot disk found"); + SearchMan.add("IMMORTAL.dsk", diskBoot, 0, true); + } + } + + if (SearchMan.hasFile("IMMORTAL_GFX.dsk")) { + ProDosDisk *diskGFX = new ProDosDisk("IMMORTAL_GFX.dsk"); + if (diskGFX) { + debug("Gfx disk found"); + SearchMan.add("IMMORTAL_GFX.dsk", diskGFX, 0, true); + } + } + + Common::File f; + if (!f.open("LOAD.OBJ")) { + debug("oh no :("); + } + + debug("first file loaded"); + f.close(); + + Common::File f2; + if (!f2.open("GOBLIN.SPR")) { + debug("oh no :(("); + } + + debug("second file loaded"); + f2.close(); + + while (!shouldQuit()) { + int64 loopStart = g_system->getMillis(); + Common::Event event; + g_system->getEventManager()->pollEvent(event); int64 loopEnd = 16 - (g_system->getMillis() - loopStart); if (loopEnd > 0) diff --git a/engines/immortal/immortal.h b/engines/immortal/immortal.h index 291cbc93def5..fc64b0f2f732 100644 --- a/engines/immortal/immortal.h +++ b/engines/immortal/immortal.h @@ -43,10 +43,12 @@ namespace Immortal { struct ImmortalGameDescription; +class ProDosDisk; class ImmortalEngine : public Engine { private: Common::RandomSource _randomSource; + protected: // Engine APIs Common::Error run() override; From 2d67a8cf0dae01ea1333ebcc98d06a3798f11e9f Mon Sep 17 00:00:00 2001 From: Quote58 Date: Sun, 19 Jun 2022 01:34:52 -0400 Subject: [PATCH 294/412] IMMORTAL: Add check for file data null pointer and fix file name parameter --- engines/immortal/disk.cpp | 34 +++++++++++++++++++++------------- engines/immortal/disk.h | 21 +++++++++------------ 2 files changed, 30 insertions(+), 25 deletions(-) diff --git a/engines/immortal/disk.cpp b/engines/immortal/disk.cpp index 35f516a95826..d14713a45918 100644 --- a/engines/immortal/disk.cpp +++ b/engines/immortal/disk.cpp @@ -45,8 +45,7 @@ void ProDosFile::printInfo() { debug("File: %s", _name); debug("Type: %02X", _type); debug("Blocks: %d", _totalBlocks); - debug("Size: %u", _eof); - debug(""); + debug("Size: %u\n", _eof); } /* For Common::Archive, this method just returns a string of the name */ @@ -199,8 +198,11 @@ void ProDosDisk::getHeader(DirHeader *h) { h->_nameLen = tempByte & 0xf; h->_type = (tempByte & 0xf0) >> 4; - // The name field is stored in 15 bytes with no null character (aside from unused chars being 00) + /* The name field is stored in 15 bytes with no null character (unused chars default to 0). + * To make it easier to use the name, we will add a terminator regardless. + */ _disk.read(h->_name, 15); + h->_name[15] = 0; _disk.read(h->_reserved, 8); // The time and date can be decompressed into structs right away @@ -243,6 +245,7 @@ void ProDosDisk::getFileEntry(FileEntry *f) { f->_type = (tempByte & 0xf0) >> 4; _disk.read(f->_name, 15); + f->_name[15] = 0; f->_ext = _disk.readByte(); f->_blockPtr = _disk.readUint16LE(); f->_totalBlocks = _disk.readUint16LE(); @@ -293,17 +296,9 @@ void ProDosDisk::searchDirectory(DirHeader *h, uint16 p, uint16 n, Common::Strin // It is a regular file if (dead < file type < pascal) and the file has a size if ((kFileTypeDead < fileEntry._type) && (fileEntry._type < kFileTypePascal) && (fileEntry._eof > 0)) { - char cString[16]; - for (int j = 0; j < 15; j++) { - cString[j] = fileEntry._name[j]; - } - cString[15] = 0; - Common::String fileName = path + cString; + Common::String fileName = path + fileEntry._name; debug("%s", fileName.c_str()); - //debug("%s", fileName.c_str()); ProDosFile *currFile = new ProDosFile(fileEntry._name, fileEntry._type, fileEntry._totalBlocks, fileEntry._eof, fileEntry._blockPtr, &_disk); - //debug("%s", currFile._name); - currFile->printInfo(); _files.setVal(fileName, Common::SharedPtr(currFile)); _disk.seek(currPos); @@ -365,7 +360,7 @@ bool ProDosDisk::open(const Common::String filename) { VolHeader header; getVolumeHeader(&header); debug("volume name: %s", header._name); - debug("volume created %d/%d/19%d", header._date._day, header._date._month, header._date._year); + //debug("volume created %d/%d/19%d", header._date._day, header._date._month, header._date._year); getVolumeBitmap(&header); @@ -397,6 +392,11 @@ bool ProDosDisk::hasFile(const Common::Path &path) const { return _files.contains(name); } +/* To create a list of files in the Archive, we define an iterator for the object type + * used by the Archive member, and then loop through the hashmap, adding the object + * pointer returned as the value from the given path. This also returns the size. + */ + int ProDosDisk::listMembers(Common::ArchiveMemberList &list) const { int f = 0; Common::HashMap>::const_iterator it; @@ -415,9 +415,17 @@ const Common::ArchiveMemberPtr ProDosDisk::getMember(const Common::Path &path) c return _files.getValOrDefault(name); } +/* This method is called on Archive members as it searches for the correct one, + * so if this member is not the correct one, we return a null pointer. + */ + Common::SeekableReadStream *ProDosDisk::createReadStreamForMember(const Common::Path &path) const { Common::String name = path.toString(); + if (!_files.contains(name)) { + return nullptr; + } Common::SharedPtr f = _files.getValOrDefault(name); + f->printInfo(); return f->createReadStream(); } diff --git a/engines/immortal/disk.h b/engines/immortal/disk.h index bc173ec3bf5b..d51971af997c 100644 --- a/engines/immortal/disk.h +++ b/engines/immortal/disk.h @@ -33,11 +33,6 @@ * matter for game engines anyway. */ -/* There is also one thing that currently has an error. If a file size is the full 15 chars, - * it seems to add a char of some kind to the end and can't be looked up by that value. - * Probably just a difference in string encoding that I need to sort out - */ - namespace Immortal { // These values define for ProDos how to read the file entry, and also whether it's a keyblock (if it is a directory header, it's the keyblock of that directory) @@ -85,7 +80,7 @@ enum FileExt { class ProDosFile : public Common::ArchiveMember { public: - ProDosFile(char name[15], uint8 type, uint16 tBlk, uint32 eof, uint16 bPtr, Common::File *disk); + ProDosFile(char name[16], uint8 type, uint16 tBlk, uint32 eof, uint16 bPtr, Common::File *disk); ~ProDosFile() {}; // These are the Common::ArchiveMember related functions @@ -93,10 +88,12 @@ class ProDosFile : public Common::ArchiveMember { Common::SeekableReadStream *createReadStream() const override; void getDataBlock(byte *memOffset, int offset, int size) const; int parseIndexBlock(byte *memOffset, int blockNum, int cSize) const; + + // Mostly for debugging purposes, just prints the metadata void printInfo(); private: - char _name[15]; + char _name[16]; uint8 _type; uint16 _blockPtr; uint16 _totalBlocks; @@ -117,7 +114,7 @@ class ProDosDisk : public Common::Archive { ProDosDisk(const Common::String filename); ~ProDosDisk(); - // Called from the constructor, parses the volume and fills the hashmap with files + // Called from the constructor, it parses the volume and fills the hashmap with files bool open(const Common::String filename); // These are the Common::Archive related methods @@ -150,7 +147,7 @@ Common::HashMap> _files; // Hashma struct VolHeader { uint8 _type; // Not really important for a volume header, as this will always be F uint8 _nameLen; - char _name[15]; + char _name[16]; byte _reserved[8]; // Extra space reserved for possible future uses, not important Date _date; Time _time; @@ -167,7 +164,7 @@ Common::HashMap> _files; // Hashma struct DirHeader { uint8 _type; uint8 _nameLen; - char _name[15]; + char _name[16]; byte _reserved[8]; Date _date; Time _time; @@ -185,7 +182,7 @@ Common::HashMap> _files; // Hashma struct FileEntry { uint8 _type; // 0 = inactive, 1-3 = file, 4 = pascal area, 14 = subdirectory, 15 = volume directory uint8 _nameLen; - char _name[15]; + char _name[16]; uint8 _ext; // File extension, uses the enum FileExt uint16 _blockPtr; // Block pointer to data for seedling, index block for sapling, or master block for tree uint16 _totalBlocks; // Really important to remember this is the total *including* the index block @@ -207,7 +204,7 @@ Common::HashMap> _files; // Hashma void getDirectoryHeader(DirHeader *h); // Uses getHeader and then fills in the values for the parent directory void getVolumeHeader(VolHeader *dir); // Uses getHeader and then fills in the volume related information (there is no parent directory to this one) void getFileEntry(FileEntry *f); // Adds all of the file entry information to the struct - void searchDirectory(DirHeader *h, uint16 p, uint16 n, Common::String path); // Recursively searches all files within a directory, and dives into subdirectories to search them as well + void searchDirectory(DirHeader *h, uint16 p, uint16 n, Common::String path); // Recursively searches all files within a directory, by calling itself for subdirectories void getVolumeBitmap(VolHeader *h); // Puts together the volume bitmap }; From 8ee7878dffeab42b7ad0c423109561e2e699ae61 Mon Sep 17 00:00:00 2001 From: Quote58 Date: Sun, 19 Jun 2022 01:39:35 -0400 Subject: [PATCH 295/412] IMMORTAL: Volume bitmap stored as byte * instead of Common::Array --- engines/immortal/disk.cpp | 31 ++++++++++++++++--------------- engines/immortal/disk.h | 13 ++++++------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/engines/immortal/disk.cpp b/engines/immortal/disk.cpp index d14713a45918..736c46065574 100644 --- a/engines/immortal/disk.cpp +++ b/engines/immortal/disk.cpp @@ -324,25 +324,25 @@ void ProDosDisk::searchDirectory(DirHeader *h, uint16 p, uint16 n, Common::Strin } } -/* This just gets the volume bitmap by finding out how many blocks it takes up and then adding them to vector of the data. */ +/* The volume bitmap is a bitmap spanning as many blocks as is required to store 1 bit for every + * block on the disk. There are 8 bits per byte and 512 bytes per block, so it needs + * ((total_blocks / 4096) + 1 (if remainder)) * 512 bytes. + */ void ProDosDisk::getVolumeBitmap(VolHeader *h) { int currPos = _disk.pos(); - _disk.seek(h->_bitmapPtr * kBlockSize); - int bitmapNum = 1; - if (_volBlocks >= 4096) { - bitmapNum = _volBlocks / 4096; - } - for (int i = 0; i < bitmapNum; i++) { - byte bitmapData[512]; - _disk.read(bitmapData, kBlockSize); - Common::Array volBitmapBlock = Common::Array(kBlockSize); - for (int j = 0; j < kBlockSize; j++) { - volBitmapBlock[j] = bitmapData[j]; - } - _volBitmap.push_back(volBitmapBlock); + int bitmapSize; + + bitmapSize = _volBlocks / 4096; + if ((_volBlocks % 4096) > 0) { + bitmapSize++; } - _disk.seek(currPos); + + _volBitmap = (byte *)malloc(bitmapSize * kBlockSize); + _disk.seek(h->_bitmapPtr * kBlockSize); + _disk.read(_volBitmap, bitmapSize); + + _disk.seek(currPos); } /* Gets the volume information and parses the filesystem, adding file objects to a map as it goes */ @@ -383,6 +383,7 @@ ProDosDisk::ProDosDisk(const Common::String filename) { ProDosDisk::~ProDosDisk() { _disk.close(); _files.clear(); + delete _volBitmap; } // --- Common::Archive methods --- diff --git a/engines/immortal/disk.h b/engines/immortal/disk.h index d51971af997c..4f8c1ea3599d 100644 --- a/engines/immortal/disk.h +++ b/engines/immortal/disk.h @@ -124,13 +124,12 @@ class ProDosDisk : public Common::Archive { Common::SeekableReadStream *createReadStreamForMember(const Common::Path &path) const override; private: - byte _loader1[512]; // There's no reason these would be needed, but why not include them just in case - byte _loader2[512]; -Common::String _name; // Name of volume - Common::File _disk; // The volume file itself - int _volBlocks; // Total blocks in volume - -Common::Array _volBitmap; // Not super useful, but could be used with _totalBlocks to check whether the disk is corrupted + byte _loader1[512]; // There's no reason these would be needed, but why not include them just in case + byte _loader2[512]; +Common::String _name; // Name of volume + Common::File _disk; // The volume file itself + int _volBlocks; // Total blocks in volume + byte *_volBitmap; // This can determine if the volume is corrupt as it contains a bit for every block, where 0 = unused, 1 = used Common::HashMap> _files; // Hashmap of files in the volume, where key=Path, Value=ProDosFile struct Date { From 566d3b3cd0e082e52c1ec60fad2c0b5bf98bafa3 Mon Sep 17 00:00:00 2001 From: Quote58 Date: Mon, 20 Jun 2022 02:46:45 -0400 Subject: [PATCH 296/412] IMMORTAL: Translation of source decompression to compression.cpp --- engines/immortal/compression.cpp | 278 +++++++++++++++++++++++++++++++ engines/immortal/compression.h | 38 +++++ engines/immortal/module.mk | 3 +- 3 files changed, 318 insertions(+), 1 deletion(-) create mode 100644 engines/immortal/compression.cpp create mode 100644 engines/immortal/compression.h diff --git a/engines/immortal/compression.cpp b/engines/immortal/compression.cpp new file mode 100644 index 000000000000..16b24467e6e6 --- /dev/null +++ b/engines/immortal/compression.cpp @@ -0,0 +1,278 @@ + /* 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/debug.h" +#include "common/file.h" +#include "common/memstream.h" +#include "immortal/compression.h" + +/* In: Source data as File, size of data, pointer that will be replaced with pointer to the data + * Out: size of uncompressed data + */ +namespace Compression { + +int unCompress(Common::File *src, int srcLen, byte *dst) { + uint16 k12BitWord = 0x0F9F; // Code is stored in lower 12 bits of word, probably doesn't need to be const + + Common::MemoryWriteStreamDynamic dstW(DisposeAfterUse::YES); + + //debug("lets get started"); + + // If the source data has no length, we certainly do not want to decompress it + if (srcLen == 0) { + return -1; // Classic C error code + } + + //debug("not null at least"); + // This is the 20k bytes the compression gets allocated to work with for the dictionary and the stack of chars + uint16 start[0x4000]; // Rename! <- I did? Probably still needs a better name though + uint16 ptk[0x4000]; // Pointer to keys? + byte stack[0x4000]; // Stack of chars to be stored + + // These are the main variables we'll need for this. They were basically scratch ram in the original + uint16 findEmpty; + uint16 code; // Needs to be ASL to index with + uint16 inputCode; + uint16 finalChar; + uint16 myCode; // Silly name is silly + uint16 oldCode; + uint16 index; // The Y register was used to index the byte array's, this will sort of take its place + uint16 evenOdd = 0; + uint16 topStack = 0; + + byte outByte; + + setupDictionary(start, ptk, findEmpty); // Clear the dictionary and also set findEmpty to 8k for some reason + bool carry = true; // This will represent the carry flag so we can make this a clean loop + + code = getInputCode(carry, src, srcLen, evenOdd); // Get the first code + if (carry == false) { + return -1; // This is essentially the same as the first error check, but the source returns an error code and didn't even check it here + } + + finalChar = code; + oldCode = code; + myCode = code; + + outByte = code & 0x00FF; + dstW.writeByte(outByte); // Take just the lower byte and write it the output + + //debug("first data write: %02X", outByte); + + // :nextcode + while (carry == true) { + + code = getInputCode(carry, src, srcLen, evenOdd); // Get the next code + if (carry == true) { + + index = code << 1; // Could just write this code*2 probably + inputCode = code; + myCode = code; + + //debug("%04X, %04X, %04X", index, inputCode, myCode); + + uint16 a = start[index] & 0x0F00; + uint16 b = ptk[index] & 0xFF00; + if ((a & b) == 0) { // Empty code + index = topStack; + outByte = finalChar & 0x00FF; + stack[index] = outByte; + topStack++; + myCode = oldCode; + } + + //debug("%04X, %04X, %04X, %04X, %02X", index, inputCode, myCode, topStack, outByte); + + //debug("nextsymbol"); + // :nextsymbol + index = myCode << 1; + while (index >= 0x200) { + myCode = start[index] & k12BitWord; + outByte = ptk[index] & 0x00FF; + index = topStack; + stack[index] = outByte; + topStack++; + //debug("i: %02X, tB: %02X, mC: %02X, b: %02X", index, topStack, myCode, outByte); + index = myCode << 1; + } + + //debug("singlechar"); + // :singlechar + finalChar = (myCode >> 1); + outByte = finalChar & 0x00FF; + + //debug("second data write: %02X", outByte); + dstW.writeByte(outByte); + + //debug("topstack %d", topStack); + + // :dump + while (topStack != 0xFFFF) { // Dump the chars on the stack into the output file + outByte = stack[topStack] & 0x00FF; + //debug("dumping stack %02X", temp); + dstW.writeByte(outByte); + topStack--; + } + topStack = 0; // Won't this always be 0 because of the while loop? + code = getMember(oldCode, finalChar, findEmpty, start, ptk); + oldCode = inputCode; + } + } + dst = dstW.getData(); + return dstW.size(); +} + +void setupDictionary(uint16 start[], uint16 ptk[], uint16 &findEmpty) { + for (int i = 0x3FFF; i >= 0; i--) { + start[i] = 0; + ptk[i] = 0; + } + for (int i=0x0FF; i >=0; i--) { + ptk[i] = 0x100; + } + findEmpty = 0x8000; +} + +int getInputCode(bool &carry, Common::File *src, int &srcLen, uint16 &evenOdd) { + uint16 k12BitWord = 0x0F9F; + + if (srcLen == 0) { + carry = false; + return 0; + } + + uint16 c; + if (evenOdd != 0) { // Odd + srcLen--; + evenOdd--; + c = (src->readUint16LE() >> 3) & 0x00FE; // & #-1-1 ???? + } else { // Even + srcLen -= 2; + evenOdd++; + c = (src->readUint16LE() & k12BitWord) << 1; + src->seek(-1, SEEK_CUR); + } + return c; +} + +// This function is effectively void, as the return value is only used in compression +uint16 getMember(uint16 codeW, uint16 k, uint16 &findEmpty, uint16 start[], uint16 ptk[]) { + // k and codeW are local variables with the value of oldCode and finalChar + uint16 k12BitWord = 0x0F9F; + + uint16 hash; + hash = (k << 3) ^ k; + hash = (hash << 1) ^ codeW; + hash <<= 1; + + hash = (hash >= 0x200) ? hash : hash + 0x200; + + uint16 a = start[hash] & 0x0F00; + uint16 b = ptk[hash] & 0xFF00; + if (a | b) { + start[hash] = codeW; + ptk[hash] = k | 0x100; + return k | 0x100; + } + + bool ag = true; + while (ag == true) { + if ((start[hash] & k12BitWord) == codeW) { + if ((ptk[hash] & 0x00FF) == k) { + return hash >> 1; + } + } + + uint16 tmp = start[hash] & 0xF000; + if (tmp == 0) { + appendList(codeW, k, hash, findEmpty, start, ptk, tmp); + ag = false; + } else { + tmp >>= 4; + hash &= 0xFF00; // The 65816 can XBA to flip the bytes in a word, instead we have mask and shift over + hash >>= 8; + hash = (hash | tmp) << 1; + } + } + return hash; +} + +void appendList(uint16 codeW, uint16 k, uint16 &hash, uint16 &findEmpty, uint16 start[], uint16 ptk[], uint16 &tmp) { + uint16 prev; + uint16 link; + + prev = hash; + if (hash >= 0x200) { + setupDictionary(start, ptk, findEmpty); + return; + } + + bool found = false; + while (found == false) { + hash -= 2; + if (hash >= 0x200) { + setupDictionary(start, ptk, findEmpty); + found = true; + } + uint16 cond; + cond = start[hash] & 0xF000; + cond |= ptk[hash]; + if ( (cond & 0xFF00) == 0) { + findEmpty = hash; + start[hash] = codeW; + ptk[hash] = k | 0x100; + link = hash >> 1; + tmp = link & 0x00FF; // Another classic XBA situation, although this time it's no less efficient here + tmp <<= 8; + ptk[prev] = (ptk[prev] & 0x00FF) | tmp; + start[prev] = ((link >> 4) & 0xF000) | start[prev]; // Yikes this statement is gross + found = true; + } + } +} + +} // namespace compression + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/engines/immortal/compression.h b/engines/immortal/compression.h new file mode 100644 index 000000000000..8770cb4d4305 --- /dev/null +++ b/engines/immortal/compression.h @@ -0,0 +1,38 @@ + /* 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 . + * + */ + +#ifndef IMMORTAL_COMPRESSION_H +#define IMMORTAL_COMPRESSION_H + +#include "common/file.h" +#include "common/memstream.h" + +namespace Compression { + +int unCompress(Common::File *src, int srcLen, byte *out); +void setupDictionary(uint16 start[], uint16 ptk[], uint16 &findEmpty); +int getInputCode(bool &carry, Common::File *src, int &srcLen, uint16 &evenOdd); +uint16 getMember(uint16 codeW, uint16 k, uint16 &findEmpty, uint16 start[], uint16 ptk[]); +void appendList(uint16 codeW, uint16 k, uint16 &hash, uint16 &findEmpty, uint16 start[], uint16 ptk[], uint16 &tmp); + +} // namespace compression + +#endif \ No newline at end of file diff --git a/engines/immortal/module.mk b/engines/immortal/module.mk index 684f8af133cf..15d7f541677d 100644 --- a/engines/immortal/module.mk +++ b/engines/immortal/module.mk @@ -3,7 +3,8 @@ MODULE := engines/immortal MODULE_OBJS = \ immortal.o \ disk.o \ - metaengine.o + metaengine.o \ + compression.o # This module can be built as a plugin ifeq ($(ENABLE_IMMORTAL), DYNAMIC_PLUGIN) From 3e560a0ca5bc0b9e5de24c27b9251eeca3fbf046 Mon Sep 17 00:00:00 2001 From: Quote58 Date: Tue, 21 Jun 2022 17:22:56 -0400 Subject: [PATCH 297/412] IMMORTAL: ProDos -> ProDOS --- engines/immortal/disk.cpp | 68 +++++++++++++++++++-------------------- engines/immortal/disk.h | 40 +++++++++++------------ 2 files changed, 53 insertions(+), 55 deletions(-) diff --git a/engines/immortal/disk.cpp b/engines/immortal/disk.cpp index 736c46065574..5979906ca6cb 100644 --- a/engines/immortal/disk.cpp +++ b/engines/immortal/disk.cpp @@ -22,15 +22,13 @@ #include "common/debug.h" #include "common/file.h" - -#include "immortal/immortal.h" #include "immortal/disk.h" namespace Immortal { -// --- ProDosFile methods --- +// --- ProDOSFile methods --- -ProDosFile::ProDosFile(char name[15], uint8 type, uint16 tBlk, uint32 eof, uint16 bPtr, Common::File *disk) +ProDOSFile::ProDOSFile(char name[15], uint8 type, uint16 tBlk, uint32 eof, uint16 bPtr, Common::File *disk) : _type(type) , _totalBlocks(tBlk) , _eof(eof) @@ -41,7 +39,7 @@ ProDosFile::ProDosFile(char name[15], uint8 type, uint16 tBlk, uint32 eof, uint1 /* For debugging purposes, this prints the meta data of a file */ -void ProDosFile::printInfo() { +void ProDOSFile::printInfo() { debug("File: %s", _name); debug("Type: %02X", _type); debug("Blocks: %d", _totalBlocks); @@ -50,7 +48,7 @@ void ProDosFile::printInfo() { /* For Common::Archive, this method just returns a string of the name */ -Common::String ProDosFile::getName() const { +Common::String ProDOSFile::getName() const { return Common::String(_name); } @@ -60,7 +58,7 @@ Common::String ProDosFile::getName() const { * memory starting at memOffset */ -void ProDosFile::getDataBlock(byte *memOffset, int offset, int size) const { +void ProDOSFile::getDataBlock(byte *memOffset, int offset, int size) const { // All this method needs to do is read (size) of data at (offset) into (memOffset) _disk->seek(offset); @@ -73,14 +71,14 @@ void ProDosFile::getDataBlock(byte *memOffset, int offset, int size) const { * determine the new position within the byte data. */ -int ProDosFile::parseIndexBlock(byte *memOffset, int blockNum, int rem) const { +int ProDOSFile::parseIndexBlock(byte *memOffset, int blockNum, int rem) const { int dataSize; // For most of the blocks, this will be kBlockSize, but the last one will be the calculated remainder int readSize = 0; // This keeps track of the new pointer position to read data to, by updating the size of data read last int dataOffset; // Where in the disk to read from int diskPos; // Current position of cursor for (int i = 0; i < blockNum; i++) { - dataSize = (i == (blockNum - 1)) ? rem : ProDosDisk::kBlockSize; + dataSize = (i == (blockNum - 1)) ? rem : ProDOSDisk::kBlockSize; dataOffset = _disk->readByte(); // Low byte is first /* The cursor needs to know where to get the next pointer from in the index block, @@ -90,7 +88,7 @@ int ProDosFile::parseIndexBlock(byte *memOffset, int blockNum, int rem) const { diskPos = _disk->pos(); _disk->skip(255); // The high bytes are stored at the end of the block instead because reasons??? - dataOffset += (_disk->readByte() << 8) * ProDosDisk::kBlockSize; // High byte is second + dataOffset += (_disk->readByte() << 8) * ProDOSDisk::kBlockSize; // High byte is second getDataBlock(memOffset + readSize, dataOffset, dataSize); readSize += dataSize; @@ -108,7 +106,7 @@ int ProDosFile::parseIndexBlock(byte *memOffset, int blockNum, int rem) const { * returns a read stream of the file contents. */ -Common::SeekableReadStream *ProDosFile::createReadStream() const { +Common::SeekableReadStream *ProDOSFile::createReadStream() const { // We know the total byte size of the data, so we can allocate the full amount right away byte *finalData = (byte *)malloc(_eof); @@ -116,12 +114,12 @@ Common::SeekableReadStream *ProDosFile::createReadStream() const { /* For a seed, this is a direct pointer to data. For a sapling it is an index file, * and for a tree it is a master index file. */ - int indexBlock = _blockPtr * ProDosDisk::kBlockSize; + int indexBlock = _blockPtr * ProDOSDisk::kBlockSize; /* For a sapling or tree, the size needs to be calculated, as they are made from multiple blocks. * _totalBlocks *includes* the index block, so the blocks before the oef block are _totalBlocks-2 */ - int remainder = _eof - ((_totalBlocks - 2) * ProDosDisk::kBlockSize); + int remainder = _eof - ((_totalBlocks - 2) * ProDOSDisk::kBlockSize); // For a seed file, the end of file value is also the size in the block, because it's just the one block if (_type == kFileTypeSeed) { @@ -157,7 +155,7 @@ Common::SeekableReadStream *ProDosFile::createReadStream() const { int diskPos = _disk->pos(); _disk->skip(255); - indexOffset += (_disk->readByte() << 8) * ProDosDisk::kBlockSize; + indexOffset += (_disk->readByte() << 8) * ProDOSDisk::kBlockSize; _disk->seek(indexOffset); readSize += parseIndexBlock(finalData + readSize, blockNum, remainder); @@ -168,27 +166,27 @@ Common::SeekableReadStream *ProDosFile::createReadStream() const { return new Common::MemoryReadStream(finalData, _eof, DisposeAfterUse::YES); } -// --- ProDosDisk methods --- +// --- ProDOSDisk methods --- /* The time and date are compressed into 16bit words, so to make them useable * we have to decompress them by masking the other bits and then shifting * to the lowest bit so that they can be stored in 8 bits each. */ -void ProDosDisk::getDate(Date *d, uint16 date) { +void ProDOSDisk::getDate(Date *d, uint16 date) { d->_day = date & 0x001f; d->_month = (date & 0x01e0) >> 5; d->_year = (date & 0xfe00) >> 9; } -void ProDosDisk::getTime(Time *t, uint16 time) { +void ProDOSDisk::getTime(Time *t, uint16 time) { t->_minute = time & 0x003f; t->_hour = (time & 0x1f00) >> 8; } /* Adds most of the header data to a directory header struct */ -void ProDosDisk::getHeader(DirHeader *h) { +void ProDOSDisk::getHeader(DirHeader *h) { /* The type and nameLen fields are stored in the same byte, * so we need to split the byte, and shift the high bits to @@ -219,7 +217,7 @@ void ProDosDisk::getHeader(DirHeader *h) { /* Since a subdirectory header is mostly the same a volume header, we will reuse the code where we can */ -void ProDosDisk::getDirectoryHeader(DirHeader *h) { +void ProDOSDisk::getDirectoryHeader(DirHeader *h) { getHeader(h); h->_parentBlockPtr = _disk.readUint16LE(); h->_parentEntryIndex = _disk.readByte(); @@ -230,7 +228,7 @@ void ProDosDisk::getDirectoryHeader(DirHeader *h) { * is a directory header for the purose of filling it out with the same code */ -void ProDosDisk::getVolumeHeader(VolHeader *h) { +void ProDOSDisk::getVolumeHeader(VolHeader *h) { getHeader((DirHeader *)h); h->_bitmapPtr = _disk.readUint16LE(); h->_volBlocks = _disk.readUint16LE(); @@ -239,7 +237,7 @@ void ProDosDisk::getVolumeHeader(VolHeader *h) { /* Getting a file entry header is very similar to getting a header, but with different data. */ -void ProDosDisk::getFileEntry(FileEntry *f) { +void ProDOSDisk::getFileEntry(FileEntry *f) { uint8 tempByte = _disk.readByte(); f->_nameLen = tempByte & 0xf; f->_type = (tempByte & 0xf0) >> 4; @@ -274,7 +272,7 @@ void ProDosDisk::getFileEntry(FileEntry *f) { * which is stored with the file object so that the engine can search by path name. */ -void ProDosDisk::searchDirectory(DirHeader *h, uint16 p, uint16 n, Common::String path) { +void ProDOSDisk::searchDirectory(DirHeader *h, uint16 p, uint16 n, Common::String path) { int currPos; int parsedFiles = 0; @@ -298,9 +296,9 @@ void ProDosDisk::searchDirectory(DirHeader *h, uint16 p, uint16 n, Common::Strin if ((kFileTypeDead < fileEntry._type) && (fileEntry._type < kFileTypePascal) && (fileEntry._eof > 0)) { Common::String fileName = path + fileEntry._name; debug("%s", fileName.c_str()); - ProDosFile *currFile = new ProDosFile(fileEntry._name, fileEntry._type, fileEntry._totalBlocks, fileEntry._eof, fileEntry._blockPtr, &_disk); + ProDOSFile *currFile = new ProDOSFile(fileEntry._name, fileEntry._type, fileEntry._totalBlocks, fileEntry._eof, fileEntry._blockPtr, &_disk); - _files.setVal(fileName, Common::SharedPtr(currFile)); + _files.setVal(fileName, Common::SharedPtr(currFile)); _disk.seek(currPos); // Otherwise, if it is a subdirectory, we want to explore that subdirectory @@ -329,7 +327,7 @@ void ProDosDisk::searchDirectory(DirHeader *h, uint16 p, uint16 n, Common::Strin * ((total_blocks / 4096) + 1 (if remainder)) * 512 bytes. */ -void ProDosDisk::getVolumeBitmap(VolHeader *h) { +void ProDOSDisk::getVolumeBitmap(VolHeader *h) { int currPos = _disk.pos(); int bitmapSize; @@ -347,7 +345,7 @@ void ProDosDisk::getVolumeBitmap(VolHeader *h) { /* Gets the volume information and parses the filesystem, adding file objects to a map as it goes */ -bool ProDosDisk::open(const Common::String filename) { +bool ProDOSDisk::open(const Common::String filename) { debug("opening %s", filename.c_str()); _disk.open(filename); @@ -372,7 +370,7 @@ bool ProDosDisk::open(const Common::String filename) { /* Constructor simply calls open(), and if it is successful it prints a statement */ -ProDosDisk::ProDosDisk(const Common::String filename) { +ProDOSDisk::ProDOSDisk(const Common::String filename) { if (open(filename)) { debug ("%s has been loaded", filename.c_str()); } @@ -380,15 +378,15 @@ ProDosDisk::ProDosDisk(const Common::String filename) { /* Destructor closes the disk and clears the map of files */ -ProDosDisk::~ProDosDisk() { +ProDOSDisk::~ProDOSDisk() { _disk.close(); _files.clear(); - delete _volBitmap; + delete _volBitmap; // Should this be free() instead? } // --- Common::Archive methods --- -bool ProDosDisk::hasFile(const Common::Path &path) const { +bool ProDOSDisk::hasFile(const Common::Path &path) const { Common::String name = path.toString(); return _files.contains(name); } @@ -398,9 +396,9 @@ bool ProDosDisk::hasFile(const Common::Path &path) const { * pointer returned as the value from the given path. This also returns the size. */ -int ProDosDisk::listMembers(Common::ArchiveMemberList &list) const { +int ProDOSDisk::listMembers(Common::ArchiveMemberList &list) const { int f = 0; - Common::HashMap>::const_iterator it; + Common::HashMap>::const_iterator it; for (it = _files.begin(); it != _files.end(); ++it) { list.push_back(Common::ArchiveMemberList::value_type(it->_value)); ++f; @@ -408,7 +406,7 @@ int ProDosDisk::listMembers(Common::ArchiveMemberList &list) const { return f; } -const Common::ArchiveMemberPtr ProDosDisk::getMember(const Common::Path &path) const { +const Common::ArchiveMemberPtr ProDOSDisk::getMember(const Common::Path &path) const { Common::String name = path.toString(); if (!_files.contains(name)) { return Common::ArchiveMemberPtr(); @@ -420,12 +418,12 @@ const Common::ArchiveMemberPtr ProDosDisk::getMember(const Common::Path &path) c * so if this member is not the correct one, we return a null pointer. */ -Common::SeekableReadStream *ProDosDisk::createReadStreamForMember(const Common::Path &path) const { +Common::SeekableReadStream *ProDOSDisk::createReadStreamForMember(const Common::Path &path) const { Common::String name = path.toString(); if (!_files.contains(name)) { return nullptr; } - Common::SharedPtr f = _files.getValOrDefault(name); + Common::SharedPtr f = _files.getValOrDefault(name); f->printInfo(); return f->createReadStream(); } diff --git a/engines/immortal/disk.h b/engines/immortal/disk.h index 4f8c1ea3599d..8ab903b7b8e5 100644 --- a/engines/immortal/disk.h +++ b/engines/immortal/disk.h @@ -19,14 +19,14 @@ * */ -#ifndef IMMORTAL_DSK_H -#define IMMORTAL_DSK_H +#ifndef IMMORTAL_DISK_H +#define IMMORTAL_DISK_H #include "common/memstream.h" #include "common/file.h" #include "common/debug.h" -/* Quick note about ProDos: +/* Quick note about ProDOS: * This disk code handles inactive, seedling, sapling, tree, and subdirectory files. * It does *not* handle sparse files at the moment. If a sparse file exists, it may not * be read correctly. It also does not do anything with Pascal files, but those should not @@ -35,7 +35,7 @@ namespace Immortal { -// These values define for ProDos how to read the file entry, and also whether it's a keyblock (if it is a directory header, it's the keyblock of that directory) +// These values define for ProDOS how to read the file entry, and also whether it's a keyblock (if it is a directory header, it's the keyblock of that directory) enum FileType : char { kFileTypeDead = 0, kFileTypeSeed = 1, @@ -47,8 +47,8 @@ enum FileType : char { kFileTypeVolHead = 0x0F }; -/* File extensions for all the ProDos supported file types - * NOTE: ProDos user defined files are F1-F8. If they are ever required, +/* File extensions for all the ProDOS supported file types + * NOTE: ProDOS user defined files are F1-F8. If they are ever required, * they can be added to this enum. */ enum FileExt { @@ -72,16 +72,16 @@ enum FileExt { kFileExtPDSys = 0xFF }; -/* A ProDos file simply contains meta data about the file and the ability to +/* A ProDOS file simply contains meta data about the file and the ability to * find and put together the data blocks that make up the file contents. * This implements Common::ArchiveMember so that it can be used directly in - * the Archive methods in ProDosDisk. + * the Archive methods in ProDOSDisk. */ -class ProDosFile : public Common::ArchiveMember { +class ProDOSFile : public Common::ArchiveMember { public: - ProDosFile(char name[16], uint8 type, uint16 tBlk, uint32 eof, uint16 bPtr, Common::File *disk); - ~ProDosFile() {}; + ProDOSFile(char name[16], uint8 type, uint16 tBlk, uint32 eof, uint16 bPtr, Common::File *disk); + ~ProDOSFile() {}; // These are the Common::ArchiveMember related functions Common::String getName() const override; @@ -107,12 +107,12 @@ class ProDosFile : public Common::ArchiveMember { * file operations to work with it. */ -class ProDosDisk : public Common::Archive { +class ProDOSDisk : public Common::Archive { public: - static const int kBlockSize = 512; // A ProDos block is always 512 bytes + static const int kBlockSize = 512; // A ProDOS block is always 512 bytes - ProDosDisk(const Common::String filename); - ~ProDosDisk(); + ProDOSDisk(const Common::String filename); + ~ProDOSDisk(); // Called from the constructor, it parses the volume and fills the hashmap with files bool open(const Common::String filename); @@ -130,7 +130,7 @@ Common::String _name; // Name of volume Common::File _disk; // The volume file itself int _volBlocks; // Total blocks in volume byte *_volBitmap; // This can determine if the volume is corrupt as it contains a bit for every block, where 0 = unused, 1 = used -Common::HashMap> _files; // Hashmap of files in the volume, where key=Path, Value=ProDosFile +Common::HashMap> _files; // Hashmap of files in the volume, where key=Path, Value=ProDOSFile struct Date { uint8 _day; @@ -153,8 +153,8 @@ Common::HashMap> _files; // Hashma uint8 _ver; uint8 _minVer; // Should pretty much always be 0 as far as I know uint8 _access; // If this ends up useful, there should be an enum for the access values - uint8 _entryLen; // Always 27 in ProDos 1.0 - uint8 _entriesPerBlock; // Always 0D in ProDos 1.0 + uint8 _entryLen; // Always 27 in ProDOS 1.0 + uint8 _entriesPerBlock; // Always 0D in ProDOS 1.0 uint16 _fileCount; // Number of files across all data blocks in this directory uint16 _bitmapPtr; // Block pointer to the keyblock of the bitmap for the entire volume uint16 _volBlocks; // Blocks in entire volume @@ -173,9 +173,9 @@ Common::HashMap> _files; // Hashma uint8 _entryLen; uint8 _entriesPerBlock; uint16 _fileCount; - uint16 _parentBlockPtr; // These values allow ProDos to navigate back out of a directory, but they aren't really needed by the class to navigate + uint16 _parentBlockPtr; // These values allow ProDOS to navigate back out of a directory, but they aren't really needed by the class to navigate uint8 _parentEntryIndex; // Index in the current directory - uint8 _parentEntryLen; // This is always 27 in ProDos 1.0 + uint8 _parentEntryLen; // This is always 27 in ProDOS 1.0 }; struct FileEntry { From 05bfec4b60cf34929c5068fc7c17830bf01d0d57 Mon Sep 17 00:00:00 2001 From: Quote58 Date: Wed, 22 Jun 2022 03:55:20 -0400 Subject: [PATCH 298/412] IMMORTAL: unCompress() returns memoryReadStream instead of int, and bitmasks have enum --- engines/immortal/compression.cpp | 203 ++++++++++++++++--------------- engines/immortal/compression.h | 3 +- 2 files changed, 110 insertions(+), 96 deletions(-) diff --git a/engines/immortal/compression.cpp b/engines/immortal/compression.cpp index 16b24467e6e6..9dd9fbb6857d 100644 --- a/engines/immortal/compression.cpp +++ b/engines/immortal/compression.cpp @@ -24,58 +24,66 @@ #include "common/memstream.h" #include "immortal/compression.h" -/* In: Source data as File, size of data, pointer that will be replaced with pointer to the data - * Out: size of uncompressed data +/* Decompression: + * This decompression algorithm follows the source assembly very closely, + * which is itself a modification to LZW (a derivitive of LZ78). + * In: Source data as File, size of data + * Out: Pointer to uncompressed data as SeekableReadStream */ namespace Compression { -int unCompress(Common::File *src, int srcLen, byte *dst) { - uint16 k12BitWord = 0x0F9F; // Code is stored in lower 12 bits of word, probably doesn't need to be const - - Common::MemoryWriteStreamDynamic dstW(DisposeAfterUse::YES); - - //debug("lets get started"); +// There is a lot of bit masking that needs to happen, so this enum makes it a little easier to read +enum BitMask : uint16 { + kMask12Bit = 0x0F9F, // Code (pos, 00, len) is stored in lower 12 bits of word + kMaskLow = 0x00FF, + kMaskHigh = 0xFF00, + kMaskLast = 0xF000 +}; +Common::SeekableReadStream *unCompress(Common::File *src, int srcLen) { // If the source data has no length, we certainly do not want to decompress it if (srcLen == 0) { - return -1; // Classic C error code + return nullptr; } - //debug("not null at least"); - // This is the 20k bytes the compression gets allocated to work with for the dictionary and the stack of chars - uint16 start[0x4000]; // Rename! <- I did? Probably still needs a better name though - uint16 ptk[0x4000]; // Pointer to keys? - byte stack[0x4000]; // Stack of chars to be stored + /* This will be the dynamically re-allocated writeable memory stream. + * We do not want it to be deleted from scope, as this location is where + * the readstream being returned will point to. + */ + Common::MemoryWriteStreamDynamic dstW(DisposeAfterUse::NO); + + // The 20k bytes of memory that compression gets allocated to work with for the dictionary and the stack of chars + uint16 start[0x4000]; // Really needs a better name, remember to do this future me + uint16 ptk[0x4000]; // Pointer To Keys? Also needs a better name + byte stack[0x4000]; // Stack of chars to be stored - // These are the main variables we'll need for this. They were basically scratch ram in the original + // These are the main variables we'll need for this uint16 findEmpty; - uint16 code; // Needs to be ASL to index with + uint16 code; // Needs to be ASL to index with uint16 inputCode; uint16 finalChar; - uint16 myCode; // Silly name is silly + uint16 myCode; // Silly name is silly uint16 oldCode; - uint16 index; // The Y register was used to index the byte array's, this will sort of take its place - uint16 evenOdd = 0; + uint16 index; // The Y register was used to index the byte array's, this will sort of take its place + uint16 evenOdd = 0; uint16 topStack = 0; - byte outByte; + byte outByte; // If only we could SEP #$20 like the 65816 - setupDictionary(start, ptk, findEmpty); // Clear the dictionary and also set findEmpty to 8k for some reason - bool carry = true; // This will represent the carry flag so we can make this a clean loop + setupDictionary(start, ptk, findEmpty); // Clear the dictionary and also set findEmpty to 8k + bool carry = true; // This will represent the carry flag so we can make this a clean loop code = getInputCode(carry, src, srcLen, evenOdd); // Get the first code if (carry == false) { - return -1; // This is essentially the same as the first error check, but the source returns an error code and didn't even check it here + return nullptr; // This is essentially the same as the first error check, but the source returns an error code and didn't even check it here so we might as well } finalChar = code; oldCode = code; myCode = code; - outByte = code & 0x00FF; - dstW.writeByte(outByte); // Take just the lower byte and write it the output - - //debug("first data write: %02X", outByte); + outByte = code & kMaskLow; + dstW.writeByte(outByte); // Take just the lower byte and write it the output // :nextcode while (carry == true) { @@ -83,100 +91,96 @@ int unCompress(Common::File *src, int srcLen, byte *dst) { code = getInputCode(carry, src, srcLen, evenOdd); // Get the next code if (carry == true) { - index = code << 1; // Could just write this code*2 probably + index = code << 1; inputCode = code; - myCode = code; - - //debug("%04X, %04X, %04X", index, inputCode, myCode); + myCode = code; uint16 a = start[index] & 0x0F00; - uint16 b = ptk[index] & 0xFF00; - if ((a & b) == 0) { // Empty code - index = topStack; - outByte = finalChar & 0x00FF; + uint16 b = ptk[index] & kMaskHigh; + if ((a & b) == 0) { // Empty code + index = topStack; + outByte = finalChar & kMaskLow; stack[index] = outByte; topStack++; myCode = oldCode; } - //debug("%04X, %04X, %04X, %04X, %02X", index, inputCode, myCode, topStack, outByte); - - //debug("nextsymbol"); // :nextsymbol index = myCode << 1; while (index >= 0x200) { - myCode = start[index] & k12BitWord; - outByte = ptk[index] & 0x00FF; - index = topStack; + myCode = start[index] & kMask12Bit; + outByte = ptk[index] & kMaskLow; + index = topStack; stack[index] = outByte; topStack++; - //debug("i: %02X, tB: %02X, mC: %02X, b: %02X", index, topStack, myCode, outByte); index = myCode << 1; } - //debug("singlechar"); // :singlechar finalChar = (myCode >> 1); - outByte = finalChar & 0x00FF; - - //debug("second data write: %02X", outByte); + outByte = finalChar & kMaskLow; dstW.writeByte(outByte); - //debug("topstack %d", topStack); - // :dump while (topStack != 0xFFFF) { // Dump the chars on the stack into the output file - outByte = stack[topStack] & 0x00FF; - //debug("dumping stack %02X", temp); + outByte = stack[topStack] & kMaskLow; dstW.writeByte(outByte); topStack--; } - topStack = 0; // Won't this always be 0 because of the while loop? - code = getMember(oldCode, finalChar, findEmpty, start, ptk); - oldCode = inputCode; + + topStack = 0; // Won't this always be 0 because of the while loop? + code = getMember(oldCode, finalChar, findEmpty, start, ptk); + oldCode = inputCode; } + } - dst = dstW.getData(); - return dstW.size(); + + // Return a readstream with a pointer to the data in the write stream. + // This one we do want to dispose after using, because it will be in the scope of the engine itself + return new Common::MemoryReadStream(dstW.getData(), dstW.size(), DisposeAfterUse::YES); } void setupDictionary(uint16 start[], uint16 ptk[], uint16 &findEmpty) { + // Clear the whole dictionary for (int i = 0x3FFF; i >= 0; i--) { start[i] = 0; - ptk[i] = 0; + ptk[i] = 0; } - for (int i=0x0FF; i >=0; i--) { - ptk[i] = 0x100; + + // Set the initial 256 bytes to be value 256, these are the characters without extensions + for (int i = 0x0FF; i >= 0; i--) { + ptk[i] = 0x100; } + + // This shouldn't really be done inside the function, but for the sake of consistency with the source, we will findEmpty = 0x8000; } int getInputCode(bool &carry, Common::File *src, int &srcLen, uint16 &evenOdd) { - uint16 k12BitWord = 0x0F9F; - + // Yes, lets check this despite having already checked it before we got here... if (srcLen == 0) { carry = false; return 0; } uint16 c; - if (evenOdd != 0) { // Odd + if (evenOdd != 0) { // Odd srcLen--; evenOdd--; - c = (src->readUint16LE() >> 3) & 0x00FE; // & #-1-1 ???? - } else { // Even + c = (src->readUint16LE() >> 3) & 0x00FE; // & #-1-1 + } else { // Even srcLen -= 2; evenOdd++; - c = (src->readUint16LE() & k12BitWord) << 1; + c = (src->readUint16LE() & kMask12Bit) << 1; src->seek(-1, SEEK_CUR); } return c; } -// This function is effectively void, as the return value is only used in compression uint16 getMember(uint16 codeW, uint16 k, uint16 &findEmpty, uint16 start[], uint16 ptk[]) { + // This function is effectively void, as the return value is only used in compression + // k and codeW are local variables with the value of oldCode and finalChar - uint16 k12BitWord = 0x0F9F; uint16 hash; hash = (k << 3) ^ k; @@ -186,28 +190,32 @@ uint16 getMember(uint16 codeW, uint16 k, uint16 &findEmpty, uint16 start[], uint hash = (hash >= 0x200) ? hash : hash + 0x200; uint16 a = start[hash] & 0x0F00; - uint16 b = ptk[hash] & 0xFF00; + uint16 b = ptk[hash] & kMaskHigh; if (a | b) { start[hash] = codeW; - ptk[hash] = k | 0x100; - return k | 0x100; + ptk[hash] = k | 0x100; + return ptk[hash]; } + // This loop is a bit wacky, due to the way the jumps were stuctured in the source bool ag = true; while (ag == true) { - if ((start[hash] & k12BitWord) == codeW) { - if ((ptk[hash] & 0x00FF) == k) { + if ((start[hash] & kMask12Bit) == codeW) { + if ((ptk[hash] & kMaskLow) == k) { return hash >> 1; } } - uint16 tmp = start[hash] & 0xF000; + uint16 tmp = start[hash] & kMaskLast; if (tmp == 0) { + + // I've separated this into it's own function for the sake of this loop being readable appendList(codeW, k, hash, findEmpty, start, ptk, tmp); ag = false; + } else { tmp >>= 4; - hash &= 0xFF00; // The 65816 can XBA to flip the bytes in a word, instead we have mask and shift over + hash &= kMaskHigh; // The 65816 can XBA to flip the bytes in a word, instead we have mask and shift over :( hash >>= 8; hash = (hash | tmp) << 1; } @@ -222,29 +230,34 @@ void appendList(uint16 codeW, uint16 k, uint16 &hash, uint16 &findEmpty, uint16 prev = hash; if (hash >= 0x200) { setupDictionary(start, ptk, findEmpty); - return; - } + + } else { + bool found = false; + while (found == false) { + hash -= 2; + if (hash >= 0x200) { + setupDictionary(start, ptk, findEmpty); + found = true; + } - bool found = false; - while (found == false) { - hash -= 2; - if (hash >= 0x200) { - setupDictionary(start, ptk, findEmpty); - found = true; - } - uint16 cond; - cond = start[hash] & 0xF000; - cond |= ptk[hash]; - if ( (cond & 0xFF00) == 0) { - findEmpty = hash; - start[hash] = codeW; - ptk[hash] = k | 0x100; - link = hash >> 1; - tmp = link & 0x00FF; // Another classic XBA situation, although this time it's no less efficient here - tmp <<= 8; - ptk[prev] = (ptk[prev] & 0x00FF) | tmp; - start[prev] = ((link >> 4) & 0xF000) | start[prev]; // Yikes this statement is gross - found = true; + // Split up the conditional statement to be easier to follow + uint16 cond; + cond = start[hash] & kMaskLast; + cond |= ptk[hash]; + + if ((cond & kMaskHigh) == 0) { + findEmpty = hash; + start[hash] = codeW; + ptk[hash] = k | 0x100; + + link = hash >> 1; + tmp = link & kMaskLow; // Another classic XBA situation, although it's nicer this time + tmp <<= 8; // Because we can just grab the low bytes and shift them forward (it's still much faster to XBA though) + + ptk[prev] = (ptk[prev] & kMaskLow) | tmp; + start[prev] = ((link >> 4) & kMaskLast) | start[prev]; // Yikes this statement is gross + found = true; + } } } } diff --git a/engines/immortal/compression.h b/engines/immortal/compression.h index 8770cb4d4305..96633758e0b8 100644 --- a/engines/immortal/compression.h +++ b/engines/immortal/compression.h @@ -27,7 +27,8 @@ namespace Compression { -int unCompress(Common::File *src, int srcLen, byte *out); +// Only unCompress() is called from outside Compression, the others are subroutines. +Common::SeekableReadStream *unCompress(Common::File *src, int srcLen); void setupDictionary(uint16 start[], uint16 ptk[], uint16 &findEmpty); int getInputCode(bool &carry, Common::File *src, int &srcLen, uint16 &evenOdd); uint16 getMember(uint16 codeW, uint16 k, uint16 &findEmpty, uint16 start[], uint16 ptk[]); From df41580e058580c64b04d77277efb1ce136f6138 Mon Sep 17 00:00:00 2001 From: Quote58 Date: Fri, 24 Jun 2022 01:55:07 -0400 Subject: [PATCH 299/412] IMMORTAL: Fix file data offset calculation error in sapling and tree files --- engines/immortal/disk.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/engines/immortal/disk.cpp b/engines/immortal/disk.cpp index 5979906ca6cb..49c940182bec 100644 --- a/engines/immortal/disk.cpp +++ b/engines/immortal/disk.cpp @@ -88,7 +88,7 @@ int ProDOSFile::parseIndexBlock(byte *memOffset, int blockNum, int rem) const { diskPos = _disk->pos(); _disk->skip(255); // The high bytes are stored at the end of the block instead because reasons??? - dataOffset += (_disk->readByte() << 8) * ProDOSDisk::kBlockSize; // High byte is second + dataOffset = (dataOffset + (_disk->readByte() << 8)) * ProDOSDisk::kBlockSize; // High byte is second getDataBlock(memOffset + readSize, dataOffset, dataSize); readSize += dataSize; @@ -155,7 +155,7 @@ Common::SeekableReadStream *ProDOSFile::createReadStream() const { int diskPos = _disk->pos(); _disk->skip(255); - indexOffset += (_disk->readByte() << 8) * ProDOSDisk::kBlockSize; + indexOffset = (indexOffset + (_disk->readByte() << 8)) * ProDOSDisk::kBlockSize; _disk->seek(indexOffset); readSize += parseIndexBlock(finalData + readSize, blockNum, remainder); From 3da314ad88ca59f3e13dd68cf489373327b342c9 Mon Sep 17 00:00:00 2001 From: Quote58 Date: Fri, 1 Jul 2022 02:25:15 -0400 Subject: [PATCH 300/412] IMMORTAL: Fix incorrect conditional in primary while loop of compression.cpp --- engines/immortal/compression.cpp | 411 ++++++++++++++++--------------- 1 file changed, 210 insertions(+), 201 deletions(-) diff --git a/engines/immortal/compression.cpp b/engines/immortal/compression.cpp index 9dd9fbb6857d..03cd608c68c6 100644 --- a/engines/immortal/compression.cpp +++ b/engines/immortal/compression.cpp @@ -34,232 +34,241 @@ namespace Compression { // There is a lot of bit masking that needs to happen, so this enum makes it a little easier to read enum BitMask : uint16 { - kMask12Bit = 0x0F9F, // Code (pos, 00, len) is stored in lower 12 bits of word + kMask12Bit = 0x0F9F, // Code (pos, 00, len) is stored in lower 12 bits of word kMaskLow = 0x00FF, kMaskHigh = 0xFF00, kMaskLast = 0xF000 }; -Common::SeekableReadStream *unCompress(Common::File *src, int srcLen) { - // If the source data has no length, we certainly do not want to decompress it - if (srcLen == 0) { - return nullptr; - } +Common::SeekableReadStream *unCompress(Common::File *src, int srcLen) { + /* Note: this function does not seek() in the file, which means + * that if there is a header on the data, the expectation is that + * seek() was already used to move past the header before this function. + */ - /* This will be the dynamically re-allocated writeable memory stream. - * We do not want it to be deleted from scope, as this location is where - * the readstream being returned will point to. - */ - Common::MemoryWriteStreamDynamic dstW(DisposeAfterUse::NO); + // If the source data has no length, we certainly do not want to decompress it + if (srcLen == 0) { + return nullptr; + } - // The 20k bytes of memory that compression gets allocated to work with for the dictionary and the stack of chars - uint16 start[0x4000]; // Really needs a better name, remember to do this future me - uint16 ptk[0x4000]; // Pointer To Keys? Also needs a better name - byte stack[0x4000]; // Stack of chars to be stored + /* This will be the dynamically re-allocated writeable memory stream. + * We do not want it to be deleted from scope, as this location is where + * the readstream being returned will point to. + */ + Common::MemoryWriteStreamDynamic dstW(DisposeAfterUse::NO); + + // The 20k bytes of memory that compression gets allocated to work with for the dictionary and the stack of chars + uint16 start[0x4000]; // Really needs a better name, remember to do this future me + uint16 ptk[0x4000]; // Pointer To Keys? Also needs a better name + byte stack[0x4000]; // Stack of chars to be stored // These are the main variables we'll need for this uint16 findEmpty; - uint16 code; // Needs to be ASL to index with + uint16 code; // Needs to be ASL to index with uint16 inputCode; uint16 finalChar; - uint16 myCode; // Silly name is silly + uint16 myCode; // Silly name is silly uint16 oldCode; - uint16 index; // The Y register was used to index the byte array's, this will sort of take its place - uint16 evenOdd = 0; - uint16 topStack = 0; - - byte outByte; // If only we could SEP #$20 like the 65816 - - setupDictionary(start, ptk, findEmpty); // Clear the dictionary and also set findEmpty to 8k - bool carry = true; // This will represent the carry flag so we can make this a clean loop - - code = getInputCode(carry, src, srcLen, evenOdd); // Get the first code - if (carry == false) { - return nullptr; // This is essentially the same as the first error check, but the source returns an error code and didn't even check it here so we might as well - } - - finalChar = code; - oldCode = code; - myCode = code; - - outByte = code & kMaskLow; - dstW.writeByte(outByte); // Take just the lower byte and write it the output - - // :nextcode - while (carry == true) { - - code = getInputCode(carry, src, srcLen, evenOdd); // Get the next code - if (carry == true) { - - index = code << 1; - inputCode = code; - myCode = code; - - uint16 a = start[index] & 0x0F00; - uint16 b = ptk[index] & kMaskHigh; - if ((a & b) == 0) { // Empty code - index = topStack; - outByte = finalChar & kMaskLow; - stack[index] = outByte; - topStack++; - myCode = oldCode; - } - - // :nextsymbol - index = myCode << 1; - while (index >= 0x200) { - myCode = start[index] & kMask12Bit; - outByte = ptk[index] & kMaskLow; - index = topStack; - stack[index] = outByte; - topStack++; - index = myCode << 1; - } - - // :singlechar - finalChar = (myCode >> 1); - outByte = finalChar & kMaskLow; - dstW.writeByte(outByte); - - // :dump - while (topStack != 0xFFFF) { // Dump the chars on the stack into the output file - outByte = stack[topStack] & kMaskLow; - dstW.writeByte(outByte); - topStack--; - } - - topStack = 0; // Won't this always be 0 because of the while loop? - code = getMember(oldCode, finalChar, findEmpty, start, ptk); - oldCode = inputCode; - } - - } - - // Return a readstream with a pointer to the data in the write stream. - // This one we do want to dispose after using, because it will be in the scope of the engine itself - return new Common::MemoryReadStream(dstW.getData(), dstW.size(), DisposeAfterUse::YES); + uint16 index; // The Y register was used to index the byte array's, this will sort of take its place + uint16 evenOdd = 0; + uint16 topStack = 0; + + byte outByte; // If only we could SEP #$20 like the 65816 + + setupDictionary(start, ptk, findEmpty); // Clear the dictionary and also set findEmpty to 8k + bool carry = true; // This will represent the carry flag so we can make this a clean loop + + code = getInputCode(carry, src, srcLen, evenOdd); // Get the first code + if (carry == false) { + return nullptr; // This is essentially the same as the first error check, but the source returns an error code and didn't even check it here so we might as well + } + + finalChar = code; + oldCode = code; + myCode = code; + + outByte = code & kMaskLow; + dstW.writeByte(outByte); // Take just the lower byte and write it the output + + // :nextcode + while (carry == true) { + + code = getInputCode(carry, src, srcLen, evenOdd); // Get the next code + if (carry == true) { + + index = code << 1; + inputCode = code; + myCode = code; + + // Split up the conditional statement to be easier to follow + uint16 cond; + cond = start[index] & kMaskLast; + cond |= ptk[index]; + + if ((cond & kMaskHigh) == 0) { // Empty code + index = topStack; + outByte = finalChar & kMaskLow; + stack[index] = outByte; + topStack++; + myCode = oldCode; + } + + // :nextsymbol + index = myCode << 1; + while (index >= 0x200) { + myCode = start[index] & kMask12Bit; + outByte = ptk[index] & kMaskLow; + index = topStack; + stack[index] = outByte; + topStack++; + index = myCode << 1; + } + + // :singlechar + finalChar = (myCode >> 1); + outByte = finalChar & kMaskLow; + dstW.writeByte(outByte); + + // :dump + while (topStack != 0xFFFF) { // Dump the chars on the stack into the output file + outByte = stack[topStack] & kMaskLow; + dstW.writeByte(outByte); + topStack--; + } + + topStack = 0; // Won't this always be 0 because of the while loop? + code = getMember(oldCode, finalChar, findEmpty, start, ptk); + oldCode = inputCode; + } + + } + + // Return a readstream with a pointer to the data in the write stream. + // This one we do want to dispose after using, because it will be in the scope of the engine itself + return new Common::MemoryReadStream(dstW.getData(), dstW.size(), DisposeAfterUse::YES); } void setupDictionary(uint16 start[], uint16 ptk[], uint16 &findEmpty) { - // Clear the whole dictionary - for (int i = 0x3FFF; i >= 0; i--) { - start[i] = 0; - ptk[i] = 0; - } - - // Set the initial 256 bytes to be value 256, these are the characters without extensions - for (int i = 0x0FF; i >= 0; i--) { - ptk[i] = 0x100; - } - - // This shouldn't really be done inside the function, but for the sake of consistency with the source, we will - findEmpty = 0x8000; + // Clear the whole dictionary + for (int i = 0x3FFF; i >= 0; i--) { + start[i] = 0; + ptk[i] = 0; + } + + // Set the initial 256 bytes to be value 256, these are the characters without extensions + for (int i = 0x0FF; i >= 0; i--) { + ptk[i] = 0x100; + } + + // This shouldn't really be done inside the function, but for the sake of consistency with the source, we will + findEmpty = 0x8000; } int getInputCode(bool &carry, Common::File *src, int &srcLen, uint16 &evenOdd) { - // Yes, lets check this despite having already checked it before we got here... - if (srcLen == 0) { - carry = false; - return 0; - } - - uint16 c; - if (evenOdd != 0) { // Odd - srcLen--; - evenOdd--; - c = (src->readUint16LE() >> 3) & 0x00FE; // & #-1-1 - } else { // Even - srcLen -= 2; - evenOdd++; - c = (src->readUint16LE() & kMask12Bit) << 1; - src->seek(-1, SEEK_CUR); - } - return c; + // Check if we're at the end of the file + if (srcLen == 0) { + carry = false; + return 0; + } + + uint16 c; + if (evenOdd != 0) { // Odd + srcLen--; + evenOdd--; + c = (src->readUint16BE() >> 3) & 0x00FE; // & #-1-1 + } else { // Even + srcLen -= 2; + evenOdd++; + c = (src->readUint16BE() & kMask12Bit) << 1; + src->seek(-1, SEEK_CUR); + } + return c; } uint16 getMember(uint16 codeW, uint16 k, uint16 &findEmpty, uint16 start[], uint16 ptk[]) { - // This function is effectively void, as the return value is only used in compression - - // k and codeW are local variables with the value of oldCode and finalChar - - uint16 hash; - hash = (k << 3) ^ k; - hash = (hash << 1) ^ codeW; - hash <<= 1; - - hash = (hash >= 0x200) ? hash : hash + 0x200; - - uint16 a = start[hash] & 0x0F00; - uint16 b = ptk[hash] & kMaskHigh; - if (a | b) { - start[hash] = codeW; - ptk[hash] = k | 0x100; - return ptk[hash]; - } - - // This loop is a bit wacky, due to the way the jumps were stuctured in the source - bool ag = true; - while (ag == true) { - if ((start[hash] & kMask12Bit) == codeW) { - if ((ptk[hash] & kMaskLow) == k) { - return hash >> 1; - } - } - - uint16 tmp = start[hash] & kMaskLast; - if (tmp == 0) { - - // I've separated this into it's own function for the sake of this loop being readable - appendList(codeW, k, hash, findEmpty, start, ptk, tmp); - ag = false; - - } else { - tmp >>= 4; - hash &= kMaskHigh; // The 65816 can XBA to flip the bytes in a word, instead we have mask and shift over :( - hash >>= 8; - hash = (hash | tmp) << 1; - } - } - return hash; + // This function is effectively void, as the return value is only used in compression + + // k and codeW are local variables with the value of oldCode and finalChar + + uint16 hash; + hash = (k << 3) ^ k; + hash = (hash << 1) ^ codeW; + hash <<= 1; + + hash = (hash >= 0x200) ? hash : hash + 0x200; + + uint16 a = start[hash] & 0x0F00; + uint16 b = ptk[hash] & kMaskHigh; + if (a | b) { + start[hash] = codeW; + ptk[hash] = k | 0x100; + return ptk[hash]; + } + + // This loop is a bit wacky, due to the way the jumps were stuctured in the source + bool ag = true; + uint16 tmp; + while (ag == true) { + if ((start[hash] & kMask12Bit) == codeW) { + if ((ptk[hash] & kMaskLow) == k) { + return hash >> 1; + } + } + + tmp = start[hash] & kMaskLast; + if (tmp == 0) { + + // I've separated this into it's own function for the sake of this loop being readable + appendList(codeW, k, hash, findEmpty, start, ptk, tmp); + ag = false; + + } else { + tmp >>= 4; + hash = ptk[hash] & kMaskHigh; // The 65816 can XBA to flip the bytes in a word, instead we have mask and shift over :( + hash >>= 8; + hash = (hash | tmp) << 1; + } + } + return hash; } void appendList(uint16 codeW, uint16 k, uint16 &hash, uint16 &findEmpty, uint16 start[], uint16 ptk[], uint16 &tmp) { - uint16 prev; - uint16 link; - - prev = hash; - if (hash >= 0x200) { - setupDictionary(start, ptk, findEmpty); - - } else { - bool found = false; - while (found == false) { - hash -= 2; - if (hash >= 0x200) { - setupDictionary(start, ptk, findEmpty); - found = true; - } - - // Split up the conditional statement to be easier to follow - uint16 cond; - cond = start[hash] & kMaskLast; - cond |= ptk[hash]; - - if ((cond & kMaskHigh) == 0) { - findEmpty = hash; - start[hash] = codeW; - ptk[hash] = k | 0x100; - - link = hash >> 1; - tmp = link & kMaskLow; // Another classic XBA situation, although it's nicer this time - tmp <<= 8; // Because we can just grab the low bytes and shift them forward (it's still much faster to XBA though) - - ptk[prev] = (ptk[prev] & kMaskLow) | tmp; - start[prev] = ((link >> 4) & kMaskLast) | start[prev]; // Yikes this statement is gross - found = true; - } - } - } + uint16 prev; + uint16 link; + + prev = hash; + if (hash >= 0x200) { + setupDictionary(start, ptk, findEmpty); + + } else { + bool found = false; + while (found == false) { + hash -= 2; + if (hash >= 0x200) { + setupDictionary(start, ptk, findEmpty); + found = true; + } + + // Split up the conditional statement to be easier to follow + uint16 cond; + cond = start[hash] & kMaskLast; + cond |= ptk[hash]; + + if ((cond & kMaskHigh) == 0) { + findEmpty = hash; + start[hash] = codeW; + ptk[hash] = k | 0x100; + + link = hash >> 1; + tmp = link & kMaskLow; // Another classic XBA situation, although it's nicer this time + tmp <<= 8; // Because we can just grab the low bytes and shift them forward (it's still much faster to XBA though) + + ptk[prev] = (ptk[prev] & kMaskLow) | tmp; + start[prev] = ((link >> 4) & kMaskLast) | start[prev]; // Yikes this statement is gross + found = true; + } + } + } } } // namespace compression From 0c9b09a41d37ae8df342f0ce84a2eb282845ed88 Mon Sep 17 00:00:00 2001 From: Quote58 Date: Fri, 1 Jul 2022 02:41:14 -0400 Subject: [PATCH 301/412] IMMORTAL: Better comments and additional extension enum entry --- engines/immortal/disk.cpp | 12 +++++++----- engines/immortal/disk.h | 32 +++++++++++++++++--------------- 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/engines/immortal/disk.cpp b/engines/immortal/disk.cpp index 49c940182bec..eb0e82b39912 100644 --- a/engines/immortal/disk.cpp +++ b/engines/immortal/disk.cpp @@ -42,6 +42,7 @@ ProDOSFile::ProDOSFile(char name[15], uint8 type, uint16 tBlk, uint32 eof, uint1 void ProDOSFile::printInfo() { debug("File: %s", _name); debug("Type: %02X", _type); + debug("data: %d", _blockPtr); debug("Blocks: %d", _totalBlocks); debug("Size: %u\n", _eof); } @@ -288,14 +289,14 @@ void ProDOSDisk::searchDirectory(DirHeader *h, uint16 p, uint16 n, Common::Strin FileEntry fileEntry; getFileEntry(&fileEntry); - + //debug("%s", fileEntry._name); parsedFiles++; currPos = _disk.pos(); // It is a regular file if (dead < file type < pascal) and the file has a size if ((kFileTypeDead < fileEntry._type) && (fileEntry._type < kFileTypePascal) && (fileEntry._eof > 0)) { - Common::String fileName = path + fileEntry._name; - debug("%s", fileName.c_str()); + Common::String fileName = path + fileEntry._name; + debug("%s, %08X", fileName.c_str(), fileEntry._eof); ProDOSFile *currFile = new ProDOSFile(fileEntry._name, fileEntry._type, fileEntry._totalBlocks, fileEntry._eof, fileEntry._blockPtr, &_disk); _files.setVal(fileName, Common::SharedPtr(currFile)); @@ -358,7 +359,6 @@ bool ProDOSDisk::open(const Common::String filename) { VolHeader header; getVolumeHeader(&header); debug("volume name: %s", header._name); - //debug("volume created %d/%d/19%d", header._date._day, header._date._month, header._date._year); getVolumeBitmap(&header); @@ -381,11 +381,12 @@ ProDOSDisk::ProDOSDisk(const Common::String filename) { ProDOSDisk::~ProDOSDisk() { _disk.close(); _files.clear(); - delete _volBitmap; // Should this be free() instead? + free(_volBitmap); // Should this be free() or delete? } // --- Common::Archive methods --- +// Very simple, just checks if the dictionary contains the path name bool ProDOSDisk::hasFile(const Common::Path &path) const { Common::String name = path.toString(); return _files.contains(name); @@ -406,6 +407,7 @@ int ProDOSDisk::listMembers(Common::ArchiveMemberList &list) const { return f; } +// If the dictionary contains the path name (could probably call hasFile() instead), get the object const Common::ArchiveMemberPtr ProDOSDisk::getMember(const Common::Path &path) const { Common::String name = path.toString(); if (!_files.contains(name)) { diff --git a/engines/immortal/disk.h b/engines/immortal/disk.h index 8ab903b7b8e5..a6045fc4a68f 100644 --- a/engines/immortal/disk.h +++ b/engines/immortal/disk.h @@ -25,6 +25,7 @@ #include "common/memstream.h" #include "common/file.h" #include "common/debug.h" +#include "common/error.h" /* Quick note about ProDOS: * This disk code handles inactive, seedling, sapling, tree, and subdirectory files. @@ -61,6 +62,7 @@ enum FileExt { kFileExtDB = 0x19, kFileExtWord = 0x1A, kFileExtSpread = 0x1B, + kFileExtSTART = 0xB3, kFileExtPascal = 0xEF, kFileExtPDCI = 0xF0, kFileExtPDRes = 0xF9, @@ -69,7 +71,7 @@ enum FileExt { kFileExtAPSProg = 0xFC, kFileExtAPSVar = 0xFD, kFileExtEDASM = 0xFE, - kFileExtPDSys = 0xFF + kFileExtSYS = 0xFF }; /* A ProDOS file simply contains meta data about the file and the ability to @@ -83,22 +85,22 @@ class ProDOSFile : public Common::ArchiveMember { ProDOSFile(char name[16], uint8 type, uint16 tBlk, uint32 eof, uint16 bPtr, Common::File *disk); ~ProDOSFile() {}; - // These are the Common::ArchiveMember related functions - Common::String getName() const override; - Common::SeekableReadStream *createReadStream() const override; - void getDataBlock(byte *memOffset, int offset, int size) const; - int parseIndexBlock(byte *memOffset, int blockNum, int cSize) const; + // -- These are the Common::ArchiveMember related functions -- + Common::String getName() const override; // Returns _name + Common::SeekableReadStream *createReadStream() const override; // This is what the archive needs to create a file + void getDataBlock(byte *memOffset, int offset, int size) const; // Gets data up to the size of a single data block (512 bytes) + int parseIndexBlock(byte *memOffset, int blockNum, int cSize) const; // Uses getDataBlock() on every pointer in the index file, adding them to byte * memory block - // Mostly for debugging purposes, just prints the metadata + // For debugging purposes, just prints the metadata void printInfo(); private: char _name[16]; - uint8 _type; - uint16 _blockPtr; + uint8 _type; // As defined by enum FileType + uint16 _blockPtr; // Block index in volume of index block or data uint16 _totalBlocks; - uint32 _eof; - Common::File *_disk; + uint32 _eof; // End Of File, used generally as size (exception being sparse files) + Common::File *_disk; // This is a pointer because it is the same _disk as in ProDosDisk, passed to the file object }; /* This class defines the entire disk volume. Upon using the open() method, @@ -109,10 +111,10 @@ class ProDOSFile : public Common::ArchiveMember { class ProDOSDisk : public Common::Archive { public: - static const int kBlockSize = 512; // A ProDOS block is always 512 bytes + static const int kBlockSize = 512; // A ProDOS block is always 512 bytes (should this be an enum?) ProDOSDisk(const Common::String filename); - ~ProDOSDisk(); + ~ProDOSDisk(); // Frees the memory used in the dictionary and the volume bitmap // Called from the constructor, it parses the volume and fills the hashmap with files bool open(const Common::String filename); @@ -124,8 +126,8 @@ class ProDOSDisk : public Common::Archive { Common::SeekableReadStream *createReadStreamForMember(const Common::Path &path) const override; private: - byte _loader1[512]; // There's no reason these would be needed, but why not include them just in case - byte _loader2[512]; + byte _loader1[kBlockSize]; // There's not much reason for these to be needed, but I included them just in case + byte _loader2[kBlockSize]; Common::String _name; // Name of volume Common::File _disk; // The volume file itself int _volBlocks; // Total blocks in volume From 432ecfb1cf9fd2ab4d2bb8f9d0f0e9c3dfedc746 Mon Sep 17 00:00:00 2001 From: Quote58 Date: Fri, 1 Jul 2022 02:47:47 -0400 Subject: [PATCH 302/412] IMMORTAL: Preliminary translation of game loop from kernal.gs, driver.gs, and logic.gs --- engines/immortal/immortal.cpp | 146 +++++++++--- engines/immortal/immortal.h | 129 ++++++++++- engines/immortal/kernal.cpp | 419 ++++++++++++++++++++++++++++++++++ engines/immortal/logic.cpp | 45 ++++ engines/immortal/module.mk | 4 +- 5 files changed, 701 insertions(+), 42 deletions(-) create mode 100644 engines/immortal/kernal.cpp create mode 100644 engines/immortal/logic.cpp diff --git a/engines/immortal/immortal.cpp b/engines/immortal/immortal.cpp index ffa043232924..ba4f80d183d8 100644 --- a/engines/immortal/immortal.cpp +++ b/engines/immortal/immortal.cpp @@ -22,6 +22,7 @@ #include "immortal/immortal.h" #include "immortal/detection.h" #include "immortal/disk.h" +#include "immortal/compression.h" #include "common/scummsys.h" #include "common/config-manager.h" @@ -36,9 +37,6 @@ #include "engines/util.h" #include "audio/mixer.h" -#include "graphics/palette.h" -#include "graphics/surface.h" - namespace Immortal { ImmortalEngine *g_engine; @@ -49,80 +47,170 @@ ImmortalEngine::ImmortalEngine(OSystem *syst, const ADGameDescription *gameDesc) , _randomSource("Immortal") { g_engine = this; + // Add the game folder to the search manager path variable const Common::FSNode gameDataDir(ConfMan.get("path")); SearchMan.addSubDirectoryMatching(gameDataDir, "game"); + // Confirm that the engine was created debug("ImmortalEngine::ImmortalEngine"); } ImmortalEngine::~ImmortalEngine() { + _window.close(); + _font.close(); + + // Confirm that the engine was destroyed debug("ImmortalEngine::~ImmortalEngine"); } +// --- Functions to make things a little more simple --- + +uint16 ImmortalEngine::xba(uint16 ab) { + /* XBA in 65816 swaps the low and high bits of a given word in A. + * This is used very frequently, so this function just makes + * initial translation a little more straightforward. Eventually, + * logic should be refactored to not require this. + */ + return ((ab & kMaskLow) << 8) + ((ab & kMaskHigh) >> 8); +} + +uint16 ImmortalEngine::rol(uint16 ab, int n) { + /* Oops, another opcode that doesn't have a nice translation. + * This just replicates bit rotation because apparently C + * doesn't have this natively??? This assumes a 16 bit + * unsigned int because that's all we need for the 65816. + */ + return (ab << n) | (ab >> (16 - n)); +} + +uint16 ImmortalEngine::ror(uint16 ab, int n) { + /* The way this works is very straightforward. We start by + * performing the bit shift like normal: + * 0001 -> 0000 + * Then we need an easy way to apply the bit whether it fell + * off the end or not, so we bit shift the opposite direction + * for the length of the word. If the bit wouldn't have + * fallen off, then it applies a 0, but if it would have, + * then we get a 1 on the opposite bit, just like the carry. + */ + return (ab >> n) | (ab << (16 - n)); +} + +uint16 ImmortalEngine::mult16(uint16 a, uint16 b) { + /* We aren't using the game's multiplication function (mult16), but we do want + * to retain the ability to drop the second word, without doing (uint16) every time + */ + return (uint16) (a * b); +} +// ----------------------------------------------------- + uint32 ImmortalEngine::getFeatures() const { + // No specific features currently return _gameDescription->flags; } Common::String ImmortalEngine::getGameId() const { + // No game ID currently return _gameDescription->gameId; } -Common::Error ImmortalEngine::run() { - initGraphics(320, 200); - +Common::ErrorCode ImmortalEngine::initDisks() { + // Check for the boot disk if (SearchMan.hasFile("IMMORTAL.dsk")) { - ProDosDisk *diskBoot = new ProDosDisk("IMMORTAL.dsk"); + + // Instantiate the disk as an object. The disk will then open and parse itself + ProDOSDisk *diskBoot = new ProDOSDisk("IMMORTAL.dsk"); if (diskBoot) { + + // With the disk successfully parsed, it can be added to the search manager debug("Boot disk found"); SearchMan.add("IMMORTAL.dsk", diskBoot, 0, true); } + } else { + debug("Please insert Boot disk..."); + return Common::kPathDoesNotExist; } + // Check for the gfx disk if (SearchMan.hasFile("IMMORTAL_GFX.dsk")) { - ProDosDisk *diskGFX = new ProDosDisk("IMMORTAL_GFX.dsk"); + ProDOSDisk *diskGFX = new ProDOSDisk("IMMORTAL_GFX.dsk"); if (diskGFX) { debug("Gfx disk found"); SearchMan.add("IMMORTAL_GFX.dsk", diskGFX, 0, true); } + } else { + debug("Please insert GFX disk..."); + return Common::kPathDoesNotExist; } - Common::File f; - if (!f.open("LOAD.OBJ")) { - debug("oh no :("); - } + // All good, return with no error + return Common::kNoError; +} - debug("first file loaded"); - f.close(); +Common::Error ImmortalEngine::run() { + initGraphics(_resH, _resV); - Common::File f2; - if (!f2.open("GOBLIN.SPR")) { - debug("oh no :(("); - } + _mainSurface = new Graphics::Surface(); + _mainSurface->create(_resH, _resV, Graphics::PixelFormat::createFormatCLUT8()); + + _screenBuff = new byte[_screenSize]; - debug("second file loaded"); - f2.close(); + if (initDisks() != Common::kNoError) { + debug("Some kind of disc error!"); + return Common::kPathDoesNotExist; + } + //Main: + _zero = 0; + _dim = 0; + _usingNormal = 0; + _draw = 1; + + loadPalette(); // We need to grab the palette from the disk first + useNormal(); // The first palette will be the default + loadFont(); // Load the font sprite + loadWindow(); // Load the window background + loadSingles("Song A"); // Music + loadSprites(); // Get all the sprite data into memory + // playing = kPlayingNothing; + // themepaused = 0; + clearSprites(); // Clear the sprites before we start + logicInit(); // Init the game logic while (!shouldQuit()) { - + + /* The game loop runs at 60fps, which is 16 milliseconds per frame. + * This loop keeps that time by getting the time in milliseconds at the start of the loop, + * then again at the end, and the difference between them is the remainder + * of the frame budget. If that remainder is within the 16 millisecond budget, + * then it delays ScummVM for the remainder. If it is 0 or negative, then it continues. + */ int64 loopStart = g_system->getMillis(); - Common::Event event; - g_system->getEventManager()->pollEvent(event); + + // Kernal main function + int err = main(); + + if (err != Common::kNoError) { + debug("To err is human, to really screw up you need an Apple IIGS!"); + return Common::kUnknownError; + } int64 loopEnd = 16 - (g_system->getMillis() - loopStart); - if (loopEnd > 0) + if (loopEnd > 0) { + //debug("remaining budget: %d", loopEnd); g_system->delayMillis(loopEnd); + } } return Common::kNoError; - } Common::Error ImmortalEngine::syncGame(Common::Serializer &s) { - // The Serializer has methods isLoading() and isSaving() - // if you need to specific steps; for example setting - // an array size after reading it's length, whereas - // for saving it would write the existing array's length + /* The Serializer has methods isLoading() and isSaving() + * if you need to specific steps; for example setting + * an array size after reading it's length, whereas + * for saving it would write the existing array's length + */ int dummy = 0; s.syncAsUint32LE(dummy); diff --git a/engines/immortal/immortal.h b/engines/immortal/immortal.h index fc64b0f2f732..ced4ac04a649 100644 --- a/engines/immortal/immortal.h +++ b/engines/immortal/immortal.h @@ -28,6 +28,8 @@ #include "common/system.h" #include "common/error.h" #include "common/fs.h" +#include "common/file.h" +#include "common/memstream.h" #include "common/hash-str.h" #include "common/random.h" #include "common/serializer.h" @@ -39,10 +41,37 @@ #include "graphics/screen.h" #include "immortal/detection.h" +#include "graphics/palette.h" +#include "graphics/surface.h" namespace Immortal { +enum BitMask16 : uint16 { + kMaskLow = 0x00FF, + kMaskHigh = 0xFF00, + kMaskLast = 0xF000, + kMaskFirst = 0x000F, + kMaskHLow = 0x0F00, + kMaskLHigh = 0x00F0, + kMaskNeg = 0x8000, +}; + +enum BitMask8 : uint8 { + kMaskASCII = 0x7F, // the non-extended ASCII table uses 7 bits, this makes a couple of things easier + kMask8High = 0xF0, + kMask8Low = 0x0F, +}; + + +enum ColourMask : uint16 { + kMaskRed = 0x0F00, + kMaskGreen = 0x00F0, + kMaskBlue = 0x000F +}; + struct ImmortalGameDescription; + +// Forward declaration because we will need the Disk class class ProDosDisk; class ImmortalEngine : public Engine { @@ -52,22 +81,99 @@ class ImmortalEngine : public Engine { protected: // Engine APIs Common::Error run() override; -public: - const ADGameDescription *_gameDescription; public: ImmortalEngine(OSystem *syst, const ADGameDescription *gameDesc); ~ImmortalEngine() override; - uint32 getFeatures() const; + /* Terrible functions because C doesn't like + * bit manipulation enough + */ + uint16 xba(uint16 ab); // This just replicates the XBA command from the 65816, because flipping the byte order is somehow not a common library function??? + uint16 rol(uint16 ab, int n); // Rotate bits left by n + uint16 ror(uint16 ab, int n); // Rotate bits right by n + uint16 mult16(uint16 a, uint16 b); // Just avoids using (uint16) everywhere, and is slightly closer to the original - /** - * Returns the game Id + const ADGameDescription *_gameDescription; + + /* 'global' members + */ + bool _draw; // Whether the screen should draw this frame + bool _dim; // Whether the palette is dim + bool _usingNormal; // Whether the palette is using normal + int _zero; // No idea what this is yet + Common::File _window; // Bitmap of the window around the game + Common::File _font; // The gfx for font sprites? Why is this not done with tilemaps... + + Common::HashMap _sprites; // Dictionary containing all sprites + + /* Screen related members */ - Common::String getGameId() const; + Graphics::Surface *_mainSurface; + byte *_screenBuff; // The final buffer that will transfer to the screen + const int _resH = 320; + const int _resV = 200; + const int _screenSize = (_resH * _resV) * 2; // The size of the screen buffer is 320x200 - /** - * Gets a random number + /* Palette related members + */ + const int kPaletteOffset = 21205; // This is the byte position of the palette data in the disk + uint16 _palDefault[16]; + uint16 _palWhite[16]; + uint16 _palBlack[16]; + uint16 _palDim[16]; + byte _palRGB[48]; // Palette that ScummVM actually uses, which is an RGB conversion of the original + int _dontResetColors = 0; // Not sure yet + + /* Functions from Kernal.gs and Driver.gs + */ + + // Palette functions + void loadPalette(); // Get the static palette data from the disk + void setColors(uint16 pal[]); // Applies the current palette to the ScummVM surface palette + void fixColors(); // Determine whether the screen should be dim or normal + void useNormal(); + void useDim(); + void useBlack(); + void useWhite(); + void pump(); // Alternates between white and black with delays in between (flashes screen) + void fadePal(uint16 pal[], int count, uint16 target[]); // Fades the palette except the frame + void fade(uint16 pal[], int dir, int delay); // Calls fadePal() by a given delay each iteration + void fadeOut(int j); // Calls Fade with a delay of j jiffies and direction 1 + void fadeIn(int j); // || and direction 0 + + void delay(int j); // Delay engine by j jiffies + void delay4(int j); // || /4 + void delay8(int j); // || /8 + + Common::ErrorCode main(); // Main game loop + void loadWindow(); // Gets the window.bm file + void loadFont(); // Gets the font.spr file, and centers the sprite + Common::SeekableReadStream *loadIFF(Common::String fileName); // Loads a file and uncompresses if it is compressed + void loadSingles(Common::String songName); // Loads and then parse the maze song + void loadSprites(); // Loads all the sprite files and centers their sprites (in spritelist, but called from kernal) + void clearSprites(); // Clears all sprites before drawing the current frame + //void Misc::textPrint(int num); + void logicInit(); + void userIO(); // Get input + void pollKeys(); // Buffer input + void noNetwork(); // Setup input mirrors + void keyTraps(); // Seems to be debug only + void logic(); // Keeps time, handles win and lose conditions, then general logic + void restartLogic(); // This is the actual logic init + int logicFreeze(); // Overcomplicated way to check if game over or level over + void drawUniv(); // Draw the background, add the sprites, determine draw order, draw the sprites + + void copyToScreen(); // If draw is 0, just check input, otherwise also copy the screen buffer to the scummvm surface and update screen + void clearScreen(); // Draws a black rectangle on the screen buffer but only inside the frame + + /* General engine functions + */ + Common::ErrorCode initDisks(); // Opens and parses IMMORTAL.dsk and IMMORTAL_GFX.dsk + uint32 getFeatures() const; // Returns the game description flags + Common::String getGameId() const; // Returns the game Id + + /* Gets a random number */ uint32 getRandomNumber(uint maxNum) { return _randomSource.getRandomNumber(maxNum); @@ -87,8 +193,7 @@ class ImmortalEngine : public Engine { return true; } - /** - * Uses a serializer to allow implementing savegame + /* Uses a serializer to allow implementing savegame * loading and saving using a single method */ Common::Error syncGame(Common::Serializer &s); @@ -96,9 +201,9 @@ class ImmortalEngine : public Engine { /* Common::Error saveGameStream(Common::WriteStream *stream, bool isAutosave = false) { Common::Serializer s(nullptr, stream); return syncGame(s); - } */ + } - /* Common::Error loadGameStream(Common::SeekableReadStream *stream) { + Common::Error loadGameStream(Common::SeekableReadStream *stream) { Common::Serializer s(stream, nullptr); return syncGame(s); } */ diff --git a/engines/immortal/kernal.cpp b/engines/immortal/kernal.cpp new file mode 100644 index 000000000000..284245ff6add --- /dev/null +++ b/engines/immortal/kernal.cpp @@ -0,0 +1,419 @@ +/* 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 . + * + */ + +/* This file covers both Kernal.GS and Driver.GS. + * This is because most of Driver.GS is hardware specific, + * and what is not (the slightly abstracted aspects), is + * directly connected to kernal, and might as well be + * considered part of the same process. + */ + +#include "common/debug.h" +#include "common/error.h" +#include "common/events.h" + +#include "immortal/immortal.h" +#include "immortal/disk.h" +#include "immortal/compression.h" + +namespace Immortal { + +/* + * + * ----- ----- + * ----- Main Functions ----- + * ----- ----- + * + */ + +Common::ErrorCode ImmortalEngine::main() { + Common::Event event; + g_system->getEventManager()->pollEvent(event); + + userIO(); + noNetwork(); + pollKeys(); + logic(); + pollKeys(); + if (logicFreeze() == 0) { + drawUniv(); + pollKeys(); + fixColors(); + copyToScreen(); + pollKeys(); + } + + return Common::kNoError; +} + +void ImmortalEngine::delay(int j) { // Delay is measured in jiffies, which are 56.17ms + g_system->delayMillis(j * 56); +} + +void ImmortalEngine::delay4(int j) { // Named in source quarterClock for some reason, 1/4 jiffies are 14.04ms + g_system->delayMillis(j * 14); +} + +void ImmortalEngine::delay8(int j) { // 1/8 jiffies are 7.02ms + g_system->delayMillis(j * 7); +} + +/* + * + * ----- ----- + * ----- Screen Drawing Functions ----- + * ----- ----- + * + */ + +void ImmortalEngine::drawUniv() { + /* The byte buffer for the screen (_screenBuff) has one byte for + * every pixel, with the resolution of the game being 320x200. + * For a bitmap like the window frame, all we need to do is + * extract the pixel out of each nyble (half byte) of the data, + * by looping over it one row at a time. + */ + + // Apply the window frame to the buffer + _window.seek(0); + byte pixel; + int pos; + for (int y = 0; y < _resV; y++) { + for (int x = 0; x < _resH; x += 2) { + pos = (y * _resH) + x; + pixel = _window.readByte(); + _screenBuff[pos] = (pixel & kMask8High) >> 4; + _screenBuff[pos + 1] = pixel & kMask8Low; + } + } + + /* copyRectToSurface will apply the screenbuffer to the ScummVM surface. + * We want to do 320 bytes per scanline, at location (0,0), with a + * size of 320x200. + */ + _mainSurface->copyRectToSurface(_screenBuff, _resH, 0, 0, _resH, _resV); + +} + +void ImmortalEngine::copyToScreen() { + if (_draw == 1) { + g_system->copyRectToScreen((byte *)_mainSurface->getPixels(), _resH, 0, 0, _resH, _resV); + g_system->updateScreen(); + } +} + +void ImmortalEngine::clearScreen() { + //fill the visible screen with black pixels by drawing a rectangle + + //rect(32, 20, 256, 128, 0) + + if ((_dontResetColors & kMaskLow) == 0) { + useNormal(); + } +} + +/* + * + * ----- ----- + * ----- File Loading ----- + * ----- ----- + * + */ + +void ImmortalEngine::loadSprites() { + // Load MoreSprites.spr + + +} + +void ImmortalEngine::loadWindow() { + // Initialize the window bitmap + if (!_window.open("WINDOWS.BM")) { + debug("oh nose :("); + } +} + +void ImmortalEngine::loadFont() { + // Initialize the font sprite + if (!_font.open("FONT.SPR")) { + debug("oh nose :("); + } +} + +Common::SeekableReadStream *ImmortalEngine::loadIFF(Common::String fileName) { + Common::File f; + if (!f.open(fileName)) { + debug("*surprised pikachu face*"); + return nullptr; + } + + /* This isn't the most efficient way to do this (could just read a 32bit uint and compare), + * but this makes it more obvious what the source was doing. We want to know if the 4 bytes + * at file[8] are 'C' 'M' 'P' '0', so this grabs just the ascii bits of those 4 bytes, + * allowing us to directly compare it with 'CMP0'. + */ + char compSig[] = "CMP0"; + char sig[] = "0000"; + + f.seek(8); + + for (int i = 0; i < 4; i++) { + sig[i] = f.readByte() & kMaskASCII; + } + + if (strcmp(sig, compSig) == 0) { + debug("compressed"); + + /* The size of the compressed data is stored in the header, but doesn't + * account for the FORM part?? Also, **technically** this is a uint32LE, + * but the engine itself actually /doesn't/ use it like that. It only + * decrements the first word (although it compares against the second half, + * as if it is expecting that to be zero? It's a little bizarre). + */ + f.seek(6); + int len = f.readUint16LE() - 4; + + // Compressed files have a 12 byte header before the data + f.seek(12); + return Compression::unCompress(&f, len); + } + + byte *out = (byte *)malloc(f.size()); + f.read(out, f.size()); + return new Common::MemoryReadStream(out, f.size(), DisposeAfterUse::YES); + +} + + +/* + * + * ----- ----- + * ----- Palette Functions ----- + * ----- ----- + * + */ + +/* Palettes on the Apple IIGS: + * In High-res mode you have 2 options: 320x200 @ 4bpp or 320x640 @ 2bpp. + * The Immortal uses the former, giving us 16 colours to use + * for any given pixel on the screen (ignoring per scanline palettes because + * The Immortal does not use them). This 16 colour palette is made of 2 byte + * words containing the RGB components in the form 0RGB. + * + * The equivalent palette for ScummVM is a byte stream of up to 256 + * colours composed of 3 bytes each, ending with a transparency byte. + * + * Because each colour in the game palette is only a single nyble (4 bits), + * we also need to multiply the nyble up to the size of a byte (* 16, or << 4). + */ + +void ImmortalEngine::loadPalette() { + // The palettes are stored at a particular location in the disk, this just grabs them + Common::File d; + d.open("IMMORTAL.dsk"); + d.seek(kPaletteOffset); + + d.read(_palDefault, 32); + d.read(_palWhite, 32); + d.read(_palBlack, 32); + d.read(_palDim, 32); + + d.close(); +} + +void ImmortalEngine::setColors(uint16 pal[]) { + // The RGB palette is 3 bytes per entry, and each byte is a colour + for (int i = 0; i < 16; i++) { + + // The palette gets masked so it can update only specific indexes and uses FFFF to do so. However the check is simply for a negative + if (pal[i] < kMaskNeg) { + + // Green is already the correct size, being the second nyble (00G0) + // Red is in the first nyble of the high byte, so it needs to move right by 4 bits (0R00 -> 00R0) + // Blue is the first nyble of the first byte, so it needs to move left by 4 bits (000B -> 00B0) + _palRGB[(i * 3)] = ((pal[i] & kMaskRed) >> 4); + _palRGB[(i * 3) + 1] = ((pal[i] & kMaskGreen)); + _palRGB[(i * 3) + 2] = (pal[i] & kMaskBlue) << 4; + } + } + // Palette index to update first is 0, and there are 16 colours to update + g_system->getPaletteManager()->setPalette(_palRGB, 0, 16); + g_system->updateScreen(); +} + +void ImmortalEngine::fixColors() { + // Pretty silly that this is done with two separate variables, could just index by one... + if (_dim == true) { + if (_usingNormal == true) { + useDim(); + } + } else { + if (_usingNormal == false) { + useNormal(); + } + } +} + +void ImmortalEngine::pump() { + // Flashes the screen (except the frame thankfully) white, black, white, black, then clears the screen and goes back to normal + useWhite(); + g_system->updateScreen(); + delay(2); + useBlack(); + g_system->updateScreen(); + delay(2); + useWhite(); + g_system->updateScreen(); + delay(2); + useBlack(); + g_system->updateScreen(); + clearScreen(); + // Why does it do this instead of setting _dontResetColors for clearScreen() instead? + useNormal(); +} + +void ImmortalEngine::fadePal(uint16 pal[], int count, uint16 target[]) { + /* This will fade the palette used by everything inside the game screen + * but will not touch the window frame palette. It essentially takes the + * color value nyble, multiplies it by a multiplier, then takes the whole + * number result and inserts it into the word at the palette index of the + * temporary palette. This could I'm sure be done with regular multiplication + * and division operators, but in case the bits that get dropped are otherwise + * kept, this is a direct translation of the bit manipulation sequence. + */ + int maskPal[16] = {0xFFFF, 0x0000, 0x0000, 0x0000, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF}; + + uint16 result; + uint16 temp; + + for (int i = 15; i >= 0; i--) { + result = maskPal[i]; + if (result == 0) { + result = pal[i]; + if (result != 0xFFFF) { + // Blue = 0RGB -> 000B -> 0BBB -> BB0B -> 000B + result = (xba(mult16((result & kMaskFirst), count))) & kMaskFirst; + + // Green = 0RGB -> 00RG -> 000G -> 0GGG -> GG0G -> 000G -> 00G0 -> 00GB + temp = mult16(((pal[i] >> 4) & kMaskFirst), count); + temp = (xba(temp) & kMaskFirst) << 4; + result = temp | result; + + // Red = 0RGB -> GB0R -> 000R -> 0RRR -> RR0R -> 000R -> 0R00 -> 0RGB + temp = xba(pal[i]) & kMaskFirst; + temp = xba(mult16(temp, count)); + temp = xba(temp & kMaskFirst); + result = temp | result; + } + } + target[i] = result; + } +} + +void ImmortalEngine::fade(uint16 pal[], int dir, int delay) { + // This temp palette will have FFFF in it, which will be understood as masks by setColors() + uint16 target[16]; + uint16 count; + + // Originally used a branch, but this is functionally identical and much nicer + count = dir * 256; + + while ((count >= 0) && (count <= 256)) { + fadePal(pal, count, target); + delay8(delay); + setColors(target); + + // Same as above, it was originally a branch, this does the same thing + count += (dir == 0) ? 16 : -16; + } +} + +// These two can probably be removed and instead use an enum to declare fadeout/in +void ImmortalEngine::fadeOut(int j) { + fade(_palDefault, 1, j); +} + +void ImmortalEngine::fadeIn(int j) { + fade(_palDefault, 0, j); +} + +// These two can probably be removed since the extra call in C doesn't have the setup needed in ASM +void ImmortalEngine::useBlack() { + setColors(_palBlack); +} +void ImmortalEngine::useWhite() { + setColors(_palBlack); +} + +void ImmortalEngine::useNormal() { + setColors(_palDefault); + _usingNormal = true; +} + +void ImmortalEngine::useDim() { + setColors(_palDim); + _usingNormal = false; +} + + +/* + * + * ----- ----- + * ----- Input Functions ----- + * ----- ----- + * + */ + +void ImmortalEngine::userIO() {} +void ImmortalEngine::pollKeys() {} +void ImmortalEngine::noNetwork() {} + +void ImmortalEngine::loadSingles(Common::String songName) { + debug("%s", songName.c_str()); +} +void ImmortalEngine::clearSprites() {} +void ImmortalEngine::keyTraps() {} + + +} // namespace Immortal + + + + + + + + + + + + + + + + + + + + diff --git a/engines/immortal/logic.cpp b/engines/immortal/logic.cpp new file mode 100644 index 000000000000..8a1fd3a7474c --- /dev/null +++ b/engines/immortal/logic.cpp @@ -0,0 +1,45 @@ +/* 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/debug.h" +#include "common/error.h" +#include "common/events.h" + +#include "immortal/immortal.h" + +namespace Immortal { + +void ImmortalEngine::logicInit() { + debug("init logic here"); +} + +void ImmortalEngine::logic() { +} + +void ImmortalEngine::restartLogic() { +} + +int ImmortalEngine::logicFreeze() { + return 0; +} + + +} // namespace Immortal \ No newline at end of file diff --git a/engines/immortal/module.mk b/engines/immortal/module.mk index 15d7f541677d..b3ba49aaff96 100644 --- a/engines/immortal/module.mk +++ b/engines/immortal/module.mk @@ -4,7 +4,9 @@ MODULE_OBJS = \ immortal.o \ disk.o \ metaengine.o \ - compression.o + compression.o \ + kernal.o \ + logic.o # This module can be built as a plugin ifeq ($(ENABLE_IMMORTAL), DYNAMIC_PLUGIN) From e8d06bf6b601e81fbfd251f6f2eadb9cd458db24 Mon Sep 17 00:00:00 2001 From: Quote58 Date: Wed, 6 Jul 2022 02:00:17 -0400 Subject: [PATCH 303/412] IMMORTAL: Disk.cpp bug fix to parse correct number of files --- engines/immortal/disk.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/engines/immortal/disk.cpp b/engines/immortal/disk.cpp index eb0e82b39912..f92501183c1b 100644 --- a/engines/immortal/disk.cpp +++ b/engines/immortal/disk.cpp @@ -278,9 +278,8 @@ void ProDOSDisk::searchDirectory(DirHeader *h, uint16 p, uint16 n, Common::Strin int parsedFiles = 0; for (int i = 0; i < h->_fileCount; i++) { - // When we have read all the files for a given block (_entriesPerBlock), we need to change to the next block of the directory - if (parsedFiles > h->_entriesPerBlock) { + if (parsedFiles == h->_entriesPerBlock) { parsedFiles = 0; _disk.seek(n * kBlockSize); p = _disk.readUint16LE(); @@ -295,8 +294,8 @@ void ProDOSDisk::searchDirectory(DirHeader *h, uint16 p, uint16 n, Common::Strin // It is a regular file if (dead < file type < pascal) and the file has a size if ((kFileTypeDead < fileEntry._type) && (fileEntry._type < kFileTypePascal) && (fileEntry._eof > 0)) { - Common::String fileName = path + fileEntry._name; - debug("%s, %08X", fileName.c_str(), fileEntry._eof); + Common::String fileName = path + fileEntry._name; + debug("%s", fileName.c_str()); ProDOSFile *currFile = new ProDOSFile(fileEntry._name, fileEntry._type, fileEntry._totalBlocks, fileEntry._eof, fileEntry._blockPtr, &_disk); _files.setVal(fileName, Common::SharedPtr(currFile)); @@ -313,8 +312,8 @@ void ProDOSDisk::searchDirectory(DirHeader *h, uint16 p, uint16 n, Common::Strin DirHeader subHead; getDirectoryHeader(&subHead); - path += Common::String(subHead._name); - path += '/'; + // Give it a temporary new path name by sticking the name of the subdirectory on to the end of the current path + Common::String subPath = Common::String(path + subHead._name + '/'); searchDirectory(&subHead, subP, subN, path); debug("--- surfacing to parent directory ---"); From d77cc8f5db2d7d34ab8b353bb8743b81cf807aed Mon Sep 17 00:00:00 2001 From: Quote58 Date: Sat, 9 Jul 2022 15:37:25 -0400 Subject: [PATCH 304/412] IMMORTAL: Compression is part of engine class, also minor changes to a couple of statements --- engines/immortal/compression.cpp | 58 ++++------ engines/immortal/compression.h | 39 ------- engines/immortal/immortal.h | 182 +++++++++++++++++++++++++------ 3 files changed, 170 insertions(+), 109 deletions(-) delete mode 100644 engines/immortal/compression.h diff --git a/engines/immortal/compression.cpp b/engines/immortal/compression.cpp index 03cd608c68c6..5a9dba9ffa58 100644 --- a/engines/immortal/compression.cpp +++ b/engines/immortal/compression.cpp @@ -19,10 +19,7 @@ * */ -#include "common/debug.h" -#include "common/file.h" -#include "common/memstream.h" -#include "immortal/compression.h" +#include "immortal/immortal.h" /* Decompression: * This decompression algorithm follows the source assembly very closely, @@ -30,17 +27,9 @@ * In: Source data as File, size of data * Out: Pointer to uncompressed data as SeekableReadStream */ -namespace Compression { +namespace Immortal { -// There is a lot of bit masking that needs to happen, so this enum makes it a little easier to read -enum BitMask : uint16 { - kMask12Bit = 0x0F9F, // Code (pos, 00, len) is stored in lower 12 bits of word - kMaskLow = 0x00FF, - kMaskHigh = 0xFF00, - kMaskLast = 0xF000 -}; - -Common::SeekableReadStream *unCompress(Common::File *src, int srcLen) { +Common::SeekableReadStream *ImmortalEngine::unCompress(Common::File *src, int srcLen) { /* Note: this function does not seek() in the file, which means * that if there is a header on the data, the expectation is that * seek() was already used to move past the header before this function. @@ -136,19 +125,20 @@ Common::SeekableReadStream *unCompress(Common::File *src, int srcLen) { topStack--; } - topStack = 0; // Won't this always be 0 because of the while loop? + topStack = 0; code = getMember(oldCode, finalChar, findEmpty, start, ptk); oldCode = inputCode; } } - // Return a readstream with a pointer to the data in the write stream. - // This one we do want to dispose after using, because it will be in the scope of the engine itself + /* Return a readstream with a pointer to the data in the write stream. + * This one we do want to dispose after using, because it will be in the scope of the engine itself + */ return new Common::MemoryReadStream(dstW.getData(), dstW.size(), DisposeAfterUse::YES); } -void setupDictionary(uint16 start[], uint16 ptk[], uint16 &findEmpty) { +void ImmortalEngine::setupDictionary(uint16 start[], uint16 ptk[], uint16 &findEmpty) { // Clear the whole dictionary for (int i = 0x3FFF; i >= 0; i--) { start[i] = 0; @@ -156,15 +146,15 @@ void setupDictionary(uint16 start[], uint16 ptk[], uint16 &findEmpty) { } // Set the initial 256 bytes to be value 256, these are the characters without extensions - for (int i = 0x0FF; i >= 0; i--) { - ptk[i] = 0x100; + for (int i = 255; i >= 0; i--) { + ptk[i] = 256; } // This shouldn't really be done inside the function, but for the sake of consistency with the source, we will findEmpty = 0x8000; } -int getInputCode(bool &carry, Common::File *src, int &srcLen, uint16 &evenOdd) { +int ImmortalEngine::getInputCode(bool &carry, Common::File *src, int &srcLen, uint16 &evenOdd) { // Check if we're at the end of the file if (srcLen == 0) { carry = false; @@ -185,12 +175,15 @@ int getInputCode(bool &carry, Common::File *src, int &srcLen, uint16 &evenOdd) { return c; } -uint16 getMember(uint16 codeW, uint16 k, uint16 &findEmpty, uint16 start[], uint16 ptk[]) { +uint16 ImmortalEngine::getMember(uint16 codeW, uint16 k, uint16 &findEmpty, uint16 start[], uint16 ptk[]) { // This function is effectively void, as the return value is only used in compression // k and codeW are local variables with the value of oldCode and finalChar uint16 hash; + uint16 tmp; + bool ag = true; + hash = (k << 3) ^ k; hash = (hash << 1) ^ codeW; hash <<= 1; @@ -206,8 +199,6 @@ uint16 getMember(uint16 codeW, uint16 k, uint16 &findEmpty, uint16 start[], uint } // This loop is a bit wacky, due to the way the jumps were stuctured in the source - bool ag = true; - uint16 tmp; while (ag == true) { if ((start[hash] & kMask12Bit) == codeW) { if ((ptk[hash] & kMaskLow) == k) { @@ -217,22 +208,20 @@ uint16 getMember(uint16 codeW, uint16 k, uint16 &findEmpty, uint16 start[], uint tmp = start[hash] & kMaskLast; if (tmp == 0) { - // I've separated this into it's own function for the sake of this loop being readable appendList(codeW, k, hash, findEmpty, start, ptk, tmp); ag = false; } else { - tmp >>= 4; - hash = ptk[hash] & kMaskHigh; // The 65816 can XBA to flip the bytes in a word, instead we have mask and shift over :( - hash >>= 8; - hash = (hash | tmp) << 1; + hash = xba(ptk[hash]); + hash = (hash & kMaskLow) | (tmp >> 4); + hash <<= 1; } } return hash; } -void appendList(uint16 codeW, uint16 k, uint16 &hash, uint16 &findEmpty, uint16 start[], uint16 ptk[], uint16 &tmp) { +void ImmortalEngine::appendList(uint16 codeW, uint16 k, uint16 &hash, uint16 &findEmpty, uint16 start[], uint16 ptk[], uint16 &tmp) { uint16 prev; uint16 link; @@ -260,18 +249,17 @@ void appendList(uint16 codeW, uint16 k, uint16 &hash, uint16 &findEmpty, uint16 ptk[hash] = k | 0x100; link = hash >> 1; - tmp = link & kMaskLow; // Another classic XBA situation, although it's nicer this time - tmp <<= 8; // Because we can just grab the low bytes and shift them forward (it's still much faster to XBA though) - ptk[prev] = (ptk[prev] & kMaskLow) | tmp; - start[prev] = ((link >> 4) & kMaskLast) | start[prev]; // Yikes this statement is gross + ptk[prev] = (link << 8) | (ptk[prev] & kMaskLow); + //start[prev] = ((link >> 4) & kMaskLast) | start[prev]; // Yikes this statement is gross + start[prev] |= (link >> 4) & kMaskLast; found = true; } } } } -} // namespace compression +} // namespace immortal diff --git a/engines/immortal/compression.h b/engines/immortal/compression.h deleted file mode 100644 index 96633758e0b8..000000000000 --- a/engines/immortal/compression.h +++ /dev/null @@ -1,39 +0,0 @@ - /* 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 . - * - */ - -#ifndef IMMORTAL_COMPRESSION_H -#define IMMORTAL_COMPRESSION_H - -#include "common/file.h" -#include "common/memstream.h" - -namespace Compression { - -// Only unCompress() is called from outside Compression, the others are subroutines. -Common::SeekableReadStream *unCompress(Common::File *src, int srcLen); -void setupDictionary(uint16 start[], uint16 ptk[], uint16 &findEmpty); -int getInputCode(bool &carry, Common::File *src, int &srcLen, uint16 &evenOdd); -uint16 getMember(uint16 codeW, uint16 k, uint16 &findEmpty, uint16 start[], uint16 ptk[]); -void appendList(uint16 codeW, uint16 k, uint16 &hash, uint16 &findEmpty, uint16 start[], uint16 ptk[], uint16 &tmp); - -} // namespace compression - -#endif \ No newline at end of file diff --git a/engines/immortal/immortal.h b/engines/immortal/immortal.h index ced4ac04a649..62412401bdfb 100644 --- a/engines/immortal/immortal.h +++ b/engines/immortal/immortal.h @@ -24,6 +24,8 @@ #include "audio/mixer.h" +#include "common/debug.h" +#include "common/events.h" #include "common/scummsys.h" #include "common/system.h" #include "common/error.h" @@ -38,14 +40,19 @@ #include "engines/engine.h" #include "engines/savestate.h" -#include "graphics/screen.h" -#include "immortal/detection.h" +#include "graphics/screen.h" #include "graphics/palette.h" #include "graphics/surface.h" +#include "immortal/detection.h" +#include "immortal/disk.h" + namespace Immortal { +#include "immortal/sprite_list.h" + +// There is a lot of bit masking that needs to happen, so this enum makes it a little easier to read enum BitMask16 : uint16 { kMaskLow = 0x00FF, kMaskHigh = 0xFF00, @@ -54,12 +61,13 @@ enum BitMask16 : uint16 { kMaskHLow = 0x0F00, kMaskLHigh = 0x00F0, kMaskNeg = 0x8000, + kMask12Bit = 0x0F9F // Compression code (pos, 00, len) is stored in lower 12 bits of word }; enum BitMask8 : uint8 { - kMaskASCII = 0x7F, // the non-extended ASCII table uses 7 bits, this makes a couple of things easier + kMaskASCII = 0x7F, // The non-extended ASCII table uses 7 bits, this makes a couple of things easier kMask8High = 0xF0, - kMask8Low = 0x0F, + kMask8Low = 0x0F }; @@ -69,6 +77,23 @@ enum ColourMask : uint16 { kMaskBlue = 0x000F }; +struct DataSprite { + uint8 _cenX; // These are the base center positions + uint8 _cenY; + byte *_bitmap; // Pointer to actual data +Common::SeekableReadStream *_file; // This will likely be removed later +}; + +struct Sprite { + uint16 _frame; // Something something background? + uint16 _activeFrame; // Why the heck is this inside the individual sprite data? + uint16 _X; + uint16 _Y; + uint16 _on; // 1 = active + uint16 _priority; +DataSprite _dSprite; +}; + struct ImmortalGameDescription; // Forward declaration because we will need the Disk class @@ -96,26 +121,54 @@ class ImmortalEngine : public Engine { const ADGameDescription *_gameDescription; - /* 'global' members + /* + * --- Members --- + * */ - bool _draw; // Whether the screen should draw this frame - bool _dim; // Whether the palette is dim - bool _usingNormal; // Whether the palette is using normal - int _zero; // No idea what this is yet - Common::File _window; // Bitmap of the window around the game - Common::File _font; // The gfx for font sprites? Why is this not done with tilemaps... - Common::HashMap _sprites; // Dictionary containing all sprites + /* + * Constants + */ + const int kResH = 320; + const int kResV = 200; + const int kScreenSize = (kResH * kResV) * 2; // The size of the screen buffer is 320x200 + const int kMaxSprites = 32; // Number of sprites allowed at once + const int kWizardX = 28; // Common sprite center for some reason + const int kWizardY = 37; + + /* + * 'global' members + */ + bool _draw = 0; // Whether the screen should draw this frame + bool _dim = 0; // Whether the palette is dim + bool _usingNormal = 0; // Whether the palette is using normal + int _zero = 0; // No idea what this is yet + uint8 _gameOverFlag = 0; + uint8 _levelOver = 0; + uint8 _themePaused = 0; + int _level = 0; + int _titlesShown = 0; + int _time = 0; + int _promoting = 0; + int _restart = 0; + int _lastCertLen = 0; + + /* + * Asset related members + */ + DataSprite _font; // The font sprite data is loaded separate from other sprite stuff + byte *_window; // Bitmap of the window around the game + Sprite _sprites[32]; // A contiguous series of sprites (this is the same as kMaxSprites, but it can't be used for this) + DataSprite _dataSprites[kFont+1]; // All the sprite data, indexed by SpriteFile - /* Screen related members + /* + * Screen related members */ Graphics::Surface *_mainSurface; byte *_screenBuff; // The final buffer that will transfer to the screen - const int _resH = 320; - const int _resV = 200; - const int _screenSize = (_resH * _resV) * 2; // The size of the screen buffer is 320x200 - /* Palette related members + /* + * Palette related members */ const int kPaletteOffset = 21205; // This is the byte position of the palette data in the disk uint16 _palDefault[16]; @@ -125,10 +178,32 @@ class ImmortalEngine : public Engine { byte _palRGB[48]; // Palette that ScummVM actually uses, which is an RGB conversion of the original int _dontResetColors = 0; // Not sure yet - /* Functions from Kernal.gs and Driver.gs + + + /* + * --- Functions --- + * */ - // Palette functions + /* + * [Kernal.cpp] Functions from Kernal.gs and Driver.gs + */ + + Common::ErrorCode main(); // Main game loop + + // Screen + void clearScreen(); // Draws a black rectangle on the screen buffer but only inside the frame + void whiteScreen(); // Draws a white rectanlge on the screen buffer (but does not do anything with resetColors) + void loadWindow(); // Gets the window.bm file + void drawUniv(); // Draw the background, add the sprites, determine draw order, draw the sprites + void copyToScreen(); // If draw is 0, just check input, otherwise also copy the screen buffer to the scummvm surface and update screen + + // Misc engine + void delay(int j); // Delay engine by j jiffies + void delay4(int j); // || /4 + void delay8(int j); // || /8 + + // Palette void loadPalette(); // Get the static palette data from the disk void setColors(uint16 pal[]); // Applies the current palette to the ScummVM surface palette void fixColors(); // Determine whether the screen should be dim or normal @@ -141,34 +216,71 @@ class ImmortalEngine : public Engine { void fade(uint16 pal[], int dir, int delay); // Calls fadePal() by a given delay each iteration void fadeOut(int j); // Calls Fade with a delay of j jiffies and direction 1 void fadeIn(int j); // || and direction 0 + void normalFadeOut(); + void slowFadeOut(); + void normalFadeIn(); - void delay(int j); // Delay engine by j jiffies - void delay4(int j); // || /4 - void delay8(int j); // || /8 - - Common::ErrorCode main(); // Main game loop - void loadWindow(); // Gets the window.bm file - void loadFont(); // Gets the font.spr file, and centers the sprite + // Assets Common::SeekableReadStream *loadIFF(Common::String fileName); // Loads a file and uncompresses if it is compressed + void loadFont(); // Gets the font.spr file, and centers the sprite void loadSingles(Common::String songName); // Loads and then parse the maze song - void loadSprites(); // Loads all the sprite files and centers their sprites (in spritelist, but called from kernal) void clearSprites(); // Clears all sprites before drawing the current frame - //void Misc::textPrint(int num); - void logicInit(); + void loadSprites(); // Loads all the sprite files and centers their sprites (in spritelist, but called from kernal) + + // Input void userIO(); // Get input void pollKeys(); // Buffer input void noNetwork(); // Setup input mirrors void keyTraps(); // Seems to be debug only + + /* + * [Sprites.cpp] Functions from Sprites.GS and spriteList.GS + */ + + // ?? + void setSpriteCenter(Common::SeekableReadStream *f, int num, uint8 cenX, uint8 cenY); // Basically initializes the data sprite + int getNumFrames(int file, int num); + + /* + * [Logic.cpp] Functions from Logic.GS + */ + + // Misc + void logicInit(); void logic(); // Keeps time, handles win and lose conditions, then general logic void restartLogic(); // This is the actual logic init - int logicFreeze(); // Overcomplicated way to check if game over or level over - void drawUniv(); // Draw the background, add the sprites, determine draw order, draw the sprites - - void copyToScreen(); // If draw is 0, just check input, otherwise also copy the screen buffer to the scummvm surface and update screen - void clearScreen(); // Draws a black rectangle on the screen buffer but only inside the frame + int logicFreeze(); // Overcomplicated way to check if game over or level over + int getLevel(); // Literally just return _level... + void gameOverDisplay(); + void gameOver(); + void levelOver(); + + /* + * [Misc.cpp] Functions from Misc + */ + + //void Misc::textPrint(int num); - /* General engine functions + /* + * [Compression.cpp] Functions from Compression.GS */ + + // Main routines + Common::SeekableReadStream *unCompress(Common::File *src, int srcLen); + + // Subroutines called by unCompress + void setupDictionary(uint16 start[], uint16 ptk[], uint16 &findEmpty); + int getInputCode(bool &carry, Common::File *src, int &srcLen, uint16 &evenOdd); + uint16 getMember(uint16 codeW, uint16 k, uint16 &findEmpty, uint16 start[], uint16 ptk[]); + void appendList(uint16 codeW, uint16 k, uint16 &hash, uint16 &findEmpty, uint16 start[], uint16 ptk[], uint16 &tmp); + + + + /* + * --- ScummVM general engine Functions --- + * + */ + Common::ErrorCode initDisks(); // Opens and parses IMMORTAL.dsk and IMMORTAL_GFX.dsk uint32 getFeatures() const; // Returns the game description flags Common::String getGameId() const; // Returns the game Id From 676cf5f7b5bea09bbd97043053fc73d7d3cb6edb Mon Sep 17 00:00:00 2001 From: Quote58 Date: Mon, 11 Jul 2022 08:06:26 -0400 Subject: [PATCH 305/412] IMMORTAL: Update to engine skeleton and addition of sprite_list, sprites, misc, and cycle --- engines/immortal/cycle.cpp | 39 +++++ engines/immortal/immortal.cpp | 68 ++++---- engines/immortal/immortal.h | 156 ++++++++++++++----- engines/immortal/kernal.cpp | 274 +++++++++++++++++++++++---------- engines/immortal/logic.cpp | 35 ++++- engines/immortal/misc.cpp | 120 +++++++++++++++ engines/immortal/module.mk | 5 +- engines/immortal/sprite_list.h | 203 ++++++++++++++++++++++++ engines/immortal/sprites.cpp | 70 +++++++++ 9 files changed, 811 insertions(+), 159 deletions(-) create mode 100644 engines/immortal/cycle.cpp create mode 100644 engines/immortal/misc.cpp create mode 100644 engines/immortal/sprite_list.h create mode 100644 engines/immortal/sprites.cpp diff --git a/engines/immortal/cycle.cpp b/engines/immortal/cycle.cpp new file mode 100644 index 000000000000..1eb43200ea25 --- /dev/null +++ b/engines/immortal/cycle.cpp @@ -0,0 +1,39 @@ +/* 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 "immortal/immortal.h" + +namespace Immortal { + +void ImmortalEngine::cycleNew() {} + int ImmortalEngine::getCycleChr() { + return 0; + } +void ImmortalEngine::cycleFreeAll() {} +void ImmortalEngine::cycleGetFile() {} +void ImmortalEngine::cycleGetNum() {} +void ImmortalEngine::cycleGetIndex() {} +void ImmortalEngine::cycleSetIndex() {} +void ImmortalEngine::cycleGetFrame() {} +void ImmortalEngine::cycleAdvance() {} + + +} // namespace Immortal diff --git a/engines/immortal/immortal.cpp b/engines/immortal/immortal.cpp index ba4f80d183d8..13856bca0f32 100644 --- a/engines/immortal/immortal.cpp +++ b/engines/immortal/immortal.cpp @@ -19,23 +19,12 @@ * */ -#include "immortal/immortal.h" -#include "immortal/detection.h" -#include "immortal/disk.h" -#include "immortal/compression.h" - -#include "common/scummsys.h" #include "common/config-manager.h" -#include "common/debug-channels.h" -#include "common/events.h" #include "common/system.h" -#include "common/debug.h" -#include "common/debug-channels.h" -#include "common/error.h" -#include "common/file.h" #include "engines/util.h" -#include "audio/mixer.h" + +#include "immortal/immortal.h" namespace Immortal { @@ -56,9 +45,6 @@ ImmortalEngine::ImmortalEngine(OSystem *syst, const ADGameDescription *gameDesc) } ImmortalEngine::~ImmortalEngine() { - _window.close(); - _font.close(); - // Confirm that the engine was destroyed debug("ImmortalEngine::~ImmortalEngine"); } @@ -71,7 +57,7 @@ uint16 ImmortalEngine::xba(uint16 ab) { * initial translation a little more straightforward. Eventually, * logic should be refactored to not require this. */ - return ((ab & kMaskLow) << 8) + ((ab & kMaskHigh) >> 8); + return ((ab & kMaskLow) << 8) | ((ab & kMaskHigh) >> 8); } uint16 ImmortalEngine::rol(uint16 ab, int n) { @@ -80,20 +66,24 @@ uint16 ImmortalEngine::rol(uint16 ab, int n) { * doesn't have this natively??? This assumes a 16 bit * unsigned int because that's all we need for the 65816. */ - return (ab << n) | (ab >> (16 - n)); + return (ab << n) | (ab >> (-n & 15)); } uint16 ImmortalEngine::ror(uint16 ab, int n) { /* The way this works is very straightforward. We start by - * performing the bit shift like normal: - * 0001 -> 0000 + * performing the bit shift like normal: 0001 -> 0000 * Then we need an easy way to apply the bit whether it fell * off the end or not, so we bit shift the opposite direction - * for the length of the word. If the bit wouldn't have - * fallen off, then it applies a 0, but if it would have, - * then we get a 1 on the opposite bit, just like the carry. + * for the length of the word minus the size of the shift. + * This way, the bit that we shifted normally, gets + * separately moved to the other end: 0001 -> 1000 + * In other words, the space C uses to evaluate the second + * part of the expression, is simulating the register for the + * carry flag. To avoid branching in case of a 0, we get the + * shift size by using the negative of the number as an + * implicit subtraction and grabbing just the relevant bits. */ - return (ab >> n) | (ab << (16 - n)); + return (ab >> n) | (ab << (-n & 15)); } uint16 ImmortalEngine::mult16(uint16 a, uint16 b) { @@ -148,12 +138,12 @@ Common::ErrorCode ImmortalEngine::initDisks() { } Common::Error ImmortalEngine::run() { - initGraphics(_resH, _resV); + initGraphics(kResH, kResV); _mainSurface = new Graphics::Surface(); - _mainSurface->create(_resH, _resV, Graphics::PixelFormat::createFormatCLUT8()); + _mainSurface->create(kResH, kResV, Graphics::PixelFormat::createFormatCLUT8()); - _screenBuff = new byte[_screenSize]; + _screenBuff = new byte[kScreenSize]; if (initDisks() != Common::kNoError) { debug("Some kind of disc error!"); @@ -177,6 +167,8 @@ Common::Error ImmortalEngine::run() { clearSprites(); // Clear the sprites before we start logicInit(); // Init the game logic + _err = Common::kNoError; + while (!shouldQuit()) { /* The game loop runs at 60fps, which is 16 milliseconds per frame. @@ -187,10 +179,24 @@ Common::Error ImmortalEngine::run() { */ int64 loopStart = g_system->getMillis(); - // Kernal main function - int err = main(); - - if (err != Common::kNoError) { + // Main + Common::Event event; + g_system->getEventManager()->pollEvent(event); + + userIO(); + noNetwork(); + pollKeys(); + logic(); + pollKeys(); + if (logicFreeze() == 0) { + drawUniv(); + pollKeys(); + fixColors(); + copyToScreen(); + pollKeys(); + } + + if (_err != Common::kNoError) { debug("To err is human, to really screw up you need an Apple IIGS!"); return Common::kUnknownError; } diff --git a/engines/immortal/immortal.h b/engines/immortal/immortal.h index 62412401bdfb..b3914ddb5127 100644 --- a/engines/immortal/immortal.h +++ b/engines/immortal/immortal.h @@ -25,6 +25,7 @@ #include "audio/mixer.h" #include "common/debug.h" +#include "common/debug-channels.h" #include "common/events.h" #include "common/scummsys.h" #include "common/system.h" @@ -48,9 +49,9 @@ #include "immortal/detection.h" #include "immortal/disk.h" -namespace Immortal { +#include "immortal/sprite_list.h" // This is an enum of all available sprites -#include "immortal/sprite_list.h" +namespace Immortal { // There is a lot of bit masking that needs to happen, so this enum makes it a little easier to read enum BitMask16 : uint16 { @@ -78,20 +79,25 @@ enum ColourMask : uint16 { }; struct DataSprite { - uint8 _cenX; // These are the base center positions - uint8 _cenY; - byte *_bitmap; // Pointer to actual data -Common::SeekableReadStream *_file; // This will likely be removed later + uint8 _cenX; // These are the base center positions + uint8 _cenY; + byte *_bitmap; // Pointer to actual data +Common::SeekableReadStream *_file; // This will likely be removed later }; struct Sprite { - uint16 _frame; // Something something background? - uint16 _activeFrame; // Why the heck is this inside the individual sprite data? - uint16 _X; - uint16 _Y; - uint16 _on; // 1 = active - uint16 _priority; -DataSprite _dSprite; + int _frame; // Current frame of the cycle + uint16 _X; + uint16 _Y; + uint16 _on; // 1 = active + uint16 _priority; +DataSprite *_dSprite; +}; + +struct Cycle { +DataSprite *_dSprite; + int _numCycles; + int *_frames; }; struct ImmortalGameDescription; @@ -111,6 +117,8 @@ class ImmortalEngine : public Engine { ImmortalEngine(OSystem *syst, const ADGameDescription *gameDesc); ~ImmortalEngine() override; + const ADGameDescription *_gameDescription; + /* Terrible functions because C doesn't like * bit manipulation enough */ @@ -119,8 +127,6 @@ class ImmortalEngine : public Engine { uint16 ror(uint16 ab, int n); // Rotate bits right by n uint16 mult16(uint16 a, uint16 b); // Just avoids using (uint16) everywhere, and is slightly closer to the original - const ADGameDescription *_gameDescription; - /* * --- Members --- * @@ -129,36 +135,52 @@ class ImmortalEngine : public Engine { /* * Constants */ + // Screen const int kResH = 320; const int kResV = 200; + const int kScreenW = 128; + const int kScreenH = 128; const int kScreenSize = (kResH * kResV) * 2; // The size of the screen buffer is 320x200 + + // Disk offsets + const int kPaletteOffset = 21205; // This is the byte position of the palette data in the disk + + // Sprite constants + const int kMaxCycles = 32; const int kMaxSprites = 32; // Number of sprites allowed at once + const int kMaxSpriteAbove = 48; // Maximum sprite extents from center + const int kMaxSpriteBelow = 16; + const int kMaxSpriteLeft = 16; + const int kMaxSpriteRight = 16; const int kWizardX = 28; // Common sprite center for some reason const int kWizardY = 37; /* * 'global' members */ - bool _draw = 0; // Whether the screen should draw this frame - bool _dim = 0; // Whether the palette is dim - bool _usingNormal = 0; // Whether the palette is using normal - int _zero = 0; // No idea what this is yet + Common::ErrorCode _err; // If this is not kNoError at any point, the engine will stop + bool _draw = 0; // Whether the screen should draw this frame + bool _dim = 0; // Whether the palette is dim + bool _usingNormal = 0; // Whether the palette is using normal + int _zero = 0; // No idea what this is yet uint8 _gameOverFlag = 0; - uint8 _levelOver = 0; - uint8 _themePaused = 0; - int _level = 0; - int _titlesShown = 0; - int _time = 0; - int _promoting = 0; - int _restart = 0; - int _lastCertLen = 0; + uint8 _levelOver = 0; + uint8 _themePaused = 0; + int _level = 0; + int _titlesShown = 0; + int _time = 0; + int _promoting = 0; + int _restart = 0; + int _lastCertLen = 0; /* * Asset related members */ + int _numSprites = 0; // This is more accurately actually the index within the sprite array, so _numSprites + 1 is the current number of sprites DataSprite _font; // The font sprite data is loaded separate from other sprite stuff byte *_window; // Bitmap of the window around the game Sprite _sprites[32]; // A contiguous series of sprites (this is the same as kMaxSprites, but it can't be used for this) + Cycle _cycles[32]; // Animation cycle for each sprite slot DataSprite _dataSprites[kFont+1]; // All the sprite data, indexed by SpriteFile /* @@ -166,11 +188,11 @@ class ImmortalEngine : public Engine { */ Graphics::Surface *_mainSurface; byte *_screenBuff; // The final buffer that will transfer to the screen - + uint16 _viewPortX; + uint16 _viewPortY; /* * Palette related members */ - const int kPaletteOffset = 21205; // This is the byte position of the palette data in the disk uint16 _palDefault[16]; uint16 _palWhite[16]; uint16 _palBlack[16]; @@ -179,7 +201,6 @@ class ImmortalEngine : public Engine { int _dontResetColors = 0; // Not sure yet - /* * --- Functions --- * @@ -189,19 +210,20 @@ class ImmortalEngine : public Engine { * [Kernal.cpp] Functions from Kernal.gs and Driver.gs */ - Common::ErrorCode main(); // Main game loop - // Screen void clearScreen(); // Draws a black rectangle on the screen buffer but only inside the frame void whiteScreen(); // Draws a white rectanlge on the screen buffer (but does not do anything with resetColors) + void rect(int x, int y, int w, int h); // Draws a solid rectangle at x,y with size w,h. Also shadows for blit? void loadWindow(); // Gets the window.bm file void drawUniv(); // Draw the background, add the sprites, determine draw order, draw the sprites void copyToScreen(); // If draw is 0, just check input, otherwise also copy the screen buffer to the scummvm surface and update screen + void mungeBM(); // Put together final bitmap? + void blit(); // Will probably want this to be it's own function + void blit40(); // Uses macro blit 40 times + void sBlit(); + void scroll(); // Misc engine - void delay(int j); // Delay engine by j jiffies - void delay4(int j); // || /4 - void delay8(int j); // || /8 // Palette void loadPalette(); // Get the static palette data from the disk @@ -226,12 +248,20 @@ class ImmortalEngine : public Engine { void loadSingles(Common::String songName); // Loads and then parse the maze song void clearSprites(); // Clears all sprites before drawing the current frame void loadSprites(); // Loads all the sprite files and centers their sprites (in spritelist, but called from kernal) + void addSprite(uint16 x, uint16 y, SpriteName n, int frame, uint16 p); // Input void userIO(); // Get input void pollKeys(); // Buffer input void noNetwork(); // Setup input mirrors void keyTraps(); // Seems to be debug only + void blit8(); // This is actually just input, but it is called blit because it does a 'paddle blit' 8 times + + // These will replace the myriad of hardware input handling from the source + void getInput(); + void addKeyBuffer(); + void clearKeyBuff(); + /* * [Sprites.cpp] Functions from Sprites.GS and spriteList.GS @@ -239,7 +269,28 @@ class ImmortalEngine : public Engine { // ?? void setSpriteCenter(Common::SeekableReadStream *f, int num, uint8 cenX, uint8 cenY); // Basically initializes the data sprite - int getNumFrames(int file, int num); + int getNumFrames(int file, int num); + + /* + * [Cycle.cpp] Functions from Cyc + */ + + /* Unneccessary + void cycleInit(); + void cycleFree(); + void cycleGetNumFrames(); + void cycleGetList();*/ + + // Misc + void cycleNew(); // Adds a cycle to the current list + int getCycleChr(); + void cycleFreeAll(); // Delete all cycles + void cycleGetFile(); + void cycleGetNum(); + void cycleGetIndex(); + void cycleSetIndex(); + void cycleGetFrame(); + void cycleAdvance(); /* * [Logic.cpp] Functions from Logic.GS @@ -249,8 +300,8 @@ class ImmortalEngine : public Engine { void logicInit(); void logic(); // Keeps time, handles win and lose conditions, then general logic void restartLogic(); // This is the actual logic init - int logicFreeze(); // Overcomplicated way to check if game over or level over - int getLevel(); // Literally just return _level... + int logicFreeze(); // Overcomplicated way to check if game over or level over + int getLevel(); // Literally just return _level... void gameOverDisplay(); void gameOver(); void levelOver(); @@ -259,7 +310,32 @@ class ImmortalEngine : public Engine { * [Misc.cpp] Functions from Misc */ - //void Misc::textPrint(int num); + // Misc + void delay(int j); // Delay engine by j jiffies (from driver originally, but makes more sense grouped with misc) + void delay4(int j); // || /4 + void delay8(int j); // || /8 + void miscInit(); + void setRandomSeed(); + void getRandom(); + void myDelay(); + + // Text printing + void textPrint(int num); + void textSub(); + void textEnd(); + void textMiddle(); + void textBeginning(); + void yesNo(); + + // Input related + void buttonPressed(); + void firePressed(); + + // Screen related + void inside(int p, int p2, int a); + void insideRect(int p, int r); + void updateHitGuage(); + /* * [Compression.cpp] Functions from Compression.GS @@ -270,7 +346,7 @@ class ImmortalEngine : public Engine { // Subroutines called by unCompress void setupDictionary(uint16 start[], uint16 ptk[], uint16 &findEmpty); - int getInputCode(bool &carry, Common::File *src, int &srcLen, uint16 &evenOdd); + int getInputCode(bool &carry, Common::File *src, int &srcLen, uint16 &evenOdd); uint16 getMember(uint16 codeW, uint16 k, uint16 &findEmpty, uint16 start[], uint16 ptk[]); void appendList(uint16 codeW, uint16 k, uint16 &hash, uint16 &findEmpty, uint16 start[], uint16 ptk[], uint16 &tmp); diff --git a/engines/immortal/kernal.cpp b/engines/immortal/kernal.cpp index 284245ff6add..79a8dfc84609 100644 --- a/engines/immortal/kernal.cpp +++ b/engines/immortal/kernal.cpp @@ -26,56 +26,10 @@ * considered part of the same process. */ -#include "common/debug.h" -#include "common/error.h" -#include "common/events.h" - #include "immortal/immortal.h" -#include "immortal/disk.h" -#include "immortal/compression.h" namespace Immortal { -/* - * - * ----- ----- - * ----- Main Functions ----- - * ----- ----- - * - */ - -Common::ErrorCode ImmortalEngine::main() { - Common::Event event; - g_system->getEventManager()->pollEvent(event); - - userIO(); - noNetwork(); - pollKeys(); - logic(); - pollKeys(); - if (logicFreeze() == 0) { - drawUniv(); - pollKeys(); - fixColors(); - copyToScreen(); - pollKeys(); - } - - return Common::kNoError; -} - -void ImmortalEngine::delay(int j) { // Delay is measured in jiffies, which are 56.17ms - g_system->delayMillis(j * 56); -} - -void ImmortalEngine::delay4(int j) { // Named in source quarterClock for some reason, 1/4 jiffies are 14.04ms - g_system->delayMillis(j * 14); -} - -void ImmortalEngine::delay8(int j) { // 1/8 jiffies are 7.02ms - g_system->delayMillis(j * 7); -} - /* * * ----- ----- @@ -85,37 +39,27 @@ void ImmortalEngine::delay8(int j) { // 1/8 jiffies are 7.02ms */ void ImmortalEngine::drawUniv() { - /* The byte buffer for the screen (_screenBuff) has one byte for - * every pixel, with the resolution of the game being 320x200. - * For a bitmap like the window frame, all we need to do is - * extract the pixel out of each nyble (half byte) of the data, - * by looping over it one row at a time. - */ - // Apply the window frame to the buffer - _window.seek(0); - byte pixel; - int pos; - for (int y = 0; y < _resV; y++) { - for (int x = 0; x < _resH; x += 2) { - pos = (y * _resH) + x; - pixel = _window.readByte(); - _screenBuff[pos] = (pixel & kMask8High) >> 4; - _screenBuff[pos + 1] = pixel & kMask8Low; - } - } + // drawBackground() = draw floor parts of leftmask rightmask and maskers + // addRows() = add rows to drawitem array + // addSprites() = add all active sprites that are in the viewport, into a list that will be sorted by priority + // sortDrawItems() = sort said items + // drawItems() = draw the items over the background + + // To start constructing the screem, we start with the frame as the base + memcpy(_screenBuff, _window, kScreenSize); /* copyRectToSurface will apply the screenbuffer to the ScummVM surface. * We want to do 320 bytes per scanline, at location (0,0), with a * size of 320x200. */ - _mainSurface->copyRectToSurface(_screenBuff, _resH, 0, 0, _resH, _resV); + _mainSurface->copyRectToSurface(_screenBuff, kResH, 0, 0, kResH, kResV); } void ImmortalEngine::copyToScreen() { if (_draw == 1) { - g_system->copyRectToScreen((byte *)_mainSurface->getPixels(), _resH, 0, 0, _resH, _resV); + g_system->copyRectToScreen((byte *)_mainSurface->getPixels(), kResH, 0, 0, kResH, kResV); g_system->updateScreen(); } } @@ -130,32 +74,174 @@ void ImmortalEngine::clearScreen() { } } +void ImmortalEngine::whiteScreen() { + //fill the visible screen with black pixels by drawing a rectangle + + //rect(32, 20, 256, 128, 13) +} + +void ImmortalEngine::mungeBM() {} +void ImmortalEngine::blit() {} +void ImmortalEngine::blit40() {} +void ImmortalEngine::sBlit() {} +void ImmortalEngine::scroll() {} + + /* * - * ----- ----- - * ----- File Loading ----- - * ----- ----- + * ----- ----- + * ----- Asset Init ----- + * ----- ----- * */ +void ImmortalEngine::addSprite(uint16 x, uint16 y, SpriteName n, int frame, uint16 p) { + if (_numSprites != kMaxSprites) { + if (x >= (kScreenW + kMaxSpriteLeft)) { + x |= kMaskHigh; // Make it negative + } + _sprites[_numSprites]._X = (x << 1) + _viewPortX; + + if (y >= (kMaxSpriteAbove + kScreenH)) { + y |= kMaskHigh; + } + _sprites[_numSprites]._Y = (y << 1) + _viewPortY; + + if (p >= 0x80) { + p |= kMaskHigh; + } + _sprites[_numSprites]._priority = ((p + y) ^ 0xFFFF) + 1; + + _sprites[_numSprites]._frame = frame; + _sprites[_numSprites]._dSprite = &_dataSprites[n]; + _sprites[_numSprites]._on = 1; + _numSprites += 1; + + } else { + debug("Max sprites reached beeeeeep!!"); + } + +} + +void ImmortalEngine::clearSprites() { + // Just sets the 'active' flag on all possible sprites to 0 + for (int i = 0; i < kMaxSprites; i++) { + _sprites[i]._on = 0; + } +} + void ImmortalEngine::loadSprites() { - // Load MoreSprites.spr + /* This is a bit weird, so I'll explain. + * In the source, this routine loads the files onto the heap, and then + * goes through a table of sprites in the form file_index, sprite_num, center_x, center_y. + * It uses file_index to get a pointer to the start of the file on the heap, + * which it then uses to set the center x/y variables in the file itself. + * ie. file_pointer[file_index]+((sprite_num<<3)+4) = center_x. + * We aren't going to have the sprite properties inside the file data, so instead + * we have an array of all game sprites _dataSprites which is indexed + * soley by a sprite number now. This also means that a sprite itself has a reference to + * a datasprite, instead of the sprite index and separate the file pointer. Datasprite + * is what needs the file, so that's where the pointer is. The index isn't used by + * the sprite or datasprite themselves, so it isn't a member of either of them. + */ + + Common::String spriteNames[] = {"MORESPRITES.SPR", "NORLAC.SPR", "POWWOW.SPR", "TURRETS.SPR", + "WORM.SPR", "IANSPRITES.SPR", "LAST.SPR", "DOORSPRITES.SPR", + "GENSPRITES.SPR", "DRAGON.SPR", "MORDAMIR.SPR", "FLAMES.SPR", + "ROPE.SPR", "RESCUE.SPR", "TROLL.SPR", "GOBLIN.SPR", "ULINDOR.SPR", + "SPIDER.SPR", "DRAG.SPR"}; + + Common::SeekableReadStream *files[19]; + + // Number of sprites in each file + int spriteNum[] = {10, 5, 7, 10, 4, 6, 3, 10, 5, 3, 2, 1, 3, 2, 9, 10, 9, 10, 9}; + + // Pairs of (x,y) for each sprite + // Should probably have made this a 2d array, oops + uint8 centerXY[] = {16,56, 16,32, 27,39, 16,16, 32,16, 34,83, 28,37, 8,12, 8,19, 24,37, + /* Norlac */ 46,18, 40,0, 8,13, 32,48, 32,40, + /* Powwow */ 53,43, 28,37, 27,37, 26,30, 26,30, 26,29, 28,25, + /* Turrets */ 34,42, 28,37, 24,32, 32,56, 26,56, 8,48, 8,32, 8,14, 8,24, 32,44, + /* Worm */ 20,65, 25,46, 9,56, 20,53, + /* Iansprites */ 24,50, 32,52, 32,53, 32,52, 40,16, 40,16, + /* Last */ 32,56, 24,32, 24,36, + /* Doorsprites */ 0,64, 4,49, 18,49, 18,56, 24,32, 24,16, 24,56, 24,32, 24,32, 36,32, + /* Gensprites */ 16,44, 16,28, 32,24, 34,45, 20,28, + /* Dragon */ 24,93, 32,48, 0,64, + /* Mordamir */ 104,104, 30,30, + /* Flames */ 64,0, + /* Rope */ 0,80, 32,52, 32,40, + /* Rescue */ 0,112, 0,112, + /* Troll */ 28,38, 28,37, 28,37, 31,38, 28,37, 25,39, 28,37, 28,37, 28,37, + /* Goblin */ 28,38, 30,38, 26,37, 30,38, 26,37, 26,37, 26,37, 26,37, 26,36, 44,32, + /* Ulindor */ 42,42, 42,42, 42,42, 42,42, 42,42, 42,42, 42,42, 42,42, 42,42, + /* Spider */ 64,44, 64,44, 64,44, 64,44, 64,44, 64,44, 64,44, 64,44, 64,44, 64,44, + /* Drag */ 19,36, 19,36, 19,36, 19,36, 19,36, 19,36, 19,36, 19,36, 19,36}; + + // Load all sprite files + for (int i = 0; i < 19; i++) { + files[i] = loadIFF(spriteNames[i]); + } + // s = current sprite index, f = current file index, n = current number of sprites for this file + int s = 0; + for (int f = 0; f < 19; f++) { + for (int n = 0; n < (spriteNum[f] * 2); n += 2, s++) { + DataSprite d; + _dataSprites[s] = d; + setSpriteCenter(files[f], s, centerXY[s * 2], centerXY[(s * 2) + 1]); + } + } } void ImmortalEngine::loadWindow() { // Initialize the window bitmap - if (!_window.open("WINDOWS.BM")) { + Common::File f; + _window = new byte[kScreenSize]; + + if (f.open("WINDOWS.BM")) { + + /* The byte buffer for the screen (_screenBuff) has one byte for + * every pixel, with the resolution of the game being 320x200. + * For a bitmap like the window frame, all we need to do is + * extract the pixel out of each nyble (half byte) of the data, + * by looping over it one row at a time. + */ + + byte pixel; + int pos; + for (int y = 0; y < kResV; y++) { + for (int x = 0; x < kResH; x += 2) { + pos = (y * kResH) + x; + pixel = f.readByte(); + _window[pos] = (pixel & kMask8High) >> 4; + _window[pos + 1] = pixel & kMask8Low; + } + } + + // Now that the bitmap is processed and stored in a byte buffer, we can close the file + f.close(); + + } else { + // Should probably give an error or something here debug("oh nose :("); } } void ImmortalEngine::loadFont() { - // Initialize the font sprite - if (!_font.open("FONT.SPR")) { + // Initialize the font data sprite + Common::SeekableReadStream *f = loadIFF("FONT.SPR"); + + DataSprite d; + _dataSprites[kFont] = d; + + if (f) { + setSpriteCenter(f, kFont, 16, 0); + } else { debug("oh nose :("); } + } Common::SeekableReadStream *ImmortalEngine::loadIFF(Common::String fileName) { @@ -193,7 +279,7 @@ Common::SeekableReadStream *ImmortalEngine::loadIFF(Common::String fileName) { // Compressed files have a 12 byte header before the data f.seek(12); - return Compression::unCompress(&f, len); + return unCompress(&f, len); } byte *out = (byte *)malloc(f.size()); @@ -229,8 +315,8 @@ void ImmortalEngine::loadPalette() { // The palettes are stored at a particular location in the disk, this just grabs them Common::File d; d.open("IMMORTAL.dsk"); + d.seek(kPaletteOffset); - d.read(_palDefault, 32); d.read(_palWhite, 32); d.read(_palBlack, 32); @@ -249,9 +335,10 @@ void ImmortalEngine::setColors(uint16 pal[]) { // Green is already the correct size, being the second nyble (00G0) // Red is in the first nyble of the high byte, so it needs to move right by 4 bits (0R00 -> 00R0) // Blue is the first nyble of the first byte, so it needs to move left by 4 bits (000B -> 00B0) - _palRGB[(i * 3)] = ((pal[i] & kMaskRed) >> 4); - _palRGB[(i * 3) + 1] = ((pal[i] & kMaskGreen)); - _palRGB[(i * 3) + 2] = (pal[i] & kMaskBlue) << 4; + // We also need to repeat the bits so that the colour is the same proportion of 255 as it is 15 + _palRGB[(i * 3)] = ((pal[i] & kMaskRed) >> 4) | ((pal[i] & kMaskRed) >> 8); + _palRGB[(i * 3) + 1] = (pal[i] & kMaskGreen) | ((pal[i] & kMaskGreen) >> 4) ; + _palRGB[(i * 3) + 2] = (pal[i] & kMaskBlue) | ((pal[i] & kMaskBlue) << 4); } } // Palette index to update first is 0, and there are 16 colours to update @@ -336,7 +423,7 @@ void ImmortalEngine::fade(uint16 pal[], int dir, int delay) { uint16 target[16]; uint16 count; - // Originally used a branch, but this is functionally identical and much nicer + // Originally used a branch, but this is functionally identical and much cleaner count = dir * 256; while ((count >= 0) && (count <= 256)) { @@ -354,10 +441,22 @@ void ImmortalEngine::fadeOut(int j) { fade(_palDefault, 1, j); } +void ImmortalEngine::normalFadeOut() { + fadeOut(15); +} + +void ImmortalEngine::slowFadeOut() { + fadeOut(28); +} + void ImmortalEngine::fadeIn(int j) { fade(_palDefault, 0, j); } +void ImmortalEngine::normalFadeIn() { + fadeIn(15); +} + // These two can probably be removed since the extra call in C doesn't have the setup needed in ASM void ImmortalEngine::useBlack() { setColors(_palBlack); @@ -388,12 +487,25 @@ void ImmortalEngine::useDim() { void ImmortalEngine::userIO() {} void ImmortalEngine::pollKeys() {} void ImmortalEngine::noNetwork() {} +void ImmortalEngine::keyTraps() {} +void ImmortalEngine::blit8() {} +void ImmortalEngine::getInput() {} +void ImmortalEngine::addKeyBuffer() {} +void ImmortalEngine::clearKeyBuff() {} + + +/* + * + * ----- ----- + * ----- Sound/Music Functions ----- + * ----- ----- + * + */ void ImmortalEngine::loadSingles(Common::String songName) { debug("%s", songName.c_str()); } -void ImmortalEngine::clearSprites() {} -void ImmortalEngine::keyTraps() {} + } // namespace Immortal diff --git a/engines/immortal/logic.cpp b/engines/immortal/logic.cpp index 8a1fd3a7474c..750e59a399be 100644 --- a/engines/immortal/logic.cpp +++ b/engines/immortal/logic.cpp @@ -19,27 +19,50 @@ * */ -#include "common/debug.h" -#include "common/error.h" -#include "common/events.h" - #include "immortal/immortal.h" namespace Immortal { +// There's no way this routine needs to still be here. In fact I'm not sure it needed to be in the game anyway? +int ImmortalEngine::getLevel() { + return _level; +} + void ImmortalEngine::logicInit() { - debug("init logic here"); + _titlesShown = 0; + _time = 0; + _promoting = 0; + _restart = 1; + //level_initAtStartOfGameOnly + _lastCertLen = 0; } void ImmortalEngine::logic() { + _time += 1; + // if time overflows the counter, inc the high byte? What the heck... + } void ImmortalEngine::restartLogic() { } int ImmortalEngine::logicFreeze() { - return 0; + // Very silly way of checking if the level is over and/or the game is over + int g = _gameOverFlag | _levelOver; + return (g ^ 1) >> 1; } +void ImmortalEngine::gameOverDisplay() { + _themePaused |= 2; + //text_print(kGameOverString) +} + +void ImmortalEngine::gameOver() { + _gameOverFlag = 1; +} + +void ImmortalEngine::levelOver() { + _levelOver = 1; +} } // namespace Immortal \ No newline at end of file diff --git a/engines/immortal/misc.cpp b/engines/immortal/misc.cpp new file mode 100644 index 000000000000..3457ccb0a3ef --- /dev/null +++ b/engines/immortal/misc.cpp @@ -0,0 +1,120 @@ +/* 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 "immortal/immortal.h" + +namespace Immortal { + +/* + * + * ----- ----- + * ----- Main Functions ----- + * ----- ----- + * + */ + +void ImmortalEngine::delay(int j) { // Delay is measured in jiffies, which are 56.17ms + g_system->delayMillis(j * 56); +} + +void ImmortalEngine::delay4(int j) { // Named in source quarterClock for some reason, 1/4 jiffies are 14.04ms + g_system->delayMillis(j * 14); +} + +void ImmortalEngine::delay8(int j) { // 1/8 jiffies are 7.02ms + g_system->delayMillis(j * 7); +} + +void ImmortalEngine::miscInit() {} +void ImmortalEngine::setRandomSeed() {} +void ImmortalEngine::getRandom() {} +void ImmortalEngine::myDelay() {} + + +/* + * + * ----- ----- + * ----- Text Printing ----- + * ----- ----- + * + */ + +void ImmortalEngine::textPrint(int num) {} +void ImmortalEngine::textSub() {} +void ImmortalEngine::textEnd() {} +void ImmortalEngine::textMiddle() {} +void ImmortalEngine::textBeginning() {} +void ImmortalEngine::yesNo() {} + + +/* + * + * ----- ----- + * ----- Input Related ----- + * ----- ----- + * + */ + +void ImmortalEngine::buttonPressed() {} +void ImmortalEngine::firePressed() {} + + +/* + * + * ----- ----- + * ----- Screen Related ----- + * ----- ----- + * + */ + +void ImmortalEngine::inside(int p, int p2, int a) {} +void ImmortalEngine::insideRect(int p, int r) {} +void ImmortalEngine::updateHitGuage() {} + + + + + +} // namespace Immortal + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/engines/immortal/module.mk b/engines/immortal/module.mk index b3ba49aaff96..fa12eb2f94f9 100644 --- a/engines/immortal/module.mk +++ b/engines/immortal/module.mk @@ -6,7 +6,10 @@ MODULE_OBJS = \ metaengine.o \ compression.o \ kernal.o \ - logic.o + logic.o \ + sprites.o \ + misc.o \ + cycle.o # This module can be built as a plugin ifeq ($(ENABLE_IMMORTAL), DYNAMIC_PLUGIN) diff --git a/engines/immortal/sprite_list.h b/engines/immortal/sprite_list.h new file mode 100644 index 000000000000..a385db5bd17f --- /dev/null +++ b/engines/immortal/sprite_list.h @@ -0,0 +1,203 @@ +/* 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 . + * + */ + +#ifndef IMMORTAL_SPRITE_LIST_H +#define IMMORTAL_SPRITE_LIST_H + +namespace Immortal { + +enum SpriteName { + // Moresprites 10 + kCandle, + kWow, + kAnaVanish, + kSink, + kTrapdoor, + kWizPhant, + kVanish, + kShadow, + kSlime, + kSlimeDeath, + + // Norlac 5 + kBridge, + kVortex, + kBubble, + kNorlac, + kNolac2, + + // Powwow 7 + kPlanners, + kUgh, + kIsDevoured, + kIsBadCrawl, + kIsGoodCrawl, + kLeg, + kIsWebbed, + + // Turrets 10 + kSleep, + kShrink, + kLocksmith, + kAnaGlimpse, + kMadKing, + kTorch, + kPipe, + kProjectile, + kKnife, + kAnaHug, + + // Worm 4 + kWorm0, + kWorm1, + kSpike, + kIsSpiked, + + // Iansprites 6 + kMurder, + kWizCrawlUp, + kWizLight, + kWizBattle, + kDown, + kNorlacDown, + + // Lastsprites 3 + kWaterLadder, + kPulledDown, + kSpill, + + // Doorsprites 10 + kDoor, + kTele, + kBomb, + kTorched, + kLadderTop, + kSecret, + kLadderBottom, + kSlipped, + kGoblinSlipped, + kFlame, + + // General 5 + kArrow, + kSpark, + kObject, + kBigBurst, + kBeam, + + // Mordamir 3 + kLight, + kMord, + kDragMask, + + // Dragon2 2 + kDFlames, + kThroat, + + // Dragon 1 + kDragon, + + // Rope 3 + kChop, + kHead, + kNurse, + + // Rescue 2 + kRescue1, + kRescue2, + + // Troll 9 + kTroll0, + kTroll1, + kTroll2, + kTroll3, + kTroll4, + kTroll5, + kTroll6, + kTroll7, + kTroll8, + + // Goblin 10 + kGoblin0, + kGoblin1, + kGoblin2, + kGoblin3, + kGoblin4, + kGoblin5, + kGoblin6, + kGoblin7, + kGoblin8, + kGoblin9, + + //Ulindor 9 + kUlindor0, + kUlindor1, + kUlindor2, + kUlindor3, + kUlindor4, + kUlindor5, + kUlindor6, + kUlindor7, + kUlindor8, + + //Spider 10 + kSpider0, + kSpider1, + kSpider2, + kSpider3, + kSpider4, + kSpider5, + kSpider6, + kSpider7, + kSpider8, + kSpider9, + + //Drag 9 + kDrag0, + kDrag1, + kDrag2, + kDrag3, + kDrag4, + kDrag5, + kDrag6, + kDrag7, + kDrag8, + + // Font + kFont +}; + +} // namespace immortal + +#endif + + + + + + + + + + + + + diff --git a/engines/immortal/sprites.cpp b/engines/immortal/sprites.cpp new file mode 100644 index 000000000000..0329cf6a420d --- /dev/null +++ b/engines/immortal/sprites.cpp @@ -0,0 +1,70 @@ +/* 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 "immortal/immortal.h" + +namespace Immortal { + +/* + * + * ----- ----- + * ----- Main Functions ----- + * ----- ----- + * + */ + +void ImmortalEngine::setSpriteCenter(Common::SeekableReadStream *f, int num, uint8 cenX, uint8 cenY) { + // Very simple, just initialize what we can of the data sprite + _dataSprites[num]._cenX = cenX; + _dataSprites[num]._cenY = cenY; + _dataSprites[num]._file = f; +} + + + + + + +} // namespace Immortal + + + + + + + + + + + + + + + + + + + + + + + + From c5181c75defb6ca4ac1217a67e56761960e043ef Mon Sep 17 00:00:00 2001 From: Quote58 Date: Tue, 12 Jul 2022 01:09:34 -0400 Subject: [PATCH 306/412] IMMORTAL: Indentation spaces -> tabs --- engines/immortal/compression.cpp | 430 ++++++++++----------- engines/immortal/credits.pl | 1 - engines/immortal/cycle.cpp | 2 +- engines/immortal/disk.cpp | 500 ++++++++++++------------- engines/immortal/disk.h | 258 ++++++------- engines/immortal/immortal.cpp | 28 +- engines/immortal/immortal.h | 91 +++-- engines/immortal/kernal.cpp | 618 +++++++++++++++---------------- engines/immortal/logic.cpp | 66 +++- engines/immortal/metaengine.cpp | 12 +- engines/immortal/misc.cpp | 6 +- engines/immortal/sprite_list.h | 316 ++++++++-------- engines/immortal/sprites.cpp | 8 +- 13 files changed, 1195 insertions(+), 1141 deletions(-) diff --git a/engines/immortal/compression.cpp b/engines/immortal/compression.cpp index 5a9dba9ffa58..aa0b2eae8cfd 100644 --- a/engines/immortal/compression.cpp +++ b/engines/immortal/compression.cpp @@ -30,233 +30,233 @@ namespace Immortal { Common::SeekableReadStream *ImmortalEngine::unCompress(Common::File *src, int srcLen) { - /* Note: this function does not seek() in the file, which means - * that if there is a header on the data, the expectation is that - * seek() was already used to move past the header before this function. - */ - - // If the source data has no length, we certainly do not want to decompress it - if (srcLen == 0) { - return nullptr; - } - - /* This will be the dynamically re-allocated writeable memory stream. - * We do not want it to be deleted from scope, as this location is where - * the readstream being returned will point to. - */ - Common::MemoryWriteStreamDynamic dstW(DisposeAfterUse::NO); - - // The 20k bytes of memory that compression gets allocated to work with for the dictionary and the stack of chars - uint16 start[0x4000]; // Really needs a better name, remember to do this future me - uint16 ptk[0x4000]; // Pointer To Keys? Also needs a better name - byte stack[0x4000]; // Stack of chars to be stored - - // These are the main variables we'll need for this - uint16 findEmpty; - uint16 code; // Needs to be ASL to index with - uint16 inputCode; - uint16 finalChar; - uint16 myCode; // Silly name is silly - uint16 oldCode; - uint16 index; // The Y register was used to index the byte array's, this will sort of take its place - uint16 evenOdd = 0; - uint16 topStack = 0; - - byte outByte; // If only we could SEP #$20 like the 65816 - - setupDictionary(start, ptk, findEmpty); // Clear the dictionary and also set findEmpty to 8k - bool carry = true; // This will represent the carry flag so we can make this a clean loop - - code = getInputCode(carry, src, srcLen, evenOdd); // Get the first code - if (carry == false) { - return nullptr; // This is essentially the same as the first error check, but the source returns an error code and didn't even check it here so we might as well - } - - finalChar = code; - oldCode = code; - myCode = code; - - outByte = code & kMaskLow; - dstW.writeByte(outByte); // Take just the lower byte and write it the output - - // :nextcode - while (carry == true) { - - code = getInputCode(carry, src, srcLen, evenOdd); // Get the next code - if (carry == true) { - - index = code << 1; - inputCode = code; - myCode = code; - - // Split up the conditional statement to be easier to follow - uint16 cond; - cond = start[index] & kMaskLast; - cond |= ptk[index]; - - if ((cond & kMaskHigh) == 0) { // Empty code - index = topStack; - outByte = finalChar & kMaskLow; - stack[index] = outByte; - topStack++; - myCode = oldCode; - } - - // :nextsymbol - index = myCode << 1; - while (index >= 0x200) { - myCode = start[index] & kMask12Bit; - outByte = ptk[index] & kMaskLow; - index = topStack; - stack[index] = outByte; - topStack++; - index = myCode << 1; - } - - // :singlechar - finalChar = (myCode >> 1); - outByte = finalChar & kMaskLow; - dstW.writeByte(outByte); - - // :dump - while (topStack != 0xFFFF) { // Dump the chars on the stack into the output file - outByte = stack[topStack] & kMaskLow; - dstW.writeByte(outByte); - topStack--; - } - - topStack = 0; - code = getMember(oldCode, finalChar, findEmpty, start, ptk); - oldCode = inputCode; - } - - } - - /* Return a readstream with a pointer to the data in the write stream. - * This one we do want to dispose after using, because it will be in the scope of the engine itself - */ - return new Common::MemoryReadStream(dstW.getData(), dstW.size(), DisposeAfterUse::YES); + /* Note: this function does not seek() in the file, which means + * that if there is a header on the data, the expectation is that + * seek() was already used to move past the header before this function. + */ + + // If the source data has no length, we certainly do not want to decompress it + if (srcLen == 0) { + return nullptr; + } + + /* This will be the dynamically re-allocated writeable memory stream. + * We do not want it to be deleted from scope, as this location is where + * the readstream being returned will point to. + */ + Common::MemoryWriteStreamDynamic dstW(DisposeAfterUse::NO); + + // The 20k bytes of memory that compression gets allocated to work with for the dictionary and the stack of chars + uint16 start[0x4000]; // Really needs a better name, remember to do this future me + uint16 ptk[0x4000]; // Pointer To Keys? Also needs a better name + byte stack[0x4000]; // Stack of chars to be stored + + // These are the main variables we'll need for this + uint16 findEmpty; + uint16 code; // Needs to be ASL to index with + uint16 inputCode; + uint16 finalChar; + uint16 myCode; // Silly name is silly + uint16 oldCode; + uint16 index; // The Y register was used to index the byte array's, this will sort of take its place + uint16 evenOdd = 0; + uint16 topStack = 0; + + byte outByte; // If only we could SEP #$20 like the 65816 + + setupDictionary(start, ptk, findEmpty); // Clear the dictionary and also set findEmpty to 8k + bool carry = true; // This will represent the carry flag so we can make this a clean loop + + code = getInputCode(carry, src, srcLen, evenOdd); // Get the first code + if (carry == false) { + return nullptr; // This is essentially the same as the first error check, but the source returns an error code and didn't even check it here so we might as well + } + + finalChar = code; + oldCode = code; + myCode = code; + + outByte = code & kMaskLow; + dstW.writeByte(outByte); // Take just the lower byte and write it the output + + // :nextcode + while (carry == true) { + + code = getInputCode(carry, src, srcLen, evenOdd); // Get the next code + if (carry == true) { + + index = code << 1; + inputCode = code; + myCode = code; + + // Split up the conditional statement to be easier to follow + uint16 cond; + cond = start[index] & kMaskLast; + cond |= ptk[index]; + + if ((cond & kMaskHigh) == 0) { // Empty code + index = topStack; + outByte = finalChar & kMaskLow; + stack[index] = outByte; + topStack++; + myCode = oldCode; + } + + // :nextsymbol + index = myCode << 1; + while (index >= 0x200) { + myCode = start[index] & kMask12Bit; + outByte = ptk[index] & kMaskLow; + index = topStack; + stack[index] = outByte; + topStack++; + index = myCode << 1; + } + + // :singlechar + finalChar = (myCode >> 1); + outByte = finalChar & kMaskLow; + dstW.writeByte(outByte); + + // :dump + while (topStack != 0xFFFF) { // Dump the chars on the stack into the output file + outByte = stack[topStack] & kMaskLow; + dstW.writeByte(outByte); + topStack--; + } + + topStack = 0; + code = getMember(oldCode, finalChar, findEmpty, start, ptk); + oldCode = inputCode; + } + + } + + /* Return a readstream with a pointer to the data in the write stream. + * This one we do want to dispose after using, because it will be in the scope of the engine itself + */ + return new Common::MemoryReadStream(dstW.getData(), dstW.size(), DisposeAfterUse::YES); } void ImmortalEngine::setupDictionary(uint16 start[], uint16 ptk[], uint16 &findEmpty) { - // Clear the whole dictionary - for (int i = 0x3FFF; i >= 0; i--) { - start[i] = 0; - ptk[i] = 0; - } - - // Set the initial 256 bytes to be value 256, these are the characters without extensions - for (int i = 255; i >= 0; i--) { - ptk[i] = 256; - } - - // This shouldn't really be done inside the function, but for the sake of consistency with the source, we will - findEmpty = 0x8000; + // Clear the whole dictionary + for (int i = 0x3FFF; i >= 0; i--) { + start[i] = 0; + ptk[i] = 0; + } + + // Set the initial 256 bytes to be value 256, these are the characters without extensions + for (int i = 255; i >= 0; i--) { + ptk[i] = 256; + } + + // This shouldn't really be done inside the function, but for the sake of consistency with the source, we will + findEmpty = 0x8000; } int ImmortalEngine::getInputCode(bool &carry, Common::File *src, int &srcLen, uint16 &evenOdd) { - // Check if we're at the end of the file - if (srcLen == 0) { - carry = false; - return 0; - } - - uint16 c; - if (evenOdd != 0) { // Odd - srcLen--; - evenOdd--; - c = (src->readUint16BE() >> 3) & 0x00FE; // & #-1-1 - } else { // Even - srcLen -= 2; - evenOdd++; - c = (src->readUint16BE() & kMask12Bit) << 1; - src->seek(-1, SEEK_CUR); - } - return c; + // Check if we're at the end of the file + if (srcLen == 0) { + carry = false; + return 0; + } + + uint16 c; + if (evenOdd != 0) { // Odd + srcLen--; + evenOdd--; + c = (src->readUint16BE() >> 3) & 0x00FE; // & #-1-1 + } else { // Even + srcLen -= 2; + evenOdd++; + c = (src->readUint16BE() & kMask12Bit) << 1; + src->seek(-1, SEEK_CUR); + } + return c; } uint16 ImmortalEngine::getMember(uint16 codeW, uint16 k, uint16 &findEmpty, uint16 start[], uint16 ptk[]) { - // This function is effectively void, as the return value is only used in compression - - // k and codeW are local variables with the value of oldCode and finalChar - - uint16 hash; - uint16 tmp; - bool ag = true; - - hash = (k << 3) ^ k; - hash = (hash << 1) ^ codeW; - hash <<= 1; - - hash = (hash >= 0x200) ? hash : hash + 0x200; - - uint16 a = start[hash] & 0x0F00; - uint16 b = ptk[hash] & kMaskHigh; - if (a | b) { - start[hash] = codeW; - ptk[hash] = k | 0x100; - return ptk[hash]; - } - - // This loop is a bit wacky, due to the way the jumps were stuctured in the source - while (ag == true) { - if ((start[hash] & kMask12Bit) == codeW) { - if ((ptk[hash] & kMaskLow) == k) { - return hash >> 1; - } - } - - tmp = start[hash] & kMaskLast; - if (tmp == 0) { - // I've separated this into it's own function for the sake of this loop being readable - appendList(codeW, k, hash, findEmpty, start, ptk, tmp); - ag = false; - - } else { - hash = xba(ptk[hash]); - hash = (hash & kMaskLow) | (tmp >> 4); - hash <<= 1; - } - } - return hash; + // This function is effectively void, as the return value is only used in compression + + // k and codeW are local variables with the value of oldCode and finalChar + + uint16 hash; + uint16 tmp; + bool ag = true; + + hash = (k << 3) ^ k; + hash = (hash << 1) ^ codeW; + hash <<= 1; + + hash = (hash >= 0x200) ? hash : hash + 0x200; + + uint16 a = start[hash] & 0x0F00; + uint16 b = ptk[hash] & kMaskHigh; + if (a | b) { + start[hash] = codeW; + ptk[hash] = k | 0x100; + return ptk[hash]; + } + + // This loop is a bit wacky, due to the way the jumps were stuctured in the source + while (ag == true) { + if ((start[hash] & kMask12Bit) == codeW) { + if ((ptk[hash] & kMaskLow) == k) { + return hash >> 1; + } + } + + tmp = start[hash] & kMaskLast; + if (tmp == 0) { + // I've separated this into it's own function for the sake of this loop being readable + appendList(codeW, k, hash, findEmpty, start, ptk, tmp); + ag = false; + + } else { + hash = xba(ptk[hash]); + hash = (hash & kMaskLow) | (tmp >> 4); + hash <<= 1; + } + } + return hash; } void ImmortalEngine::appendList(uint16 codeW, uint16 k, uint16 &hash, uint16 &findEmpty, uint16 start[], uint16 ptk[], uint16 &tmp) { - uint16 prev; - uint16 link; - - prev = hash; - if (hash >= 0x200) { - setupDictionary(start, ptk, findEmpty); - - } else { - bool found = false; - while (found == false) { - hash -= 2; - if (hash >= 0x200) { - setupDictionary(start, ptk, findEmpty); - found = true; - } - - // Split up the conditional statement to be easier to follow - uint16 cond; - cond = start[hash] & kMaskLast; - cond |= ptk[hash]; - - if ((cond & kMaskHigh) == 0) { - findEmpty = hash; - start[hash] = codeW; - ptk[hash] = k | 0x100; - - link = hash >> 1; - - ptk[prev] = (link << 8) | (ptk[prev] & kMaskLow); - //start[prev] = ((link >> 4) & kMaskLast) | start[prev]; // Yikes this statement is gross - start[prev] |= (link >> 4) & kMaskLast; - found = true; - } - } - } + uint16 prev; + uint16 link; + + prev = hash; + if (hash >= 0x200) { + setupDictionary(start, ptk, findEmpty); + + } else { + bool found = false; + while (found == false) { + hash -= 2; + if (hash >= 0x200) { + setupDictionary(start, ptk, findEmpty); + found = true; + } + + // Split up the conditional statement to be easier to follow + uint16 cond; + cond = start[hash] & kMaskLast; + cond |= ptk[hash]; + + if ((cond & kMaskHigh) == 0) { + findEmpty = hash; + start[hash] = codeW; + ptk[hash] = k | 0x100; + + link = hash >> 1; + + ptk[prev] = (link << 8) | (ptk[prev] & kMaskLow); + //start[prev] = ((link >> 4) & kMaskLast) | start[prev]; // Yikes this statement is gross + start[prev] |= (link >> 4) & kMaskLast; + found = true; + } + } + } } } // namespace immortal diff --git a/engines/immortal/credits.pl b/engines/immortal/credits.pl index c9fc8d7affd6..59b13cf59b46 100644 --- a/engines/immortal/credits.pl +++ b/engines/immortal/credits.pl @@ -1,4 +1,3 @@ begin_section("Immortal"); add_person("Michael Hayman", "Quote58", ""); - #add_person("Eugene ?", "JoeFish", ""); end_section(); diff --git a/engines/immortal/cycle.cpp b/engines/immortal/cycle.cpp index 1eb43200ea25..c02570f93d60 100644 --- a/engines/immortal/cycle.cpp +++ b/engines/immortal/cycle.cpp @@ -25,7 +25,7 @@ namespace Immortal { void ImmortalEngine::cycleNew() {} int ImmortalEngine::getCycleChr() { - return 0; + return 0; } void ImmortalEngine::cycleFreeAll() {} void ImmortalEngine::cycleGetFile() {} diff --git a/engines/immortal/disk.cpp b/engines/immortal/disk.cpp index f92501183c1b..340a07d409ec 100644 --- a/engines/immortal/disk.cpp +++ b/engines/immortal/disk.cpp @@ -29,28 +29,28 @@ namespace Immortal { // --- ProDOSFile methods --- ProDOSFile::ProDOSFile(char name[15], uint8 type, uint16 tBlk, uint32 eof, uint16 bPtr, Common::File *disk) - : _type(type) - , _totalBlocks(tBlk) - , _eof(eof) - , _blockPtr(bPtr) - , _disk(disk) { - strcpy(_name, name); - } + : _type(type) + , _totalBlocks(tBlk) + , _eof(eof) + , _blockPtr(bPtr) + , _disk(disk) { + strcpy(_name, name); + } /* For debugging purposes, this prints the meta data of a file */ void ProDOSFile::printInfo() { - debug("File: %s", _name); - debug("Type: %02X", _type); - debug("data: %d", _blockPtr); - debug("Blocks: %d", _totalBlocks); - debug("Size: %u\n", _eof); + debug("File: %s", _name); + debug("Type: %02X", _type); + debug("data: %d", _blockPtr); + debug("Blocks: %d", _totalBlocks); + debug("Size: %u\n", _eof); } /* For Common::Archive, this method just returns a string of the name */ Common::String ProDOSFile::getName() const { - return Common::String(_name); + return Common::String(_name); } /* This method is used to get a single block of data from the disk, @@ -61,9 +61,9 @@ Common::String ProDOSFile::getName() const { void ProDOSFile::getDataBlock(byte *memOffset, int offset, int size) const { - // All this method needs to do is read (size) of data at (offset) into (memOffset) - _disk->seek(offset); - _disk->read(memOffset, size); + // All this method needs to do is read (size) of data at (offset) into (memOffset) + _disk->seek(offset); + _disk->read(memOffset, size); } /* To put together a sapling file, you need to loop through the index @@ -73,31 +73,31 @@ void ProDOSFile::getDataBlock(byte *memOffset, int offset, int size) const { */ int ProDOSFile::parseIndexBlock(byte *memOffset, int blockNum, int rem) const { - int dataSize; // For most of the blocks, this will be kBlockSize, but the last one will be the calculated remainder - int readSize = 0; // This keeps track of the new pointer position to read data to, by updating the size of data read last - int dataOffset; // Where in the disk to read from - int diskPos; // Current position of cursor - - for (int i = 0; i < blockNum; i++) { - dataSize = (i == (blockNum - 1)) ? rem : ProDOSDisk::kBlockSize; - dataOffset = _disk->readByte(); // Low byte is first - - /* The cursor needs to know where to get the next pointer from in the index block, - * but it also needs to jump to the offset of data to read it, so we need to preserve - * the position in the index block it was in before. - */ - diskPos = _disk->pos(); - - _disk->skip(255); // The high bytes are stored at the end of the block instead because reasons??? - dataOffset = (dataOffset + (_disk->readByte() << 8)) * ProDOSDisk::kBlockSize; // High byte is second - - getDataBlock(memOffset + readSize, dataOffset, dataSize); - readSize += dataSize; - - // And now we resume the position before this call - _disk->seek(diskPos); - } - return readSize; + int dataSize; // For most of the blocks, this will be kBlockSize, but the last one will be the calculated remainder + int readSize = 0; // This keeps track of the new pointer position to read data to, by updating the size of data read last + int dataOffset; // Where in the disk to read from + int diskPos; // Current position of cursor + + for (int i = 0; i < blockNum; i++) { + dataSize = (i == (blockNum - 1)) ? rem : ProDOSDisk::kBlockSize; + dataOffset = _disk->readByte(); // Low byte is first + + /* The cursor needs to know where to get the next pointer from in the index block, + * but it also needs to jump to the offset of data to read it, so we need to preserve + * the position in the index block it was in before. + */ + diskPos = _disk->pos(); + + _disk->skip(255); // The high bytes are stored at the end of the block instead because reasons??? + dataOffset = (dataOffset + (_disk->readByte() << 8)) * ProDOSDisk::kBlockSize; // High byte is second + + getDataBlock(memOffset + readSize, dataOffset, dataSize); + readSize += dataSize; + + // And now we resume the position before this call + _disk->seek(diskPos); + } + return readSize; } /* Extracting file data is a little tricky, as the blocks are spread out in the disk. There are 3 types @@ -109,62 +109,62 @@ int ProDOSFile::parseIndexBlock(byte *memOffset, int blockNum, int rem) const { Common::SeekableReadStream *ProDOSFile::createReadStream() const { - // We know the total byte size of the data, so we can allocate the full amount right away - byte *finalData = (byte *)malloc(_eof); - - /* For a seed, this is a direct pointer to data. For a sapling it is an index file, - * and for a tree it is a master index file. - */ - int indexBlock = _blockPtr * ProDOSDisk::kBlockSize; - - /* For a sapling or tree, the size needs to be calculated, as they are made from multiple blocks. - * _totalBlocks *includes* the index block, so the blocks before the oef block are _totalBlocks-2 - */ - int remainder = _eof - ((_totalBlocks - 2) * ProDOSDisk::kBlockSize); - - // For a seed file, the end of file value is also the size in the block, because it's just the one block - if (_type == kFileTypeSeed) { - getDataBlock(finalData, indexBlock, _eof); - - } else if (_type == kFileTypeSapling) { - _disk->seek(indexBlock); - parseIndexBlock(finalData, _totalBlocks - 1, remainder); - - } else { - // If it's not a seed and not a sapling, it's a tree. - _disk->seek(indexBlock); - - /* A sapling can have an index block of up to 256, so if it is a tree, - * that means it has more than 256 blocks - */ - int indexNum = (_totalBlocks - 1) / 256; - int indexNumR = (_totalBlocks - 1) % 256; - - /* However, to know how many index blocks there are, we need to know the remainder - * so we can figure out if it's ex. 2 index blocks, or 2 and some portion of a 3rd - */ - indexNum += indexNumR; - int blockNum; - int indexOffset; - int readSize = 0; - - // Now we can loop through the master index file, parsing the individual index files similar to a sapling - for (int i = 0; i < indexNum; i++) { - blockNum = (i == indexNum - 1) ? indexNumR : 256; - - indexOffset = _disk->readByte(); - int diskPos = _disk->pos(); - - _disk->skip(255); - indexOffset = (indexOffset + (_disk->readByte() << 8)) * ProDOSDisk::kBlockSize; - - _disk->seek(indexOffset); - readSize += parseIndexBlock(finalData + readSize, blockNum, remainder); - - _disk->seek(diskPos); - } - } - return new Common::MemoryReadStream(finalData, _eof, DisposeAfterUse::YES); + // We know the total byte size of the data, so we can allocate the full amount right away + byte *finalData = (byte *)malloc(_eof); + + /* For a seed, this is a direct pointer to data. For a sapling it is an index file, + * and for a tree it is a master index file. + */ + int indexBlock = _blockPtr * ProDOSDisk::kBlockSize; + + /* For a sapling or tree, the size needs to be calculated, as they are made from multiple blocks. + * _totalBlocks *includes* the index block, so the blocks before the oef block are _totalBlocks-2 + */ + int remainder = _eof - ((_totalBlocks - 2) * ProDOSDisk::kBlockSize); + + // For a seed file, the end of file value is also the size in the block, because it's just the one block + if (_type == kFileTypeSeed) { + getDataBlock(finalData, indexBlock, _eof); + + } else if (_type == kFileTypeSapling) { + _disk->seek(indexBlock); + parseIndexBlock(finalData, _totalBlocks - 1, remainder); + + } else { + // If it's not a seed and not a sapling, it's a tree. + _disk->seek(indexBlock); + + /* A sapling can have an index block of up to 256, so if it is a tree, + * that means it has more than 256 blocks + */ + int indexNum = (_totalBlocks - 1) / 256; + int indexNumR = (_totalBlocks - 1) % 256; + + /* However, to know how many index blocks there are, we need to know the remainder + * so we can figure out if it's ex. 2 index blocks, or 2 and some portion of a 3rd + */ + indexNum += indexNumR; + int blockNum; + int indexOffset; + int readSize = 0; + + // Now we can loop through the master index file, parsing the individual index files similar to a sapling + for (int i = 0; i < indexNum; i++) { + blockNum = (i == indexNum - 1) ? indexNumR : 256; + + indexOffset = _disk->readByte(); + int diskPos = _disk->pos(); + + _disk->skip(255); + indexOffset = (indexOffset + (_disk->readByte() << 8)) * ProDOSDisk::kBlockSize; + + _disk->seek(indexOffset); + readSize += parseIndexBlock(finalData + readSize, blockNum, remainder); + + _disk->seek(diskPos); + } + } + return new Common::MemoryReadStream(finalData, _eof, DisposeAfterUse::YES); } // --- ProDOSDisk methods --- @@ -175,54 +175,54 @@ Common::SeekableReadStream *ProDOSFile::createReadStream() const { */ void ProDOSDisk::getDate(Date *d, uint16 date) { - d->_day = date & 0x001f; - d->_month = (date & 0x01e0) >> 5; - d->_year = (date & 0xfe00) >> 9; + d->_day = date & 0x001f; + d->_month = (date & 0x01e0) >> 5; + d->_year = (date & 0xfe00) >> 9; } void ProDOSDisk::getTime(Time *t, uint16 time) { - t->_minute = time & 0x003f; - t->_hour = (time & 0x1f00) >> 8; + t->_minute = time & 0x003f; + t->_hour = (time & 0x1f00) >> 8; } /* Adds most of the header data to a directory header struct */ void ProDOSDisk::getHeader(DirHeader *h) { - /* The type and nameLen fields are stored in the same byte, - * so we need to split the byte, and shift the high bits to - * make it readable as an int - */ - uint8 tempByte = _disk.readByte(); - h->_nameLen = tempByte & 0xf; - h->_type = (tempByte & 0xf0) >> 4; - - /* The name field is stored in 15 bytes with no null character (unused chars default to 0). - * To make it easier to use the name, we will add a terminator regardless. - */ - _disk.read(h->_name, 15); - h->_name[15] = 0; - _disk.read(h->_reserved, 8); - - // The time and date can be decompressed into structs right away - getDate(&(h->_date), _disk.readUint16LE()); - getTime(&(h->_time), _disk.readUint16LE()); - - h->_ver = _disk.readByte(); - h->_minVer = _disk.readByte(); - h->_access = _disk.readByte(); - h->_entryLen = _disk.readByte(); - h->_entriesPerBlock = _disk.readByte(); - h->_fileCount = _disk.readUint16LE(); + /* The type and nameLen fields are stored in the same byte, + * so we need to split the byte, and shift the high bits to + * make it readable as an int + */ + uint8 tempByte = _disk.readByte(); + h->_nameLen = tempByte & 0xf; + h->_type = (tempByte & 0xf0) >> 4; + + /* The name field is stored in 15 bytes with no null character (unused chars default to 0). + * To make it easier to use the name, we will add a terminator regardless. + */ + _disk.read(h->_name, 15); + h->_name[15] = 0; + _disk.read(h->_reserved, 8); + + // The time and date can be decompressed into structs right away + getDate(&(h->_date), _disk.readUint16LE()); + getTime(&(h->_time), _disk.readUint16LE()); + + h->_ver = _disk.readByte(); + h->_minVer = _disk.readByte(); + h->_access = _disk.readByte(); + h->_entryLen = _disk.readByte(); + h->_entriesPerBlock = _disk.readByte(); + h->_fileCount = _disk.readUint16LE(); } /* Since a subdirectory header is mostly the same a volume header, we will reuse the code where we can */ void ProDOSDisk::getDirectoryHeader(DirHeader *h) { - getHeader(h); - h->_parentBlockPtr = _disk.readUint16LE(); - h->_parentEntryIndex = _disk.readByte(); - h->_parentEntryLen = _disk.readUint16LE(); + getHeader(h); + h->_parentBlockPtr = _disk.readUint16LE(); + h->_parentEntryIndex = _disk.readByte(); + h->_parentEntryLen = _disk.readUint16LE(); } /* This is a little sneaky, but since the bulk of the header is the same, we're just going to pretend the volume header @@ -230,40 +230,40 @@ void ProDOSDisk::getDirectoryHeader(DirHeader *h) { */ void ProDOSDisk::getVolumeHeader(VolHeader *h) { - getHeader((DirHeader *)h); - h->_bitmapPtr = _disk.readUint16LE(); - h->_volBlocks = _disk.readUint16LE(); - _volBlocks = h->_volBlocks; + getHeader((DirHeader *)h); + h->_bitmapPtr = _disk.readUint16LE(); + h->_volBlocks = _disk.readUint16LE(); + _volBlocks = h->_volBlocks; } /* Getting a file entry header is very similar to getting a header, but with different data. */ void ProDOSDisk::getFileEntry(FileEntry *f) { - uint8 tempByte = _disk.readByte(); - f->_nameLen = tempByte & 0xf; - f->_type = (tempByte & 0xf0) >> 4; + uint8 tempByte = _disk.readByte(); + f->_nameLen = tempByte & 0xf; + f->_type = (tempByte & 0xf0) >> 4; - _disk.read(f->_name, 15); - f->_name[15] = 0; - f->_ext = _disk.readByte(); - f->_blockPtr = _disk.readUint16LE(); - f->_totalBlocks = _disk.readUint16LE(); + _disk.read(f->_name, 15); + f->_name[15] = 0; + f->_ext = _disk.readByte(); + f->_blockPtr = _disk.readUint16LE(); + f->_totalBlocks = _disk.readUint16LE(); - // The file size in bytes is stored as a long (3 bytes), lowest to highest - f->_eof = _disk.readByte() + (_disk.readByte() << 8) + (_disk.readByte() << 16); + // The file size in bytes is stored as a long (3 bytes), lowest to highest + f->_eof = _disk.readByte() + (_disk.readByte() << 8) + (_disk.readByte() << 16); - getDate(&(f->_date), _disk.readUint16LE()); - getTime(&(f->_time), _disk.readUint16LE()); + getDate(&(f->_date), _disk.readUint16LE()); + getTime(&(f->_time), _disk.readUint16LE()); - f->_ver = _disk.readByte(); - f->_minVer = _disk.readByte(); - f->_access = _disk.readByte(); - f->_varUse = _disk.readUint16LE(); + f->_ver = _disk.readByte(); + f->_minVer = _disk.readByte(); + f->_access = _disk.readByte(); + f->_varUse = _disk.readUint16LE(); - getDate(&(f->_modDate), _disk.readUint16LE()); - getTime(&(f->_modTime), _disk.readUint16LE()); + getDate(&(f->_modDate), _disk.readUint16LE()); + getTime(&(f->_modTime), _disk.readUint16LE()); - f->_dirHeadPtr = _disk.readUint16LE(); + f->_dirHeadPtr = _disk.readUint16LE(); } /* This is basically a loop based on the number of total files indicated by the header (including deleted file entries), @@ -274,52 +274,52 @@ void ProDOSDisk::getFileEntry(FileEntry *f) { */ void ProDOSDisk::searchDirectory(DirHeader *h, uint16 p, uint16 n, Common::String path) { - int currPos; - int parsedFiles = 0; - - for (int i = 0; i < h->_fileCount; i++) { - // When we have read all the files for a given block (_entriesPerBlock), we need to change to the next block of the directory - if (parsedFiles == h->_entriesPerBlock) { - parsedFiles = 0; - _disk.seek(n * kBlockSize); - p = _disk.readUint16LE(); - n = _disk.readUint16LE(); - } - - FileEntry fileEntry; - getFileEntry(&fileEntry); - //debug("%s", fileEntry._name); - parsedFiles++; - currPos = _disk.pos(); - - // It is a regular file if (dead < file type < pascal) and the file has a size - if ((kFileTypeDead < fileEntry._type) && (fileEntry._type < kFileTypePascal) && (fileEntry._eof > 0)) { - Common::String fileName = path + fileEntry._name; - debug("%s", fileName.c_str()); - ProDOSFile *currFile = new ProDOSFile(fileEntry._name, fileEntry._type, fileEntry._totalBlocks, fileEntry._eof, fileEntry._blockPtr, &_disk); - - _files.setVal(fileName, Common::SharedPtr(currFile)); - _disk.seek(currPos); - - // Otherwise, if it is a subdirectory, we want to explore that subdirectory - } else if (fileEntry._type == kFileTypeSubDir) { - - _disk.seek(fileEntry._blockPtr * kBlockSize); - debug("--- diving into a subdirectory ---"); - - uint16 subP = _disk.readUint16LE(); - uint16 subN = _disk.readUint16LE(); - DirHeader subHead; - getDirectoryHeader(&subHead); - - // Give it a temporary new path name by sticking the name of the subdirectory on to the end of the current path - Common::String subPath = Common::String(path + subHead._name + '/'); - searchDirectory(&subHead, subP, subN, path); - - debug("--- surfacing to parent directory ---"); - _disk.seek(currPos); - } - } + int currPos; + int parsedFiles = 0; + + for (int i = 0; i < h->_fileCount; i++) { + // When we have read all the files for a given block (_entriesPerBlock), we need to change to the next block of the directory + if (parsedFiles == h->_entriesPerBlock) { + parsedFiles = 0; + _disk.seek(n * kBlockSize); + p = _disk.readUint16LE(); + n = _disk.readUint16LE(); + } + + FileEntry fileEntry; + getFileEntry(&fileEntry); + //debug("%s", fileEntry._name); + parsedFiles++; + currPos = _disk.pos(); + + // It is a regular file if (dead < file type < pascal) and the file has a size + if ((kFileTypeDead < fileEntry._type) && (fileEntry._type < kFileTypePascal) && (fileEntry._eof > 0)) { + Common::String fileName = path + fileEntry._name; + debug("%s", fileName.c_str()); + ProDOSFile *currFile = new ProDOSFile(fileEntry._name, fileEntry._type, fileEntry._totalBlocks, fileEntry._eof, fileEntry._blockPtr, &_disk); + + _files.setVal(fileName, Common::SharedPtr(currFile)); + _disk.seek(currPos); + + // Otherwise, if it is a subdirectory, we want to explore that subdirectory + } else if (fileEntry._type == kFileTypeSubDir) { + + _disk.seek(fileEntry._blockPtr * kBlockSize); + debug("--- diving into a subdirectory ---"); + + uint16 subP = _disk.readUint16LE(); + uint16 subN = _disk.readUint16LE(); + DirHeader subHead; + getDirectoryHeader(&subHead); + + // Give it a temporary new path name by sticking the name of the subdirectory on to the end of the current path + Common::String subPath = Common::String(path + subHead._name + '/'); + searchDirectory(&subHead, subP, subN, path); + + debug("--- surfacing to parent directory ---"); + _disk.seek(currPos); + } + } } /* The volume bitmap is a bitmap spanning as many blocks as is required to store 1 bit for every @@ -328,67 +328,67 @@ void ProDOSDisk::searchDirectory(DirHeader *h, uint16 p, uint16 n, Common::Strin */ void ProDOSDisk::getVolumeBitmap(VolHeader *h) { - int currPos = _disk.pos(); - int bitmapSize; + int currPos = _disk.pos(); + int bitmapSize; - bitmapSize = _volBlocks / 4096; - if ((_volBlocks % 4096) > 0) { - bitmapSize++; - } + bitmapSize = _volBlocks / 4096; + if ((_volBlocks % 4096) > 0) { + bitmapSize++; + } - _volBitmap = (byte *)malloc(bitmapSize * kBlockSize); - _disk.seek(h->_bitmapPtr * kBlockSize); - _disk.read(_volBitmap, bitmapSize); + _volBitmap = (byte *)malloc(bitmapSize * kBlockSize); + _disk.seek(h->_bitmapPtr * kBlockSize); + _disk.read(_volBitmap, bitmapSize); - _disk.seek(currPos); + _disk.seek(currPos); } /* Gets the volume information and parses the filesystem, adding file objects to a map as it goes */ bool ProDOSDisk::open(const Common::String filename) { - debug("opening %s", filename.c_str()); + debug("opening %s", filename.c_str()); - _disk.open(filename); - _disk.read(_loader1, kBlockSize); - _disk.read(_loader2, kBlockSize); + _disk.open(filename); + _disk.read(_loader1, kBlockSize); + _disk.read(_loader2, kBlockSize); - uint16 prev = _disk.readUint16LE(); // This is always going to be 0 for the volume header, but there's also no reason to skip it - uint16 next = _disk.readUint16LE(); + uint16 prev = _disk.readUint16LE(); // This is always going to be 0 for the volume header, but there's also no reason to skip it + uint16 next = _disk.readUint16LE(); - VolHeader header; - getVolumeHeader(&header); - debug("volume name: %s", header._name); + VolHeader header; + getVolumeHeader(&header); + debug("volume name: %s", header._name); - getVolumeBitmap(&header); + getVolumeBitmap(&header); - Common::String pathName; // This is so that the path name starts blank, and then for every directory searched it adds the directory name to the path - searchDirectory((DirHeader *)&header, prev, next, pathName); + Common::String pathName; // This is so that the path name starts blank, and then for every directory searched it adds the directory name to the path + searchDirectory((DirHeader *)&header, prev, next, pathName); - return true; // When I get to error checking on this, the bool will be useful + return true; // When I get to error checking on this, the bool will be useful } /* Constructor simply calls open(), and if it is successful it prints a statement */ ProDOSDisk::ProDOSDisk(const Common::String filename) { - if (open(filename)) { - debug ("%s has been loaded", filename.c_str()); - } + if (open(filename)) { + debug ("%s has been loaded", filename.c_str()); + } } /* Destructor closes the disk and clears the map of files */ ProDOSDisk::~ProDOSDisk() { - _disk.close(); - _files.clear(); - free(_volBitmap); // Should this be free() or delete? + _disk.close(); + _files.clear(); + free(_volBitmap); // Should this be free() or delete? } // --- Common::Archive methods --- // Very simple, just checks if the dictionary contains the path name bool ProDOSDisk::hasFile(const Common::Path &path) const { - Common::String name = path.toString(); - return _files.contains(name); + Common::String name = path.toString(); + return _files.contains(name); } /* To create a list of files in the Archive, we define an iterator for the object type @@ -397,22 +397,22 @@ bool ProDOSDisk::hasFile(const Common::Path &path) const { */ int ProDOSDisk::listMembers(Common::ArchiveMemberList &list) const { - int f = 0; - Common::HashMap>::const_iterator it; - for (it = _files.begin(); it != _files.end(); ++it) { - list.push_back(Common::ArchiveMemberList::value_type(it->_value)); - ++f; - } - return f; + int f = 0; + Common::HashMap>::const_iterator it; + for (it = _files.begin(); it != _files.end(); ++it) { + list.push_back(Common::ArchiveMemberList::value_type(it->_value)); + ++f; + } + return f; } // If the dictionary contains the path name (could probably call hasFile() instead), get the object const Common::ArchiveMemberPtr ProDOSDisk::getMember(const Common::Path &path) const { - Common::String name = path.toString(); - if (!_files.contains(name)) { - return Common::ArchiveMemberPtr(); - } - return _files.getValOrDefault(name); + Common::String name = path.toString(); + if (!_files.contains(name)) { + return Common::ArchiveMemberPtr(); + } + return _files.getValOrDefault(name); } /* This method is called on Archive members as it searches for the correct one, @@ -420,13 +420,13 @@ const Common::ArchiveMemberPtr ProDOSDisk::getMember(const Common::Path &path) c */ Common::SeekableReadStream *ProDOSDisk::createReadStreamForMember(const Common::Path &path) const { - Common::String name = path.toString(); - if (!_files.contains(name)) { - return nullptr; - } - Common::SharedPtr f = _files.getValOrDefault(name); - f->printInfo(); - return f->createReadStream(); + Common::String name = path.toString(); + if (!_files.contains(name)) { + return nullptr; + } + Common::SharedPtr f = _files.getValOrDefault(name); + f->printInfo(); + return f->createReadStream(); } } // namespace Immortal diff --git a/engines/immortal/disk.h b/engines/immortal/disk.h index a6045fc4a68f..030fbb00f88e 100644 --- a/engines/immortal/disk.h +++ b/engines/immortal/disk.h @@ -38,14 +38,14 @@ namespace Immortal { // These values define for ProDOS how to read the file entry, and also whether it's a keyblock (if it is a directory header, it's the keyblock of that directory) enum FileType : char { - kFileTypeDead = 0, - kFileTypeSeed = 1, - kFileTypeSapling = 2, - kFileTypeTree = 3, - kFileTypePascal = 4, - kFileTypeSubDir = 0x0D, - kFileTypeSubHead = 0x0E, - kFileTypeVolHead = 0x0F + kFileTypeDead = 0, + kFileTypeSeed = 1, + kFileTypeSapling = 2, + kFileTypeTree = 3, + kFileTypePascal = 4, + kFileTypeSubDir = 0x0D, + kFileTypeSubHead = 0x0E, + kFileTypeVolHead = 0x0F }; /* File extensions for all the ProDOS supported file types @@ -53,25 +53,25 @@ enum FileType : char { * they can be added to this enum. */ enum FileExt { - kFileExtNull = 0, - kFileExtBad = 1, - kFileExtTxt = 4, - kFileExtBin = 6, - kFileExtGfx = 8, - kFileExtDir = 0xF, - kFileExtDB = 0x19, - kFileExtWord = 0x1A, - kFileExtSpread = 0x1B, - kFileExtSTART = 0xB3, - kFileExtPascal = 0xEF, - kFileExtPDCI = 0xF0, - kFileExtPDRes = 0xF9, - kFileExtIBProg = 0xFA, - kFileExtIBVar = 0xFB, - kFileExtAPSProg = 0xFC, - kFileExtAPSVar = 0xFD, - kFileExtEDASM = 0xFE, - kFileExtSYS = 0xFF + kFileExtNull = 0, + kFileExtBad = 1, + kFileExtTxt = 4, + kFileExtBin = 6, + kFileExtGfx = 8, + kFileExtDir = 0xF, + kFileExtDB = 0x19, + kFileExtWord = 0x1A, + kFileExtSpread = 0x1B, + kFileExtSTART = 0xB3, + kFileExtPascal = 0xEF, + kFileExtPDCI = 0xF0, + kFileExtPDRes = 0xF9, + kFileExtIBProg = 0xFA, + kFileExtIBVar = 0xFB, + kFileExtAPSProg = 0xFC, + kFileExtAPSVar = 0xFD, + kFileExtEDASM = 0xFE, + kFileExtSYS = 0xFF }; /* A ProDOS file simply contains meta data about the file and the ability to @@ -82,25 +82,25 @@ enum FileExt { class ProDOSFile : public Common::ArchiveMember { public: - ProDOSFile(char name[16], uint8 type, uint16 tBlk, uint32 eof, uint16 bPtr, Common::File *disk); - ~ProDOSFile() {}; + ProDOSFile(char name[16], uint8 type, uint16 tBlk, uint32 eof, uint16 bPtr, Common::File *disk); + ~ProDOSFile() {}; - // -- These are the Common::ArchiveMember related functions -- - Common::String getName() const override; // Returns _name - Common::SeekableReadStream *createReadStream() const override; // This is what the archive needs to create a file - void getDataBlock(byte *memOffset, int offset, int size) const; // Gets data up to the size of a single data block (512 bytes) - int parseIndexBlock(byte *memOffset, int blockNum, int cSize) const; // Uses getDataBlock() on every pointer in the index file, adding them to byte * memory block + // -- These are the Common::ArchiveMember related functions -- + Common::String getName() const override; // Returns _name + Common::SeekableReadStream *createReadStream() const override; // This is what the archive needs to create a file + void getDataBlock(byte *memOffset, int offset, int size) const; // Gets data up to the size of a single data block (512 bytes) + int parseIndexBlock(byte *memOffset, int blockNum, int cSize) const; // Uses getDataBlock() on every pointer in the index file, adding them to byte * memory block - // For debugging purposes, just prints the metadata - void printInfo(); + // For debugging purposes, just prints the metadata + void printInfo(); private: - char _name[16]; - uint8 _type; // As defined by enum FileType - uint16 _blockPtr; // Block index in volume of index block or data - uint16 _totalBlocks; - uint32 _eof; // End Of File, used generally as size (exception being sparse files) - Common::File *_disk; // This is a pointer because it is the same _disk as in ProDosDisk, passed to the file object + char _name[16]; + uint8 _type; // As defined by enum FileType + uint16 _blockPtr; // Block index in volume of index block or data + uint16 _totalBlocks; + uint32 _eof; // End Of File, used generally as size (exception being sparse files) + Common::File *_disk; // This is a pointer because it is the same _disk as in ProDosDisk, passed to the file object }; /* This class defines the entire disk volume. Upon using the open() method, @@ -111,102 +111,102 @@ class ProDOSFile : public Common::ArchiveMember { class ProDOSDisk : public Common::Archive { public: - static const int kBlockSize = 512; // A ProDOS block is always 512 bytes (should this be an enum?) + static const int kBlockSize = 512; // A ProDOS block is always 512 bytes (should this be an enum?) - ProDOSDisk(const Common::String filename); - ~ProDOSDisk(); // Frees the memory used in the dictionary and the volume bitmap + ProDOSDisk(const Common::String filename); + ~ProDOSDisk(); // Frees the memory used in the dictionary and the volume bitmap - // Called from the constructor, it parses the volume and fills the hashmap with files - bool open(const Common::String filename); + // Called from the constructor, it parses the volume and fills the hashmap with files + bool open(const Common::String filename); - // These are the Common::Archive related methods - bool hasFile(const Common::Path &path) const override; - int listMembers(Common::ArchiveMemberList &list) const override; - const Common::ArchiveMemberPtr getMember(const Common::Path &path) const override; - Common::SeekableReadStream *createReadStreamForMember(const Common::Path &path) const override; + // These are the Common::Archive related methods + bool hasFile(const Common::Path &path) const override; + int listMembers(Common::ArchiveMemberList &list) const override; + const Common::ArchiveMemberPtr getMember(const Common::Path &path) const override; + Common::SeekableReadStream *createReadStreamForMember(const Common::Path &path) const override; private: - byte _loader1[kBlockSize]; // There's not much reason for these to be needed, but I included them just in case - byte _loader2[kBlockSize]; + byte _loader1[kBlockSize]; // There's not much reason for these to be needed, but I included them just in case + byte _loader2[kBlockSize]; Common::String _name; // Name of volume Common::File _disk; // The volume file itself - int _volBlocks; // Total blocks in volume - byte *_volBitmap; // This can determine if the volume is corrupt as it contains a bit for every block, where 0 = unused, 1 = used + int _volBlocks; // Total blocks in volume + byte *_volBitmap; // This can determine if the volume is corrupt as it contains a bit for every block, where 0 = unused, 1 = used Common::HashMap> _files; // Hashmap of files in the volume, where key=Path, Value=ProDOSFile - struct Date { - uint8 _day; - uint8 _month; - uint8 _year; - }; - - struct Time { - uint8 _hour; - uint8 _minute; - }; - - struct VolHeader { - uint8 _type; // Not really important for a volume header, as this will always be F - uint8 _nameLen; - char _name[16]; - byte _reserved[8]; // Extra space reserved for possible future uses, not important - Date _date; - Time _time; - uint8 _ver; - uint8 _minVer; // Should pretty much always be 0 as far as I know - uint8 _access; // If this ends up useful, there should be an enum for the access values - uint8 _entryLen; // Always 27 in ProDOS 1.0 - uint8 _entriesPerBlock; // Always 0D in ProDOS 1.0 - uint16 _fileCount; // Number of files across all data blocks in this directory - uint16 _bitmapPtr; // Block pointer to the keyblock of the bitmap for the entire volume - uint16 _volBlocks; // Blocks in entire volume - }; - - struct DirHeader { - uint8 _type; - uint8 _nameLen; - char _name[16]; - byte _reserved[8]; - Date _date; - Time _time; - uint8 _ver; - uint8 _minVer; - uint8 _access; - uint8 _entryLen; - uint8 _entriesPerBlock; - uint16 _fileCount; - uint16 _parentBlockPtr; // These values allow ProDOS to navigate back out of a directory, but they aren't really needed by the class to navigate - uint8 _parentEntryIndex; // Index in the current directory - uint8 _parentEntryLen; // This is always 27 in ProDOS 1.0 - }; - - struct FileEntry { - uint8 _type; // 0 = inactive, 1-3 = file, 4 = pascal area, 14 = subdirectory, 15 = volume directory - uint8 _nameLen; - char _name[16]; - uint8 _ext; // File extension, uses the enum FileExt - uint16 _blockPtr; // Block pointer to data for seedling, index block for sapling, or master block for tree - uint16 _totalBlocks; // Really important to remember this is the total *including* the index block - uint32 _eof; // This is a long (3 bytes, read low to high) value representing the total readable data in a file (unless it's a sparse file, be careful!) - Date _date; - Time _time; - uint8 _ver; - uint8 _minVer; - uint8 _access; - uint16 _varUse; - Date _modDate; - Time _modTime; - uint16 _dirHeadPtr; // Pointer to the key block of the directory that contains this file entry - }; - - void getDate(Date *d, uint16 date); // Decompresses the date into a struct - void getTime(Time *t, uint16 time); // Decompresses the time into a struct - void getHeader(DirHeader *h); // Adds the main header values to the struct - void getDirectoryHeader(DirHeader *h); // Uses getHeader and then fills in the values for the parent directory - void getVolumeHeader(VolHeader *dir); // Uses getHeader and then fills in the volume related information (there is no parent directory to this one) - void getFileEntry(FileEntry *f); // Adds all of the file entry information to the struct - void searchDirectory(DirHeader *h, uint16 p, uint16 n, Common::String path); // Recursively searches all files within a directory, by calling itself for subdirectories - void getVolumeBitmap(VolHeader *h); // Puts together the volume bitmap + struct Date { + uint8 _day; + uint8 _month; + uint8 _year; + }; + + struct Time { + uint8 _hour; + uint8 _minute; + }; + + struct VolHeader { + uint8 _type; // Not really important for a volume header, as this will always be F + uint8 _nameLen; + char _name[16]; + byte _reserved[8]; // Extra space reserved for possible future uses, not important + Date _date; + Time _time; + uint8 _ver; + uint8 _minVer; // Should pretty much always be 0 as far as I know + uint8 _access; // If this ends up useful, there should be an enum for the access values + uint8 _entryLen; // Always 27 in ProDOS 1.0 + uint8 _entriesPerBlock; // Always 0D in ProDOS 1.0 + uint16 _fileCount; // Number of files across all data blocks in this directory + uint16 _bitmapPtr; // Block pointer to the keyblock of the bitmap for the entire volume + uint16 _volBlocks; // Blocks in entire volume + }; + + struct DirHeader { + uint8 _type; + uint8 _nameLen; + char _name[16]; + byte _reserved[8]; + Date _date; + Time _time; + uint8 _ver; + uint8 _minVer; + uint8 _access; + uint8 _entryLen; + uint8 _entriesPerBlock; + uint16 _fileCount; + uint16 _parentBlockPtr; // These values allow ProDOS to navigate back out of a directory, but they aren't really needed by the class to navigate + uint8 _parentEntryIndex; // Index in the current directory + uint8 _parentEntryLen; // This is always 27 in ProDOS 1.0 + }; + + struct FileEntry { + uint8 _type; // 0 = inactive, 1-3 = file, 4 = pascal area, 14 = subdirectory, 15 = volume directory + uint8 _nameLen; + char _name[16]; + uint8 _ext; // File extension, uses the enum FileExt + uint16 _blockPtr; // Block pointer to data for seedling, index block for sapling, or master block for tree + uint16 _totalBlocks; // Really important to remember this is the total *including* the index block + uint32 _eof; // This is a long (3 bytes, read low to high) value representing the total readable data in a file (unless it's a sparse file, be careful!) + Date _date; + Time _time; + uint8 _ver; + uint8 _minVer; + uint8 _access; + uint16 _varUse; + Date _modDate; + Time _modTime; + uint16 _dirHeadPtr; // Pointer to the key block of the directory that contains this file entry + }; + + void getDate(Date *d, uint16 date); // Decompresses the date into a struct + void getTime(Time *t, uint16 time); // Decompresses the time into a struct + void getHeader(DirHeader *h); // Adds the main header values to the struct + void getDirectoryHeader(DirHeader *h); // Uses getHeader and then fills in the values for the parent directory + void getVolumeHeader(VolHeader *dir); // Uses getHeader and then fills in the volume related information (there is no parent directory to this one) + void getFileEntry(FileEntry *f); // Adds all of the file entry information to the struct + void searchDirectory(DirHeader *h, uint16 p, uint16 n, Common::String path); // Recursively searches all files within a directory, by calling itself for subdirectories + void getVolumeBitmap(VolHeader *h); // Puts together the volume bitmap }; diff --git a/engines/immortal/immortal.cpp b/engines/immortal/immortal.cpp index 13856bca0f32..c07bcfdda3d7 100644 --- a/engines/immortal/immortal.cpp +++ b/engines/immortal/immortal.cpp @@ -181,20 +181,20 @@ Common::Error ImmortalEngine::run() { // Main Common::Event event; - g_system->getEventManager()->pollEvent(event); - - userIO(); - noNetwork(); - pollKeys(); - logic(); - pollKeys(); - if (logicFreeze() == 0) { - drawUniv(); - pollKeys(); - fixColors(); - copyToScreen(); - pollKeys(); - } + g_system->getEventManager()->pollEvent(event); + + userIO(); + noNetwork(); + pollKeys(); + logic(); + pollKeys(); + if (logicFreeze() == 0) { + drawUniv(); + pollKeys(); + fixColors(); + copyToScreen(); + pollKeys(); + } if (_err != Common::kNoError) { debug("To err is human, to really screw up you need an Apple IIGS!"); diff --git a/engines/immortal/immortal.h b/engines/immortal/immortal.h index b3914ddb5127..3c6203e9979e 100644 --- a/engines/immortal/immortal.h +++ b/engines/immortal/immortal.h @@ -55,33 +55,45 @@ namespace Immortal { // There is a lot of bit masking that needs to happen, so this enum makes it a little easier to read enum BitMask16 : uint16 { - kMaskLow = 0x00FF, - kMaskHigh = 0xFF00, - kMaskLast = 0xF000, - kMaskFirst = 0x000F, - kMaskHLow = 0x0F00, - kMaskLHigh = 0x00F0, - kMaskNeg = 0x8000, - kMask12Bit = 0x0F9F // Compression code (pos, 00, len) is stored in lower 12 bits of word + kMaskLow = 0x00FF, + kMaskHigh = 0xFF00, + kMaskLast = 0xF000, + kMaskFirst = 0x000F, + kMaskHLow = 0x0F00, + kMaskLHigh = 0x00F0, + kMaskNeg = 0x8000, + kMask12Bit = 0x0F9F // Compression code (pos, 00, len) is stored in lower 12 bits of word }; enum BitMask8 : uint8 { - kMaskASCII = 0x7F, // The non-extended ASCII table uses 7 bits, this makes a couple of things easier - kMask8High = 0xF0, - kMask8Low = 0x0F + kMaskASCII = 0x7F, // The non-extended ASCII table uses 7 bits, this makes a couple of things easier + kMask8High = 0xF0, + kMask8Low = 0x0F }; - enum ColourMask : uint16 { kMaskRed = 0x0F00, kMaskGreen = 0x00F0, kMaskBlue = 0x000F }; +enum InputAction : int { + kActionRestart, + kActionSound, + kActionFire +}; + +enum InputDirection : int { + kDirectionUp, + kDirectionLeft, + kDirectionDown, + kDirectionRight +}; + struct DataSprite { - uint8 _cenX; // These are the base center positions - uint8 _cenY; - byte *_bitmap; // Pointer to actual data + uint8 _cenX; // These are the base center positions + uint8 _cenY; + byte *_bitmap; // Pointer to actual data Common::SeekableReadStream *_file; // This will likely be removed later }; @@ -89,15 +101,15 @@ struct Sprite { int _frame; // Current frame of the cycle uint16 _X; uint16 _Y; - uint16 _on; // 1 = active + uint16 _on; // 1 = active uint16 _priority; DataSprite *_dSprite; }; struct Cycle { DataSprite *_dSprite; - int _numCycles; - int *_frames; + int _numCycles; + int *_frames; }; struct ImmortalGameDescription; @@ -159,19 +171,27 @@ class ImmortalEngine : public Engine { * 'global' members */ Common::ErrorCode _err; // If this is not kNoError at any point, the engine will stop - bool _draw = 0; // Whether the screen should draw this frame - bool _dim = 0; // Whether the palette is dim - bool _usingNormal = 0; // Whether the palette is using normal - int _zero = 0; // No idea what this is yet - uint8 _gameOverFlag = 0; - uint8 _levelOver = 0; - uint8 _themePaused = 0; - int _level = 0; - int _titlesShown = 0; - int _time = 0; - int _promoting = 0; - int _restart = 0; - int _lastCertLen = 0; + bool _draw = 0; // Whether the screen should draw this frame + bool _dim = 0; // Whether the palette is dim + bool _usingNormal = 0; // Whether the palette is using normal + int _zero = 0; // No idea what this is yet + uint8 _gameOverFlag = 0; + uint8 _levelOver = 0; + uint8 _themePaused = 0; + int _level = 0; + int _titlesShown = 0; + int _time = 0; + int _promoting = 0; + int _restart = 0; + int _lastCertLen = 0; + + /* + * Input members + */ + int _pressedAction; + int _heldAction; + int _pressedDirection; + int _heldDirection; /* * Asset related members @@ -296,6 +316,9 @@ class ImmortalEngine : public Engine { * [Logic.cpp] Functions from Logic.GS */ + // Surface level + bool trapKeys(); // Poorly named, this checks if the player wants to restart the game + // Misc void logicInit(); void logic(); // Keeps time, handles win and lose conditions, then general logic @@ -369,9 +392,9 @@ class ImmortalEngine : public Engine { bool hasFeature(EngineFeature f) const override { return - (f == kSupportsLoadingDuringRuntime) || - (f == kSupportsSavingDuringRuntime) || - (f == kSupportsReturnToLauncher); + (f == kSupportsLoadingDuringRuntime) || + (f == kSupportsSavingDuringRuntime) || + (f == kSupportsReturnToLauncher); }; bool canLoadGameStateCurrently() override { diff --git a/engines/immortal/kernal.cpp b/engines/immortal/kernal.cpp index 79a8dfc84609..043d7065858b 100644 --- a/engines/immortal/kernal.cpp +++ b/engines/immortal/kernal.cpp @@ -40,44 +40,44 @@ namespace Immortal { void ImmortalEngine::drawUniv() { - // drawBackground() = draw floor parts of leftmask rightmask and maskers - // addRows() = add rows to drawitem array - // addSprites() = add all active sprites that are in the viewport, into a list that will be sorted by priority - // sortDrawItems() = sort said items - // drawItems() = draw the items over the background + // drawBackground() = draw floor parts of leftmask rightmask and maskers + // addRows() = add rows to drawitem array + // addSprites() = add all active sprites that are in the viewport, into a list that will be sorted by priority + // sortDrawItems() = sort said items + // drawItems() = draw the items over the background - // To start constructing the screem, we start with the frame as the base - memcpy(_screenBuff, _window, kScreenSize); + // To start constructing the screem, we start with the frame as the base + memcpy(_screenBuff, _window, kScreenSize); - /* copyRectToSurface will apply the screenbuffer to the ScummVM surface. - * We want to do 320 bytes per scanline, at location (0,0), with a - * size of 320x200. - */ - _mainSurface->copyRectToSurface(_screenBuff, kResH, 0, 0, kResH, kResV); + /* copyRectToSurface will apply the screenbuffer to the ScummVM surface. + * We want to do 320 bytes per scanline, at location (0,0), with a + * size of 320x200. + */ + _mainSurface->copyRectToSurface(_screenBuff, kResH, 0, 0, kResH, kResV); } void ImmortalEngine::copyToScreen() { - if (_draw == 1) { - g_system->copyRectToScreen((byte *)_mainSurface->getPixels(), kResH, 0, 0, kResH, kResV); - g_system->updateScreen(); - } + if (_draw == 1) { + g_system->copyRectToScreen((byte *)_mainSurface->getPixels(), kResH, 0, 0, kResH, kResV); + g_system->updateScreen(); + } } void ImmortalEngine::clearScreen() { - //fill the visible screen with black pixels by drawing a rectangle + //fill the visible screen with black pixels by drawing a rectangle - //rect(32, 20, 256, 128, 0) - - if ((_dontResetColors & kMaskLow) == 0) { - useNormal(); - } + //rect(32, 20, 256, 128, 0) + + if ((_dontResetColors & kMaskLow) == 0) { + useNormal(); + } } void ImmortalEngine::whiteScreen() { - //fill the visible screen with black pixels by drawing a rectangle + //fill the visible screen with black pixels by drawing a rectangle - //rect(32, 20, 256, 128, 13) + //rect(32, 20, 256, 128, 13) } void ImmortalEngine::mungeBM() {} @@ -96,195 +96,195 @@ void ImmortalEngine::scroll() {} */ void ImmortalEngine::addSprite(uint16 x, uint16 y, SpriteName n, int frame, uint16 p) { - if (_numSprites != kMaxSprites) { - if (x >= (kScreenW + kMaxSpriteLeft)) { - x |= kMaskHigh; // Make it negative - } - _sprites[_numSprites]._X = (x << 1) + _viewPortX; - - if (y >= (kMaxSpriteAbove + kScreenH)) { - y |= kMaskHigh; - } - _sprites[_numSprites]._Y = (y << 1) + _viewPortY; - - if (p >= 0x80) { - p |= kMaskHigh; - } - _sprites[_numSprites]._priority = ((p + y) ^ 0xFFFF) + 1; - - _sprites[_numSprites]._frame = frame; - _sprites[_numSprites]._dSprite = &_dataSprites[n]; - _sprites[_numSprites]._on = 1; - _numSprites += 1; - - } else { - debug("Max sprites reached beeeeeep!!"); - } + if (_numSprites != kMaxSprites) { + if (x >= (kScreenW + kMaxSpriteLeft)) { + x |= kMaskHigh; // Make it negative + } + _sprites[_numSprites]._X = (x << 1) + _viewPortX; + + if (y >= (kMaxSpriteAbove + kScreenH)) { + y |= kMaskHigh; + } + _sprites[_numSprites]._Y = (y << 1) + _viewPortY; + + if (p >= 0x80) { + p |= kMaskHigh; + } + _sprites[_numSprites]._priority = ((p + y) ^ 0xFFFF) + 1; + + _sprites[_numSprites]._frame = frame; + _sprites[_numSprites]._dSprite = &_dataSprites[n]; + _sprites[_numSprites]._on = 1; + _numSprites += 1; + + } else { + debug("Max sprites reached beeeeeep!!"); + } } void ImmortalEngine::clearSprites() { - // Just sets the 'active' flag on all possible sprites to 0 - for (int i = 0; i < kMaxSprites; i++) { - _sprites[i]._on = 0; - } + // Just sets the 'active' flag on all possible sprites to 0 + for (int i = 0; i < kMaxSprites; i++) { + _sprites[i]._on = 0; + } } void ImmortalEngine::loadSprites() { - /* This is a bit weird, so I'll explain. - * In the source, this routine loads the files onto the heap, and then - * goes through a table of sprites in the form file_index, sprite_num, center_x, center_y. - * It uses file_index to get a pointer to the start of the file on the heap, - * which it then uses to set the center x/y variables in the file itself. - * ie. file_pointer[file_index]+((sprite_num<<3)+4) = center_x. - * We aren't going to have the sprite properties inside the file data, so instead - * we have an array of all game sprites _dataSprites which is indexed - * soley by a sprite number now. This also means that a sprite itself has a reference to - * a datasprite, instead of the sprite index and separate the file pointer. Datasprite - * is what needs the file, so that's where the pointer is. The index isn't used by - * the sprite or datasprite themselves, so it isn't a member of either of them. - */ - - Common::String spriteNames[] = {"MORESPRITES.SPR", "NORLAC.SPR", "POWWOW.SPR", "TURRETS.SPR", - "WORM.SPR", "IANSPRITES.SPR", "LAST.SPR", "DOORSPRITES.SPR", - "GENSPRITES.SPR", "DRAGON.SPR", "MORDAMIR.SPR", "FLAMES.SPR", - "ROPE.SPR", "RESCUE.SPR", "TROLL.SPR", "GOBLIN.SPR", "ULINDOR.SPR", - "SPIDER.SPR", "DRAG.SPR"}; - - Common::SeekableReadStream *files[19]; - - // Number of sprites in each file - int spriteNum[] = {10, 5, 7, 10, 4, 6, 3, 10, 5, 3, 2, 1, 3, 2, 9, 10, 9, 10, 9}; - - // Pairs of (x,y) for each sprite - // Should probably have made this a 2d array, oops - uint8 centerXY[] = {16,56, 16,32, 27,39, 16,16, 32,16, 34,83, 28,37, 8,12, 8,19, 24,37, - /* Norlac */ 46,18, 40,0, 8,13, 32,48, 32,40, - /* Powwow */ 53,43, 28,37, 27,37, 26,30, 26,30, 26,29, 28,25, - /* Turrets */ 34,42, 28,37, 24,32, 32,56, 26,56, 8,48, 8,32, 8,14, 8,24, 32,44, - /* Worm */ 20,65, 25,46, 9,56, 20,53, - /* Iansprites */ 24,50, 32,52, 32,53, 32,52, 40,16, 40,16, - /* Last */ 32,56, 24,32, 24,36, - /* Doorsprites */ 0,64, 4,49, 18,49, 18,56, 24,32, 24,16, 24,56, 24,32, 24,32, 36,32, - /* Gensprites */ 16,44, 16,28, 32,24, 34,45, 20,28, - /* Dragon */ 24,93, 32,48, 0,64, - /* Mordamir */ 104,104, 30,30, - /* Flames */ 64,0, - /* Rope */ 0,80, 32,52, 32,40, - /* Rescue */ 0,112, 0,112, - /* Troll */ 28,38, 28,37, 28,37, 31,38, 28,37, 25,39, 28,37, 28,37, 28,37, - /* Goblin */ 28,38, 30,38, 26,37, 30,38, 26,37, 26,37, 26,37, 26,37, 26,36, 44,32, - /* Ulindor */ 42,42, 42,42, 42,42, 42,42, 42,42, 42,42, 42,42, 42,42, 42,42, - /* Spider */ 64,44, 64,44, 64,44, 64,44, 64,44, 64,44, 64,44, 64,44, 64,44, 64,44, - /* Drag */ 19,36, 19,36, 19,36, 19,36, 19,36, 19,36, 19,36, 19,36, 19,36}; - - // Load all sprite files - for (int i = 0; i < 19; i++) { - files[i] = loadIFF(spriteNames[i]); - } - - // s = current sprite index, f = current file index, n = current number of sprites for this file - int s = 0; - for (int f = 0; f < 19; f++) { - for (int n = 0; n < (spriteNum[f] * 2); n += 2, s++) { - DataSprite d; - _dataSprites[s] = d; - setSpriteCenter(files[f], s, centerXY[s * 2], centerXY[(s * 2) + 1]); - } - } + /* This is a bit weird, so I'll explain. + * In the source, this routine loads the files onto the heap, and then + * goes through a table of sprites in the form file_index, sprite_num, center_x, center_y. + * It uses file_index to get a pointer to the start of the file on the heap, + * which it then uses to set the center x/y variables in the file itself. + * ie. file_pointer[file_index]+((sprite_num<<3)+4) = center_x. + * We aren't going to have the sprite properties inside the file data, so instead + * we have an array of all game sprites _dataSprites which is indexed + * soley by a sprite number now. This also means that a sprite itself has a reference to + * a datasprite, instead of the sprite index and separate the file pointer. Datasprite + * is what needs the file, so that's where the pointer is. The index isn't used by + * the sprite or datasprite themselves, so it isn't a member of either of them. + */ + + Common::String spriteNames[] = {"MORESPRITES.SPR", "NORLAC.SPR", "POWWOW.SPR", "TURRETS.SPR", + "WORM.SPR", "IANSPRITES.SPR", "LAST.SPR", "DOORSPRITES.SPR", + "GENSPRITES.SPR", "DRAGON.SPR", "MORDAMIR.SPR", "FLAMES.SPR", + "ROPE.SPR", "RESCUE.SPR", "TROLL.SPR", "GOBLIN.SPR", "ULINDOR.SPR", + "SPIDER.SPR", "DRAG.SPR"}; + + Common::SeekableReadStream *files[19]; + + // Number of sprites in each file + int spriteNum[] = {10, 5, 7, 10, 4, 6, 3, 10, 5, 3, 2, 1, 3, 2, 9, 10, 9, 10, 9}; + + // Pairs of (x,y) for each sprite + // Should probably have made this a 2d array, oops + uint8 centerXY[] = {16,56, 16,32, 27,39, 16,16, 32,16, 34,83, 28,37, 8,12, 8,19, 24,37, + /* Norlac */ 46,18, 40,0, 8,13, 32,48, 32,40, + /* Powwow */ 53,43, 28,37, 27,37, 26,30, 26,30, 26,29, 28,25, + /* Turrets */ 34,42, 28,37, 24,32, 32,56, 26,56, 8,48, 8,32, 8,14, 8,24, 32,44, + /* Worm */ 20,65, 25,46, 9,56, 20,53, + /* Iansprites */ 24,50, 32,52, 32,53, 32,52, 40,16, 40,16, + /* Last */ 32,56, 24,32, 24,36, + /* Doorsprites */ 0,64, 4,49, 18,49, 18,56, 24,32, 24,16, 24,56, 24,32, 24,32, 36,32, + /* Gensprites */ 16,44, 16,28, 32,24, 34,45, 20,28, + /* Dragon */ 24,93, 32,48, 0,64, + /* Mordamir */ 104,104, 30,30, + /* Flames */ 64,0, + /* Rope */ 0,80, 32,52, 32,40, + /* Rescue */ 0,112, 0,112, + /* Troll */ 28,38, 28,37, 28,37, 31,38, 28,37, 25,39, 28,37, 28,37, 28,37, + /* Goblin */ 28,38, 30,38, 26,37, 30,38, 26,37, 26,37, 26,37, 26,37, 26,36, 44,32, + /* Ulindor */ 42,42, 42,42, 42,42, 42,42, 42,42, 42,42, 42,42, 42,42, 42,42, + /* Spider */ 64,44, 64,44, 64,44, 64,44, 64,44, 64,44, 64,44, 64,44, 64,44, 64,44, + /* Drag */ 19,36, 19,36, 19,36, 19,36, 19,36, 19,36, 19,36, 19,36, 19,36}; + + // Load all sprite files + for (int i = 0; i < 19; i++) { + files[i] = loadIFF(spriteNames[i]); + } + + // s = current sprite index, f = current file index, n = current number of sprites for this file + int s = 0; + for (int f = 0; f < 19; f++) { + for (int n = 0; n < (spriteNum[f] * 2); n += 2, s++) { + DataSprite d; + _dataSprites[s] = d; + setSpriteCenter(files[f], s, centerXY[s * 2], centerXY[(s * 2) + 1]); + } + } } void ImmortalEngine::loadWindow() { - // Initialize the window bitmap - Common::File f; - _window = new byte[kScreenSize]; - - if (f.open("WINDOWS.BM")) { - - /* The byte buffer for the screen (_screenBuff) has one byte for - * every pixel, with the resolution of the game being 320x200. - * For a bitmap like the window frame, all we need to do is - * extract the pixel out of each nyble (half byte) of the data, - * by looping over it one row at a time. - */ - - byte pixel; - int pos; - for (int y = 0; y < kResV; y++) { - for (int x = 0; x < kResH; x += 2) { - pos = (y * kResH) + x; - pixel = f.readByte(); - _window[pos] = (pixel & kMask8High) >> 4; - _window[pos + 1] = pixel & kMask8Low; - } - } - - // Now that the bitmap is processed and stored in a byte buffer, we can close the file - f.close(); - - } else { - // Should probably give an error or something here - debug("oh nose :("); - } + // Initialize the window bitmap + Common::File f; + _window = new byte[kScreenSize]; + + if (f.open("WINDOWS.BM")) { + + /* The byte buffer for the screen (_screenBuff) has one byte for + * every pixel, with the resolution of the game being 320x200. + * For a bitmap like the window frame, all we need to do is + * extract the pixel out of each nyble (half byte) of the data, + * by looping over it one row at a time. + */ + + byte pixel; + int pos; + for (int y = 0; y < kResV; y++) { + for (int x = 0; x < kResH; x += 2) { + pos = (y * kResH) + x; + pixel = f.readByte(); + _window[pos] = (pixel & kMask8High) >> 4; + _window[pos + 1] = pixel & kMask8Low; + } + } + + // Now that the bitmap is processed and stored in a byte buffer, we can close the file + f.close(); + + } else { + // Should probably give an error or something here + debug("oh nose :("); + } } void ImmortalEngine::loadFont() { - // Initialize the font data sprite - Common::SeekableReadStream *f = loadIFF("FONT.SPR"); + // Initialize the font data sprite + Common::SeekableReadStream *f = loadIFF("FONT.SPR"); - DataSprite d; - _dataSprites[kFont] = d; + DataSprite d; + _dataSprites[kFont] = d; - if (f) { - setSpriteCenter(f, kFont, 16, 0); - } else { - debug("oh nose :("); - } + if (f) { + setSpriteCenter(f, kFont, 16, 0); + } else { + debug("oh nose :("); + } } Common::SeekableReadStream *ImmortalEngine::loadIFF(Common::String fileName) { - Common::File f; - if (!f.open(fileName)) { - debug("*surprised pikachu face*"); - return nullptr; - } - - /* This isn't the most efficient way to do this (could just read a 32bit uint and compare), - * but this makes it more obvious what the source was doing. We want to know if the 4 bytes - * at file[8] are 'C' 'M' 'P' '0', so this grabs just the ascii bits of those 4 bytes, - * allowing us to directly compare it with 'CMP0'. - */ - char compSig[] = "CMP0"; - char sig[] = "0000"; - - f.seek(8); - - for (int i = 0; i < 4; i++) { - sig[i] = f.readByte() & kMaskASCII; - } - - if (strcmp(sig, compSig) == 0) { - debug("compressed"); - - /* The size of the compressed data is stored in the header, but doesn't - * account for the FORM part?? Also, **technically** this is a uint32LE, - * but the engine itself actually /doesn't/ use it like that. It only - * decrements the first word (although it compares against the second half, - * as if it is expecting that to be zero? It's a little bizarre). - */ - f.seek(6); - int len = f.readUint16LE() - 4; - - // Compressed files have a 12 byte header before the data - f.seek(12); - return unCompress(&f, len); - } - - byte *out = (byte *)malloc(f.size()); - f.read(out, f.size()); - return new Common::MemoryReadStream(out, f.size(), DisposeAfterUse::YES); + Common::File f; + if (!f.open(fileName)) { + debug("*surprised pikachu face*"); + return nullptr; + } + + /* This isn't the most efficient way to do this (could just read a 32bit uint and compare), + * but this makes it more obvious what the source was doing. We want to know if the 4 bytes + * at file[8] are 'C' 'M' 'P' '0', so this grabs just the ascii bits of those 4 bytes, + * allowing us to directly compare it with 'CMP0'. + */ + char compSig[] = "CMP0"; + char sig[] = "0000"; + + f.seek(8); + + for (int i = 0; i < 4; i++) { + sig[i] = f.readByte() & kMaskASCII; + } + + if (strcmp(sig, compSig) == 0) { + debug("compressed"); + + /* The size of the compressed data is stored in the header, but doesn't + * account for the FORM part?? Also, **technically** this is a uint32LE, + * but the engine itself actually /doesn't/ use it like that. It only + * decrements the first word (although it compares against the second half, + * as if it is expecting that to be zero? It's a little bizarre). + */ + f.seek(6); + int len = f.readUint16LE() - 4; + + // Compressed files have a 12 byte header before the data + f.seek(12); + return unCompress(&f, len); + } + + byte *out = (byte *)malloc(f.size()); + f.read(out, f.size()); + return new Common::MemoryReadStream(out, f.size(), DisposeAfterUse::YES); } @@ -312,167 +312,167 @@ Common::SeekableReadStream *ImmortalEngine::loadIFF(Common::String fileName) { */ void ImmortalEngine::loadPalette() { - // The palettes are stored at a particular location in the disk, this just grabs them - Common::File d; - d.open("IMMORTAL.dsk"); - - d.seek(kPaletteOffset); - d.read(_palDefault, 32); - d.read(_palWhite, 32); - d.read(_palBlack, 32); - d.read(_palDim, 32); - - d.close(); + // The palettes are stored at a particular location in the disk, this just grabs them + Common::File d; + d.open("IMMORTAL.dsk"); + + d.seek(kPaletteOffset); + d.read(_palDefault, 32); + d.read(_palWhite, 32); + d.read(_palBlack, 32); + d.read(_palDim, 32); + + d.close(); } void ImmortalEngine::setColors(uint16 pal[]) { - // The RGB palette is 3 bytes per entry, and each byte is a colour - for (int i = 0; i < 16; i++) { - - // The palette gets masked so it can update only specific indexes and uses FFFF to do so. However the check is simply for a negative - if (pal[i] < kMaskNeg) { - - // Green is already the correct size, being the second nyble (00G0) - // Red is in the first nyble of the high byte, so it needs to move right by 4 bits (0R00 -> 00R0) - // Blue is the first nyble of the first byte, so it needs to move left by 4 bits (000B -> 00B0) - // We also need to repeat the bits so that the colour is the same proportion of 255 as it is 15 - _palRGB[(i * 3)] = ((pal[i] & kMaskRed) >> 4) | ((pal[i] & kMaskRed) >> 8); - _palRGB[(i * 3) + 1] = (pal[i] & kMaskGreen) | ((pal[i] & kMaskGreen) >> 4) ; - _palRGB[(i * 3) + 2] = (pal[i] & kMaskBlue) | ((pal[i] & kMaskBlue) << 4); - } - } - // Palette index to update first is 0, and there are 16 colours to update - g_system->getPaletteManager()->setPalette(_palRGB, 0, 16); - g_system->updateScreen(); + // The RGB palette is 3 bytes per entry, and each byte is a colour + for (int i = 0; i < 16; i++) { + + // The palette gets masked so it can update only specific indexes and uses FFFF to do so. However the check is simply for a negative + if (pal[i] < kMaskNeg) { + + // Green is already the correct size, being the second nyble (00G0) + // Red is in the first nyble of the high byte, so it needs to move right by 4 bits (0R00 -> 00R0) + // Blue is the first nyble of the first byte, so it needs to move left by 4 bits (000B -> 00B0) + // We also need to repeat the bits so that the colour is the same proportion of 255 as it is 15 + _palRGB[(i * 3)] = ((pal[i] & kMaskRed) >> 4) | ((pal[i] & kMaskRed) >> 8); + _palRGB[(i * 3) + 1] = (pal[i] & kMaskGreen) | ((pal[i] & kMaskGreen) >> 4) ; + _palRGB[(i * 3) + 2] = (pal[i] & kMaskBlue) | ((pal[i] & kMaskBlue) << 4); + } + } + // Palette index to update first is 0, and there are 16 colours to update + g_system->getPaletteManager()->setPalette(_palRGB, 0, 16); + g_system->updateScreen(); } void ImmortalEngine::fixColors() { - // Pretty silly that this is done with two separate variables, could just index by one... - if (_dim == true) { - if (_usingNormal == true) { - useDim(); - } - } else { - if (_usingNormal == false) { - useNormal(); - } - } + // Pretty silly that this is done with two separate variables, could just index by one... + if (_dim == true) { + if (_usingNormal == true) { + useDim(); + } + } else { + if (_usingNormal == false) { + useNormal(); + } + } } void ImmortalEngine::pump() { - // Flashes the screen (except the frame thankfully) white, black, white, black, then clears the screen and goes back to normal - useWhite(); - g_system->updateScreen(); - delay(2); - useBlack(); - g_system->updateScreen(); - delay(2); - useWhite(); - g_system->updateScreen(); - delay(2); - useBlack(); - g_system->updateScreen(); - clearScreen(); - // Why does it do this instead of setting _dontResetColors for clearScreen() instead? - useNormal(); + // Flashes the screen (except the frame thankfully) white, black, white, black, then clears the screen and goes back to normal + useWhite(); + g_system->updateScreen(); + delay(2); + useBlack(); + g_system->updateScreen(); + delay(2); + useWhite(); + g_system->updateScreen(); + delay(2); + useBlack(); + g_system->updateScreen(); + clearScreen(); + // Why does it do this instead of setting _dontResetColors for clearScreen() instead? + useNormal(); } void ImmortalEngine::fadePal(uint16 pal[], int count, uint16 target[]) { - /* This will fade the palette used by everything inside the game screen - * but will not touch the window frame palette. It essentially takes the - * color value nyble, multiplies it by a multiplier, then takes the whole - * number result and inserts it into the word at the palette index of the - * temporary palette. This could I'm sure be done with regular multiplication - * and division operators, but in case the bits that get dropped are otherwise - * kept, this is a direct translation of the bit manipulation sequence. - */ - int maskPal[16] = {0xFFFF, 0x0000, 0x0000, 0x0000, - 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, - 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, - 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF}; - - uint16 result; - uint16 temp; - - for (int i = 15; i >= 0; i--) { - result = maskPal[i]; - if (result == 0) { - result = pal[i]; - if (result != 0xFFFF) { - // Blue = 0RGB -> 000B -> 0BBB -> BB0B -> 000B - result = (xba(mult16((result & kMaskFirst), count))) & kMaskFirst; - - // Green = 0RGB -> 00RG -> 000G -> 0GGG -> GG0G -> 000G -> 00G0 -> 00GB - temp = mult16(((pal[i] >> 4) & kMaskFirst), count); - temp = (xba(temp) & kMaskFirst) << 4; - result = temp | result; - - // Red = 0RGB -> GB0R -> 000R -> 0RRR -> RR0R -> 000R -> 0R00 -> 0RGB - temp = xba(pal[i]) & kMaskFirst; - temp = xba(mult16(temp, count)); - temp = xba(temp & kMaskFirst); - result = temp | result; - } - } - target[i] = result; - } + /* This will fade the palette used by everything inside the game screen + * but will not touch the window frame palette. It essentially takes the + * color value nyble, multiplies it by a multiplier, then takes the whole + * number result and inserts it into the word at the palette index of the + * temporary palette. This could I'm sure be done with regular multiplication + * and division operators, but in case the bits that get dropped are otherwise + * kept, this is a direct translation of the bit manipulation sequence. + */ + int maskPal[16] = {0xFFFF, 0x0000, 0x0000, 0x0000, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF}; + + uint16 result; + uint16 temp; + + for (int i = 15; i >= 0; i--) { + result = maskPal[i]; + if (result == 0) { + result = pal[i]; + if (result != 0xFFFF) { + // Blue = 0RGB -> 000B -> 0BBB -> BB0B -> 000B + result = (xba(mult16((result & kMaskFirst), count))) & kMaskFirst; + + // Green = 0RGB -> 00RG -> 000G -> 0GGG -> GG0G -> 000G -> 00G0 -> 00GB + temp = mult16(((pal[i] >> 4) & kMaskFirst), count); + temp = (xba(temp) & kMaskFirst) << 4; + result = temp | result; + + // Red = 0RGB -> GB0R -> 000R -> 0RRR -> RR0R -> 000R -> 0R00 -> 0RGB + temp = xba(pal[i]) & kMaskFirst; + temp = xba(mult16(temp, count)); + temp = xba(temp & kMaskFirst); + result = temp | result; + } + } + target[i] = result; + } } void ImmortalEngine::fade(uint16 pal[], int dir, int delay) { - // This temp palette will have FFFF in it, which will be understood as masks by setColors() - uint16 target[16]; - uint16 count; + // This temp palette will have FFFF in it, which will be understood as masks by setColors() + uint16 target[16]; + uint16 count; - // Originally used a branch, but this is functionally identical and much cleaner - count = dir * 256; + // Originally used a branch, but this is functionally identical and much cleaner + count = dir * 256; - while ((count >= 0) && (count <= 256)) { - fadePal(pal, count, target); - delay8(delay); - setColors(target); + while ((count >= 0) && (count <= 256)) { + fadePal(pal, count, target); + delay8(delay); + setColors(target); - // Same as above, it was originally a branch, this does the same thing - count += (dir == 0) ? 16 : -16; - } + // Same as above, it was originally a branch, this does the same thing + count += (dir == 0) ? 16 : -16; + } } // These two can probably be removed and instead use an enum to declare fadeout/in void ImmortalEngine::fadeOut(int j) { - fade(_palDefault, 1, j); + fade(_palDefault, 1, j); } void ImmortalEngine::normalFadeOut() { - fadeOut(15); + fadeOut(15); } void ImmortalEngine::slowFadeOut() { - fadeOut(28); + fadeOut(28); } void ImmortalEngine::fadeIn(int j) { - fade(_palDefault, 0, j); + fade(_palDefault, 0, j); } void ImmortalEngine::normalFadeIn() { - fadeIn(15); + fadeIn(15); } // These two can probably be removed since the extra call in C doesn't have the setup needed in ASM void ImmortalEngine::useBlack() { - setColors(_palBlack); + setColors(_palBlack); } void ImmortalEngine::useWhite() { - setColors(_palBlack); + setColors(_palBlack); } void ImmortalEngine::useNormal() { - setColors(_palDefault); - _usingNormal = true; + setColors(_palDefault); + _usingNormal = true; } void ImmortalEngine::useDim() { - setColors(_palDim); - _usingNormal = false; + setColors(_palDim); + _usingNormal = false; } @@ -503,7 +503,7 @@ void ImmortalEngine::clearKeyBuff() {} */ void ImmortalEngine::loadSingles(Common::String songName) { - debug("%s", songName.c_str()); + debug("%s", songName.c_str()); } diff --git a/engines/immortal/logic.cpp b/engines/immortal/logic.cpp index 750e59a399be..c7061c8b5292 100644 --- a/engines/immortal/logic.cpp +++ b/engines/immortal/logic.cpp @@ -23,23 +23,36 @@ namespace Immortal { +bool ImmortalEngine::trapKeys() { + // This weirdly named routine just checks if you want to restart the game. On the NES it pulls up a dialog with a yes/no, + // But on the Apple IIGS it's just the R key + getInput(); + if (_pressedAction == kActionRestart) { + gameOver(); + return true; + } else if (_pressedAction == kActionSound) { + //toggleSound(); + } + return false; +} + // There's no way this routine needs to still be here. In fact I'm not sure it needed to be in the game anyway? int ImmortalEngine::getLevel() { - return _level; + return _level; } void ImmortalEngine::logicInit() { - _titlesShown = 0; - _time = 0; - _promoting = 0; - _restart = 1; - //level_initAtStartOfGameOnly - _lastCertLen = 0; + _titlesShown = 0; + _time = 0; + _promoting = 0; + _restart = 1; + //level_initAtStartOfGameOnly + _lastCertLen = 0; } void ImmortalEngine::logic() { - _time += 1; - // if time overflows the counter, inc the high byte? What the heck... + _time += 1; + // if time overflows the counter, inc the high byte? What the heck... } @@ -47,22 +60,41 @@ void ImmortalEngine::restartLogic() { } int ImmortalEngine::logicFreeze() { - // Very silly way of checking if the level is over and/or the game is over - int g = _gameOverFlag | _levelOver; - return (g ^ 1) >> 1; + // Very silly way of checking if the level is over and/or the game is over + int g = _gameOverFlag | _levelOver; + return (g ^ 1) >> 1; } void ImmortalEngine::gameOverDisplay() { - _themePaused |= 2; - //text_print(kGameOverString) + _themePaused |= 2; + //text_print(kGameOverString) } void ImmortalEngine::gameOver() { - _gameOverFlag = 1; + _gameOverFlag = 1; } void ImmortalEngine::levelOver() { - _levelOver = 1; + _levelOver = 1; } -} // namespace Immortal \ No newline at end of file +} // namespace Immortal + + + + + + + + + + + + + + + + + + + diff --git a/engines/immortal/metaengine.cpp b/engines/immortal/metaengine.cpp index b736f5f80424..1448f05a6631 100644 --- a/engines/immortal/metaengine.cpp +++ b/engines/immortal/metaengine.cpp @@ -33,15 +33,15 @@ Common::Error ImmortalMetaEngine::createInstance(OSystem *syst, Engine **engine, } bool ImmortalMetaEngine::hasFeature(MetaEngineFeature f) const { - return false; + return false; /* return (f == kSavesUseExtendedFormat) || (f == kSimpleSavesNames) || - (f == kSupportsListSaves) || - (f == kSupportsDeleteSave) || - (f == kSavesSupportMetaInfo) || - (f == kSavesSupportThumbnail) || - (f == kSupportsLoadingDuringStartup); */ + (f == kSupportsListSaves) || + (f == kSupportsDeleteSave) || + (f == kSavesSupportMetaInfo) || + (f == kSavesSupportThumbnail) || + (f == kSupportsLoadingDuringStartup); */ } #if PLUGIN_ENABLED_DYNAMIC(IMMORTAL) diff --git a/engines/immortal/misc.cpp b/engines/immortal/misc.cpp index 3457ccb0a3ef..f55680f21fad 100644 --- a/engines/immortal/misc.cpp +++ b/engines/immortal/misc.cpp @@ -32,15 +32,15 @@ namespace Immortal { */ void ImmortalEngine::delay(int j) { // Delay is measured in jiffies, which are 56.17ms - g_system->delayMillis(j * 56); + g_system->delayMillis(j * 56); } void ImmortalEngine::delay4(int j) { // Named in source quarterClock for some reason, 1/4 jiffies are 14.04ms - g_system->delayMillis(j * 14); + g_system->delayMillis(j * 14); } void ImmortalEngine::delay8(int j) { // 1/8 jiffies are 7.02ms - g_system->delayMillis(j * 7); + g_system->delayMillis(j * 7); } void ImmortalEngine::miscInit() {} diff --git a/engines/immortal/sprite_list.h b/engines/immortal/sprite_list.h index a385db5bd17f..656e8a12e34e 100644 --- a/engines/immortal/sprite_list.h +++ b/engines/immortal/sprite_list.h @@ -25,164 +25,164 @@ namespace Immortal { enum SpriteName { - // Moresprites 10 - kCandle, - kWow, - kAnaVanish, - kSink, - kTrapdoor, - kWizPhant, - kVanish, - kShadow, - kSlime, - kSlimeDeath, - - // Norlac 5 - kBridge, - kVortex, - kBubble, - kNorlac, - kNolac2, - - // Powwow 7 - kPlanners, - kUgh, - kIsDevoured, - kIsBadCrawl, - kIsGoodCrawl, - kLeg, - kIsWebbed, - - // Turrets 10 - kSleep, - kShrink, - kLocksmith, - kAnaGlimpse, - kMadKing, - kTorch, - kPipe, - kProjectile, - kKnife, - kAnaHug, - - // Worm 4 - kWorm0, - kWorm1, - kSpike, - kIsSpiked, - - // Iansprites 6 - kMurder, - kWizCrawlUp, - kWizLight, - kWizBattle, - kDown, - kNorlacDown, - - // Lastsprites 3 - kWaterLadder, - kPulledDown, - kSpill, - - // Doorsprites 10 - kDoor, - kTele, - kBomb, - kTorched, - kLadderTop, - kSecret, - kLadderBottom, - kSlipped, - kGoblinSlipped, - kFlame, - - // General 5 - kArrow, - kSpark, - kObject, - kBigBurst, - kBeam, - - // Mordamir 3 - kLight, - kMord, - kDragMask, - - // Dragon2 2 - kDFlames, - kThroat, - - // Dragon 1 - kDragon, - - // Rope 3 - kChop, - kHead, - kNurse, - - // Rescue 2 - kRescue1, - kRescue2, - - // Troll 9 - kTroll0, - kTroll1, - kTroll2, - kTroll3, - kTroll4, - kTroll5, - kTroll6, - kTroll7, - kTroll8, - - // Goblin 10 - kGoblin0, - kGoblin1, - kGoblin2, - kGoblin3, - kGoblin4, - kGoblin5, - kGoblin6, - kGoblin7, - kGoblin8, - kGoblin9, - - //Ulindor 9 - kUlindor0, - kUlindor1, - kUlindor2, - kUlindor3, - kUlindor4, - kUlindor5, - kUlindor6, - kUlindor7, - kUlindor8, - - //Spider 10 - kSpider0, - kSpider1, - kSpider2, - kSpider3, - kSpider4, - kSpider5, - kSpider6, - kSpider7, - kSpider8, - kSpider9, - - //Drag 9 - kDrag0, - kDrag1, - kDrag2, - kDrag3, - kDrag4, - kDrag5, - kDrag6, - kDrag7, - kDrag8, - - // Font - kFont + // Moresprites 10 + kCandle, + kWow, + kAnaVanish, + kSink, + kTrapdoor, + kWizPhant, + kVanish, + kShadow, + kSlime, + kSlimeDeath, + + // Norlac 5 + kBridge, + kVortex, + kBubble, + kNorlac, + kNolac2, + + // Powwow 7 + kPlanners, + kUgh, + kIsDevoured, + kIsBadCrawl, + kIsGoodCrawl, + kLeg, + kIsWebbed, + + // Turrets 10 + kSleep, + kShrink, + kLocksmith, + kAnaGlimpse, + kMadKing, + kTorch, + kPipe, + kProjectile, + kKnife, + kAnaHug, + + // Worm 4 + kWorm0, + kWorm1, + kSpike, + kIsSpiked, + + // Iansprites 6 + kMurder, + kWizCrawlUp, + kWizLight, + kWizBattle, + kDown, + kNorlacDown, + + // Lastsprites 3 + kWaterLadder, + kPulledDown, + kSpill, + + // Doorsprites 10 + kDoor, + kTele, + kBomb, + kTorched, + kLadderTop, + kSecret, + kLadderBottom, + kSlipped, + kGoblinSlipped, + kFlame, + + // General 5 + kArrow, + kSpark, + kObject, + kBigBurst, + kBeam, + + // Mordamir 3 + kLight, + kMord, + kDragMask, + + // Dragon2 2 + kDFlames, + kThroat, + + // Dragon 1 + kDragon, + + // Rope 3 + kChop, + kHead, + kNurse, + + // Rescue 2 + kRescue1, + kRescue2, + + // Troll 9 + kTroll0, + kTroll1, + kTroll2, + kTroll3, + kTroll4, + kTroll5, + kTroll6, + kTroll7, + kTroll8, + + // Goblin 10 + kGoblin0, + kGoblin1, + kGoblin2, + kGoblin3, + kGoblin4, + kGoblin5, + kGoblin6, + kGoblin7, + kGoblin8, + kGoblin9, + + //Ulindor 9 + kUlindor0, + kUlindor1, + kUlindor2, + kUlindor3, + kUlindor4, + kUlindor5, + kUlindor6, + kUlindor7, + kUlindor8, + + //Spider 10 + kSpider0, + kSpider1, + kSpider2, + kSpider3, + kSpider4, + kSpider5, + kSpider6, + kSpider7, + kSpider8, + kSpider9, + + //Drag 9 + kDrag0, + kDrag1, + kDrag2, + kDrag3, + kDrag4, + kDrag5, + kDrag6, + kDrag7, + kDrag8, + + // Font + kFont }; } // namespace immortal diff --git a/engines/immortal/sprites.cpp b/engines/immortal/sprites.cpp index 0329cf6a420d..1bad636a6729 100644 --- a/engines/immortal/sprites.cpp +++ b/engines/immortal/sprites.cpp @@ -32,10 +32,10 @@ namespace Immortal { */ void ImmortalEngine::setSpriteCenter(Common::SeekableReadStream *f, int num, uint8 cenX, uint8 cenY) { - // Very simple, just initialize what we can of the data sprite - _dataSprites[num]._cenX = cenX; - _dataSprites[num]._cenY = cenY; - _dataSprites[num]._file = f; + // Very simple, just initialize what we can of the data sprite + _dataSprites[num]._cenX = cenX; + _dataSprites[num]._cenY = cenY; + _dataSprites[num]._file = f; } From 0310509fa1f3612a6e726789451866a5515d7795 Mon Sep 17 00:00:00 2001 From: Quote58 Date: Fri, 29 Jul 2022 05:37:12 -0400 Subject: [PATCH 307/412] IMMORTAL: Minor formatting in disk.h --- engines/immortal/disk.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/engines/immortal/disk.h b/engines/immortal/disk.h index 030fbb00f88e..2d581c969c4a 100644 --- a/engines/immortal/disk.h +++ b/engines/immortal/disk.h @@ -83,7 +83,7 @@ enum FileExt { class ProDOSFile : public Common::ArchiveMember { public: ProDOSFile(char name[16], uint8 type, uint16 tBlk, uint32 eof, uint16 bPtr, Common::File *disk); - ~ProDOSFile() {}; + ~ProDOSFile() {}; // File does not need a destructor, because the file it reads from is a pointer to Disk, and Disk has a destructor // -- These are the Common::ArchiveMember related functions -- Common::String getName() const override; // Returns _name @@ -95,12 +95,12 @@ class ProDOSFile : public Common::ArchiveMember { void printInfo(); private: - char _name[16]; + char _name[16]; uint8 _type; // As defined by enum FileType uint16 _blockPtr; // Block index in volume of index block or data uint16 _totalBlocks; uint32 _eof; // End Of File, used generally as size (exception being sparse files) - Common::File *_disk; // This is a pointer because it is the same _disk as in ProDosDisk, passed to the file object +Common::File *_disk; // This is a pointer because it is the same _disk as in ProDosDisk, passed to the file object }; /* This class defines the entire disk volume. Upon using the open() method, From 032377fe775a8d2f8a357f46281172def1915c9d Mon Sep 17 00:00:00 2001 From: Quote58 Date: Fri, 29 Jul 2022 05:38:15 -0400 Subject: [PATCH 308/412] IMMORTAL: Add wizard data sprite indexes --- engines/immortal/sprite_list.h | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/engines/immortal/sprite_list.h b/engines/immortal/sprite_list.h index 656e8a12e34e..2411936dcf88 100644 --- a/engines/immortal/sprite_list.h +++ b/engines/immortal/sprite_list.h @@ -124,7 +124,7 @@ enum SpriteName { kRescue1, kRescue2, - // Troll 9 + // Troll 9 (8 directions + ?) kTroll0, kTroll1, kTroll2, @@ -135,7 +135,7 @@ enum SpriteName { kTroll7, kTroll8, - // Goblin 10 + // Goblin 10 (8 directions + ?) kGoblin0, kGoblin1, kGoblin2, @@ -147,7 +147,22 @@ enum SpriteName { kGoblin8, kGoblin9, - //Ulindor 9 + // Wizard A 8 (8 directions) + kWizard0, + kWizard1, + kWizard2, + kWizard3, + kWizard4, + kWizard5, + kWizard6, + kWizard7, + + // Wizard B 3 (3 ?) + kWizard8, + kWizard9, + kWizard10, + + // Ulindor 9 (8 directions + ?) kUlindor0, kUlindor1, kUlindor2, @@ -158,7 +173,7 @@ enum SpriteName { kUlindor7, kUlindor8, - //Spider 10 + // Spider 10 (probably not directions) kSpider0, kSpider1, kSpider2, @@ -170,7 +185,7 @@ enum SpriteName { kSpider8, kSpider9, - //Drag 9 + // Drag 9 (probably not directions) kDrag0, kDrag1, kDrag2, From d475e36f7541a5c19d7019b994a861f3d24640bd Mon Sep 17 00:00:00 2001 From: Quote58 Date: Fri, 29 Jul 2022 05:39:04 -0400 Subject: [PATCH 309/412] IMMORTAL: New functions added to kernal + update to initdatasprite in sprites.cpp --- engines/immortal/immortal.h | 344 ++++++++++++++++++++++------- engines/immortal/kernal.cpp | 409 +++++++++++++++++++++++++++++++---- engines/immortal/sprites.cpp | 48 +++- 3 files changed, 671 insertions(+), 130 deletions(-) diff --git a/engines/immortal/immortal.h b/engines/immortal/immortal.h index 3c6203e9979e..fc489eacb28e 100644 --- a/engines/immortal/immortal.h +++ b/engines/immortal/immortal.h @@ -77,28 +77,90 @@ enum ColourMask : uint16 { kMaskBlue = 0x000F }; -enum InputAction : int { - kActionRestart, +enum Screen { // These are constants that are used for defining screen related arrays + kMaxRooms = 16, // Should probably put this in a different enum + kMaxSprites = 32, // Number of sprites allowed at once + kViewPortCW = 256 / 64, + kViewPortCH = 128 / kMaxSprites, + kMaxDrawItems = kViewPortCH + 1 + kMaxSprites +}; + +enum InputAction { + kActionNothing, + kActionRestart, // Key "R" <-- Debug? kActionSound, - kActionFire + kActionFire, + kActionButton, + kActionDBGStep // Debug key for moving engine forward one frame at a time }; -enum InputDirection : int { +enum InputDirection { kDirectionUp, kDirectionLeft, kDirectionDown, kDirectionRight }; +enum ObjFlag : uint8 { + kObjUsesFireButton = 0x40, + kObjIsInvisible = 0x20, + kObjIsRunning = 0x10, + kObjIsChest = 0x08, + kObjIsOnGround = 0x04, + kObjIsF1 = 0x02, + kObjIsF2 = 0x01 +}; + +enum Monster { + kPlayerID +}; + +enum Str { + kStrGold +}; + +enum CertIndex : uint8 { + kCertHits, + kCertLevel, + kCertLoGameFlags, + kCertHiGameFlags, + kCertQuickness, + kCertInvLo, + kCertInvHi, + kCertGoldLo, + kCertGoldHi +}; + +enum Song { + kSongNothing, + kSongMaze, + kSongCombat, + kSongText +}; + +enum GameFlags : uint8 { + kSavedNone = 0, + kSavedKing = 1, + kSavedAna = 2 +}; + +struct Frame { + uint16 _deltaX; + uint16 _deltaY; + uint16 _rectX; + uint16 _rectY; + byte *_bitmap; +}; + struct DataSprite { - uint8 _cenX; // These are the base center positions - uint8 _cenY; - byte *_bitmap; // Pointer to actual data -Common::SeekableReadStream *_file; // This will likely be removed later + uint16 _cenX; // These are the base center positions + uint16 _cenY; + uint16 _numFrames; +Common::Array _frames; }; struct Sprite { - int _frame; // Current frame of the cycle + int _frame; // Index of _dSprite._frames[] uint16 _X; uint16 _Y; uint16 _on; // 1 = active @@ -106,16 +168,20 @@ struct Sprite { DataSprite *_dSprite; }; -struct Cycle { -DataSprite *_dSprite; - int _numCycles; - int *_frames; +struct ObjType { + Str _str; + Str _desc; + int _size; + //_pickup; + //_use; + //_run; }; struct ImmortalGameDescription; // Forward declaration because we will need the Disk class class ProDosDisk; +class Room; class ImmortalEngine : public Engine { private: @@ -147,78 +213,154 @@ class ImmortalEngine : public Engine { /* * Constants */ - // Screen - const int kResH = 320; - const int kResV = 200; - const int kScreenW = 128; - const int kScreenH = 128; + + // Misc constants + + // Screen constants + const int kResH = 320; + const int kResV = 200; + const int kScreenW__ = 128; // ??? labeled in source as SCREENWIDTH + const int kScreenH__ = 128; // ??? + const int kViewPortW = 256; + const int kViewPortH = 128; const int kScreenSize = (kResH * kResV) * 2; // The size of the screen buffer is 320x200 - + const int kScreenLeft = 32; + const int kScreenTop = 20; + const int kTextLeft = 8; + const int kTextTop = 4; + const int kGaugeX = 0; + const int kGaugeY = -13; // ??? + const int kScreenBMW = 160; // Literally no idea yet + const int kChrW = 64; + const int kChrH = 32; + const int kChrLen = (kChrW / 2) * kChrH; + const int kChrBMW = kChrW / 2; + + uint16 _tChrMask[] = {0,0,0,0,-1,1,0,1,-1,0,0,2,0,-1,2,-2,0,-2,1}; + + uint16 _isBackground[] = {1,0,0,0,0,0,0,0, + 0,1,1,0,0,0,0,0, + 0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0}; + + // Disk offsets const int kPaletteOffset = 21205; // This is the byte position of the palette data in the disk // Sprite constants - const int kMaxCycles = 32; - const int kMaxSprites = 32; // Number of sprites allowed at once const int kMaxSpriteAbove = 48; // Maximum sprite extents from center const int kMaxSpriteBelow = 16; const int kMaxSpriteLeft = 16; const int kMaxSpriteRight = 16; - const int kWizardX = 28; // Common sprite center for some reason - const int kWizardY = 37; - + const int kMaxSpriteW = 64; + const int kMaxSpriteH = 64; + const int kSpriteDY = 32; + const int kVSX = kMaxSpriteW; + const int kVSY = kSpriteDY; + const int kVSBMW = (kViewPortW + kMaxSpriteW) / 2; + const int kVSLen = kVSBMW * (kViewPortH + kMaxSpriteH); + const int kVSDY = 32; // difference from top of screen to top of viewport in the virtual screen buffer + const int kMySuperBottom = kVSDY + kViewPortH; + const int kSuperBottom = 200; + const int kMySuperTop = kVSDY; + const int kSuperTop = 0; + const int kViewPortSpX = 32; + const int kViewPortSpY = 0; + const int kWizardX = 28; // Common sprite center for some reason + const int kWizardY = 37; + + // Asset constants + const char kGaugeOn = 1; // On uses the sprite at index 1 of the font spriteset + const char kGaugeOff = 0; // Off uses the sprite at index 0 of the font spriteset + const char kGaugeStop = 1; // Literally just means the final kGaugeOn char to draw + const char kGaugeStart = 1; // First kGaugeOn char to draw + + // General Strings + const Common::String kOldGameString = "New game?%"; + const Common::String kEnterCertificate = "Enter certificate:&-="; + const Common::String kBadCertificate = "Invalid certificate.@"; + const Common::String kCertString = "End of level!&Here is your certificate:&&="; + const Common::String kCert2String = "&@"; + const Common::String kTitle0 = " Electronic Arts presents&& The Immortal&&&&  1990 Will Harvey|]]]]]]]]]="; // Might need \ for something + const Common::String kTitle4 = " written by&& Will Harvey& Ian Gooding& Michael Marcantel& Brett G. Durrett& Douglas Fulton|]]]]]]]/="; /* * 'global' members */ + + // Misc Common::ErrorCode _err; // If this is not kNoError at any point, the engine will stop bool _draw = 0; // Whether the screen should draw this frame - bool _dim = 0; // Whether the palette is dim - bool _usingNormal = 0; // Whether the palette is using normal int _zero = 0; // No idea what this is yet - uint8 _gameOverFlag = 0; - uint8 _levelOver = 0; - uint8 _themePaused = 0; - int _level = 0; + bool _gameOverFlag = false; + uint8 _gameFlags; // Bitflag array of event flags, but only two were used (saving ana and saving the king) <-- why is gameOverFlag not in this? Lol + bool _themePaused; // In the source, this is actually considered a bit flag array of 2 bits (b0 and b1). However, it only ever checks for non-zero, so it's effectively only 1 bit. int _titlesShown = 0; int _time = 0; - int _promoting = 0; - int _restart = 0; + int _promoting = 0; // I think promoting means the title stuff + bool _restart = false; int _lastCertLen = 0; + int _cert = 0; // This will probably not be an int - /* - * Input members - */ + // Level members + int _maxLevels = 0; // This is determined when loading in story files + int _level = 0; + bool _levelOver = false; + Room *_rooms[kMaxRooms]; // Rooms within the level + + // Debug members + bool _singleStep; // Flag for _singleStep mode + + // Input members int _pressedAction; int _heldAction; int _pressedDirection; int _heldDirection; - /* - * Asset related members - */ + // Music members + Song _playing; // Currently playing song + int _themeID = 0; // Not sure yet tbh + int _combatID = 0; + + // Asset members int _numSprites = 0; // This is more accurately actually the index within the sprite array, so _numSprites + 1 is the current number of sprites DataSprite _font; // The font sprite data is loaded separate from other sprite stuff - byte *_window; // Bitmap of the window around the game - Sprite _sprites[32]; // A contiguous series of sprites (this is the same as kMaxSprites, but it can't be used for this) - Cycle _cycles[32]; // Animation cycle for each sprite slot + Sprite _sprites[kMaxSprites]; // All the sprites shown on screen DataSprite _dataSprites[kFont+1]; // All the sprite data, indexed by SpriteFile - /* - * Screen related members - */ + // Screen members + byte *_window; // Bitmap of the window around the game + byte *_screenBuff; // The final buffer that will transfer to the screen + uint16 _myCNM[(kViewPortCW+1)][(kViewPortCH+1)]; + uint16 _myModCNM[(kViewPortCW+1)][(kViewPortCH+1)]; + uint16 _myModLCNM[(kViewPortCW+1)][(kViewPortCH+1)]; + uint16 _columnX[kViewPortCW+1]; + uint16 _columnTop[kViewPortCW+1]; + uint16 _columnIndex[kViewPortCW+1]; // Why the heck is this an entire array, when it's just an index that gets zeroed before it gets used anyway... + uint16 _tIndex[kMaxDrawItems]; + uint16 _tPriority[kMaxDrawItems]; + uint16 _viewPortX; + uint16 _viewPortY; + uint16 _myViewPortX; // Probably mirror of viewportX + uint16 _myViewPortY; + int _lastGauge = 0; // Mirror for player health, used to update health gauge display + uint16 _penX = 0; // Basically where in the screen we are currently drawing + uint16 _penY = 0; + uint16 _myUnivPointX; + uint16 _myUnivPointY; + int _num2DrawItems = 0; Graphics::Surface *_mainSurface; - byte *_screenBuff; // The final buffer that will transfer to the screen - uint16 _viewPortX; - uint16 _viewPortY; - /* - * Palette related members - */ + + // Palette members + bool _dim = 0; // Whether the palette is dim uint16 _palDefault[16]; uint16 _palWhite[16]; uint16 _palBlack[16]; uint16 _palDim[16]; byte _palRGB[48]; // Palette that ScummVM actually uses, which is an RGB conversion of the original int _dontResetColors = 0; // Not sure yet + bool _usingNormal = 0; // Whether the palette is using normal /* @@ -234,6 +376,7 @@ class ImmortalEngine : public Engine { void clearScreen(); // Draws a black rectangle on the screen buffer but only inside the frame void whiteScreen(); // Draws a white rectanlge on the screen buffer (but does not do anything with resetColors) void rect(int x, int y, int w, int h); // Draws a solid rectangle at x,y with size w,h. Also shadows for blit? + void printChr(char c); void loadWindow(); // Gets the window.bm file void drawUniv(); // Draw the background, add the sprites, determine draw order, draw the sprites void copyToScreen(); // If draw is 0, just check input, otherwise also copy the screen buffer to the scummvm surface and update screen @@ -242,8 +385,24 @@ class ImmortalEngine : public Engine { void blit40(); // Uses macro blit 40 times void sBlit(); void scroll(); - - // Misc engine + void makeMyCNM(); // ? + void drawBGRND(); // Draw floor parts of leftmask rightmask and maskers + void addRows(); // Add rows to drawitem array + void addSprites(); // Add all active sprites that are in the viewport, into a list that will be sorted by priority + void sortDrawItems(); // Sort said items + void drawItems(); // Draw the items over the background + + + // Music + void toggleSound(); // Actually pauses the sound, doesn't just turn it off/mute + void fixPause(); + Song getPlaying(); + void playMazeSong(); + void playCombatSong(); + void doGroan(); + void musicPause(int sID); + void musicUnPause(int sID); + void loadSingles(Common::String songName); // Loads and then parse the maze song // Palette void loadPalette(); // Get the static palette data from the disk @@ -265,7 +424,6 @@ class ImmortalEngine : public Engine { // Assets Common::SeekableReadStream *loadIFF(Common::String fileName); // Loads a file and uncompresses if it is compressed void loadFont(); // Gets the font.spr file, and centers the sprite - void loadSingles(Common::String songName); // Loads and then parse the maze song void clearSprites(); // Clears all sprites before drawing the current frame void loadSprites(); // Loads all the sprite files and centers their sprites (in spritelist, but called from kernal) void addSprite(uint16 x, uint16 y, SpriteName n, int frame, uint16 p); @@ -274,11 +432,11 @@ class ImmortalEngine : public Engine { void userIO(); // Get input void pollKeys(); // Buffer input void noNetwork(); // Setup input mirrors - void keyTraps(); // Seems to be debug only + void waitKey(); // Waits until a key is pressed (until getInput() returns true) void blit8(); // This is actually just input, but it is called blit because it does a 'paddle blit' 8 times // These will replace the myriad of hardware input handling from the source - void getInput(); + bool getInput(); // True if there was input, false if not void addKeyBuffer(); void clearKeyBuff(); @@ -287,48 +445,44 @@ class ImmortalEngine : public Engine { * [Sprites.cpp] Functions from Sprites.GS and spriteList.GS */ - // ?? - void setSpriteCenter(Common::SeekableReadStream *f, int num, uint8 cenX, uint8 cenY); // Basically initializes the data sprite - int getNumFrames(int file, int num); - - /* - * [Cycle.cpp] Functions from Cyc - */ - - /* Unneccessary - void cycleInit(); - void cycleFree(); - void cycleGetNumFrames(); - void cycleGetList();*/ + // Init + void initDataSprite(Common::SeekableReadStream *f, DataSprite *d, int index, uint16 cenX, uint16 cenY); // Initializes the data sprite + + // Main + void superSprite(int s, uint16 x, uint16 y, Frame f, int bmw, byte *dst, int sT, int sB); - // Misc - void cycleNew(); // Adds a cycle to the current list - int getCycleChr(); - void cycleFreeAll(); // Delete all cycles - void cycleGetFile(); - void cycleGetNum(); - void cycleGetIndex(); - void cycleSetIndex(); - void cycleGetFrame(); - void cycleAdvance(); /* * [Logic.cpp] Functions from Logic.GS */ - // Surface level - bool trapKeys(); // Poorly named, this checks if the player wants to restart the game + // Debug + void doSingleStep(); // Let the user advance the engine one frame at a time - // Misc + // Main + void trapKeys(); // Poorly named, this checks if the player wants to restart/pause music/use debug step void logicInit(); void logic(); // Keeps time, handles win and lose conditions, then general logic void restartLogic(); // This is the actual logic init int logicFreeze(); // Overcomplicated way to check if game over or level over + void updateHitGauge(); + void drawGauge(int h); + bool getCertificate(); + + // Misc + bool printAnd(const Common::String s); + bool fromOldGame(); + void setGameFlags(uint16 f); + void setSavedKing(); + bool isSavedKing(); + void setSavedAna(); + bool isSavedAna(); int getLevel(); // Literally just return _level... void gameOverDisplay(); void gameOver(); void levelOver(); + /* * [Misc.cpp] Functions from Misc */ @@ -343,7 +497,7 @@ class ImmortalEngine : public Engine { void myDelay(); // Text printing - void textPrint(int num); + bool textPrint(const Common::String s); void textSub(); void textEnd(); void textMiddle(); @@ -357,7 +511,6 @@ class ImmortalEngine : public Engine { // Screen related void inside(int p, int p2, int a); void insideRect(int p, int r); - void updateHitGuage(); /* @@ -374,6 +527,31 @@ class ImmortalEngine : public Engine { void appendList(uint16 codeW, uint16 k, uint16 &hash, uint16 &findEmpty, uint16 start[], uint16 ptk[], uint16 &tmp); + /* + * [Music.cpp] Functions from Music.cpp + */ + + // Misc + + + /* + * [DrawChr.cpp] Functions from DrawChr.cpp + */ + + // Main + int mungeCBM(int numChrs); + void storeAddr(); + void mungeSolid(); + void mungeLRHC(); + void mungeLLHC(); + void mungeULHC(); + void mungeURHC(); + void drawSolid(int chr, int x, int y); + void drawULHC(int chr, int x, int y); + void drawURHC(int chr, int x, int y); + void drawLLHC(int chr, int x, int y); + void drawLRHC(int chr, int x, int y); + /* * --- ScummVM general engine Functions --- diff --git a/engines/immortal/kernal.cpp b/engines/immortal/kernal.cpp index 043d7065858b..8e5deb0d82ae 100644 --- a/engines/immortal/kernal.cpp +++ b/engines/immortal/kernal.cpp @@ -39,12 +39,21 @@ namespace Immortal { */ void ImmortalEngine::drawUniv() { + // This is where the entire screen actually comes together + _myViewPortX = _viewPortX & 0xFFFE; + _myViewPortY = _viewPortY; - // drawBackground() = draw floor parts of leftmask rightmask and maskers - // addRows() = add rows to drawitem array - // addSprites() = add all active sprites that are in the viewport, into a list that will be sorted by priority - // sortDrawItems() = sort said items - // drawItems() = draw the items over the background + _num2DrawItems = 0; + + _myUnivPointX = !(_myViewPortX & (kChrW - 1)) + kViewPortSpX; + _myUnivPointY = !(_myViewPortY & (kChrH - 1)) + kViewPortSpY; + + makeMyCNM(); + drawBGRND(); // Draw floor parts of leftmask rightmask and maskers + addRows(); // Add rows to drawitem array + addSprites(); // Add all active sprites that are in the viewport, into a list that will be sorted by priority + sortDrawItems(); // Sort said items + drawItems(); // Draw the items over the background // To start constructing the screem, we start with the frame as the base memcpy(_screenBuff, _window, kScreenSize); @@ -85,7 +94,258 @@ void ImmortalEngine::blit() {} void ImmortalEngine::blit40() {} void ImmortalEngine::sBlit() {} void ImmortalEngine::scroll() {} +void ImmortalEngine::makeMyCNM() {} // ? + +void ImmortalEngine::addRows() { + // I'm not really sure how this works yet + int i = _num2DrawItems; + _tPriority[i] = !(!(_myViewPortY & (kChrH - 1)) + _myViewPortY); + + for (int j = 0; j != kViewPortCH+4; j++, i++) { + _tIndex[i] = (j << 5) | 0x8000; + _tPriority[i] = _tPriority[i] - kChrH; + } + _num2DrawItems = i; +} + +void ImmortalEngine::addSprites() { + // My goodness this routine is gross + int tmpNum = _num2DrawItems; + for (int i = 0; i < kMaxSprites; i++) { + if (_sprites[i]._on == 1) { + if ((_sprites[i]._X & 1) != 0) { + debug("not good! BRK"); + return; + } + int tmpx = (_sprites[i]._X - kMaxSpriteW) - _myViewPortX; + if (tmpx < 0) { + if (tmpx + (kMaxSpriteW * 2) < 0) { + continue; + } + } else if (tmpx >= kViewPortW) { + continue; + } + + int tmpy = (_sprites[i]._Y - kMaxSpriteH) - _myViewPortY; + if (tmpy < 0) { + if (tmpy + (kMaxSpriteH * 2) < 0) { + continue; + } + } else if (tmpy >= kViewPortH) { + continue; + } + + DataSprite *tempD = _sprites[i]._dSprite; + Frame *tempF = &(_sprites[i]._dSprite->_frames[_sprites[i]._frame]); + int sx = ((_sprites[i]._X + tempF->_deltaX) - tempD->_cenX) - _myViewPortX; + int sy = ((_sprites[i]._Y + tempF->_deltaY) - tempD->_cenY) - _myViewPortY; + + if (sx >= 0 ) { + if (sx >= kViewPortW) { + continue; + } + } else if ((sx + tempF->_rectX) <= 0) { + continue; + } + + if (sy >= 0 ) { + if (sy >= kViewPortH) { + continue; + } + } else if ((sy + tempF->_rectY) <= 0) { + continue; + } + + // Sprite is actually in viewport, we can now enter it in the sorting array + _tIndex[_num2DrawItems] = i; + _tPriority[_num2DrawItems] = _sprites[i]._priority; + tmpNum++; + if (tmpNum == kMaxDrawItems) { + break; + } + } + } + _num2DrawItems = tmpNum; +} + +void ImmortalEngine::sortDrawItems() { + /* Just an implementation of bubble sort. + * Sorting largest to smallest entry, simply + * swapping every two entries if they are not in order. + */ + + int top = _num2DrawItems; + bool bailout; + + do { + // Assume that the list is sorted + bailout = true; + for (int i = 1; i < top; i++) { + if (_tPriority[i] > _tPriority[i-1]) { + uint16 tmp = _tPriority[i]; + _tPriority[i] = _tPriority[i-1]; + _tPriority[i-1] = tmp; + + // List was not sorted yet, therefor we need to check it again + bailout = false; + } + } + /* After every pass, the smallest entry is at the end of the array, so we move + * the end marker back by one + */ + top--; + } while (bailout == false); +} + +void ImmortalEngine::drawBGRND() { + // 'tmp' is y, 'cmp' is x + + uint16 pointX = _myUnivPointX; + uint16 pointY = _myUnivPointY; + + for (int y = kViewPortCH + 1, y2 = 0; y != 0; y--, y2++) { + for (int x = 0; x < (kViewPortCW + 1); x += (kViewPortCW + 1)) { + uint16 BTS = _myModLCNM[y2][x]; + + if (_tIsBackground[BTS] != 0) { + // Low Floor value, draw tile as background + drawSolid(_myCNM[y2][x], pointX, pointY); + + } else if (_tChrMask[BTS] >= 0x8000) { + // Right Mask, draw upper left hand corner (ULHC) of floor + drawULHC(_myCNM[y2][x], pointX, pointY); + + } else if (_tChrMask[BTS] != 0) { + // Left Mask, draw upper right hand corner (UPHC) of floor + drawURHC(_myCNM[y2][x], pointX, pointY); + } + pointX += kChrW; // This (and the H version) could be added to the for loop iterator arugment + } + pointX -= (kChrW * (kViewPortCW + 1)); // They could have also just done pointX = _myUnivPointX + pointY += kChrH; + } +} + +void ImmortalEngine::drawItems() { + for (int i = 0; i < (kViewPortCW + 1); i++) { + _columnIndex[i] = 0; + } + + for (int i = 0; i < (kViewPortCW + 1); i++) { + _columnTop[i] = _myUnivPointY; + } + + _columnX[0] = _myUnivPointX; + for (int i = 1; i < (kViewPortCW + 1); i++) { + _columnX[i] = _myUnivPointX + kChrW; + } + + // This is truly horrible, I should double check that this is the intended logic + int n = 0; + uint16 rowY = 0; + do { + uint16 index = _tIndex[n]; + if (index >= 0x8000) { // If negative, it's a row to draw + // rowY is (I think) the position of the start of the scroll window within the tile data + rowY = (index & 0x7FFF) + _myUnivPointY; + + // The background is a matrix of rows and columns, so for each column, we draw each row tile + for (int i = 0; (i < (kViewPortCW + 1)); i++) { + //draw the column of rows + while (_columnIndex[i] < ((kViewPortCW + 1) * (kViewPortCH + 1))) { + + k = _myModLCNM[i][_columnIndex[i]]; + if ((rowY - _tChrDy[k]) < _columnTop[i]) { + break; + } + if (_tIsBackground[k] == 0) { + // If it's a background tile, we already drew it (why is it in here then??) + if (_tChrMask[k] >= 0x8000) { + // Right Mask, draw lower right hand corner (LRHC) + drawLRHC(_myCNM[i][_columnIndex[i]], _columnTop[i], _columnX[i]); + + } else if (_tChrMask[k] == 0) { + // Floor or cover, draw the whole CHR + drawSolid(_myCNM[i][_columnIndex[i]], _columnTop[i], _columnX[i]); + + } else { + // Left Mask, draw lower left hand corner (LLHC) + drawLLHC(_myCNM[i][_columnIndex[i]], _columnTop[i], _columnX[i]); + } + } + _columnTop[i] += kChrH; + _columnIndex += (kViewPortCW + 1); + } + } + + } else { + // If positive, it's a sprite + uint16 x = (_sprites[index]._X - _myViewPortX) + kVSX; + uint16 y = (_sprites[index]._Y - _myViewPortY) + kVSY; + superSprite(index, x, y, _sprites[index]._dSprite->_frames[_sprites[index]._frame], kVSBMW, _screenBuff, kMySuperTop, kMySuperBottom); + } + n++; + } while (n != _num2DrawItems); +} + +void ImmortalEngine::printChr(char c) { + // This draws a character from the font sprite table, indexed as an ascii char, using superSprite + c &= kMaskASCII; // Grab just the non-extended ascii part + if (c == ' ') { + _penX += 8; // A space just moves the position on the screen to draw ahead by the size of a space + return; + } + + if (c == 0x27) { + _penX -= 2; + } + + if ((c >= 'A') && (c <= 'Z')) { + _penX += 8; + + } else { + switch (c) { + // Capitals, the health bar icons, and lower case m/w are all 2 chars wide + case 'm': + case 'w': + case 'M': + case 'W': + case 1: // Can't use the constant for this for some reason + case 0: + _penX += 8; + break; + case 'i': + _penX -= 3; + break; + case 'j': + case 't': + _penX -= 2; + break; + case 'l': + _penX -= 4; + default: + break; + } + } + + uint16 x = _penX + kScreenLeft; + if (x < _dataSprites[kFont]._cenX) { + return; + } + + uint16 y = _penY + kScreenTop; + if (y < _dataSprites[kFont]._cenY) { + return; + } + + superSprite(0, x, y, _dataSprites[kFont]._frames[(int) c], kScreenBMW, _screenBuff, kSuperTop, kSuperBottom); + if ((c == 0x27) || (c == 'T')) { + _penX -= 2; // Why is this done twice?? + } + + _penX += 8; +} /* * @@ -97,12 +357,12 @@ void ImmortalEngine::scroll() {} void ImmortalEngine::addSprite(uint16 x, uint16 y, SpriteName n, int frame, uint16 p) { if (_numSprites != kMaxSprites) { - if (x >= (kScreenW + kMaxSpriteLeft)) { + if (x >= (kResH + kMaxSpriteLeft)) { x |= kMaskHigh; // Make it negative } _sprites[_numSprites]._X = (x << 1) + _viewPortX; - if (y >= (kMaxSpriteAbove + kScreenH)) { + if (y >= (kMaxSpriteAbove + kResV)) { y |= kMaskHigh; } _sprites[_numSprites]._Y = (y << 1) + _viewPortY; @@ -148,17 +408,15 @@ void ImmortalEngine::loadSprites() { Common::String spriteNames[] = {"MORESPRITES.SPR", "NORLAC.SPR", "POWWOW.SPR", "TURRETS.SPR", "WORM.SPR", "IANSPRITES.SPR", "LAST.SPR", "DOORSPRITES.SPR", "GENSPRITES.SPR", "DRAGON.SPR", "MORDAMIR.SPR", "FLAMES.SPR", - "ROPE.SPR", "RESCUE.SPR", "TROLL.SPR", "GOBLIN.SPR", "ULINDOR.SPR", - "SPIDER.SPR", "DRAG.SPR"}; - - Common::SeekableReadStream *files[19]; + "ROPE.SPR", "RESCUE.SPR", "TROLL.SPR", "GOBLIN.SPR", "WIZARDA.SPR", + "WIZARDB.SPR", "ULINDOR.SPR", "SPIDER.SPR", "DRAG.SPR"}; // Number of sprites in each file - int spriteNum[] = {10, 5, 7, 10, 4, 6, 3, 10, 5, 3, 2, 1, 3, 2, 9, 10, 9, 10, 9}; + int spriteNum[] = {10, 5, 7, 10, 4, 6, 3, 10, 5, 3, 2, 1, 3, 2, 9, 10, 8, 3, 9, 10, 9}; // Pairs of (x,y) for each sprite // Should probably have made this a 2d array, oops - uint8 centerXY[] = {16,56, 16,32, 27,39, 16,16, 32,16, 34,83, 28,37, 8,12, 8,19, 24,37, + uint16 centerXY[] = {16,56, 16,32, 27,39, 16,16, 32,16, 34,83, 28,37, 8,12, 8,19, 24,37, /* Norlac */ 46,18, 40,0, 8,13, 32,48, 32,40, /* Powwow */ 53,43, 28,37, 27,37, 26,30, 26,30, 26,29, 28,25, /* Turrets */ 34,42, 28,37, 24,32, 32,56, 26,56, 8,48, 8,32, 8,14, 8,24, 32,44, @@ -174,25 +432,25 @@ void ImmortalEngine::loadSprites() { /* Rescue */ 0,112, 0,112, /* Troll */ 28,38, 28,37, 28,37, 31,38, 28,37, 25,39, 28,37, 28,37, 28,37, /* Goblin */ 28,38, 30,38, 26,37, 30,38, 26,37, 26,37, 26,37, 26,37, 26,36, 44,32, + /* Wizarda */ 28,37, 28,37, 28,37, 28,37, 28,37, 28,37, 28,37, 28,37, + /* Wizardb */ 28,37, 28,37, 28,37, /* Ulindor */ 42,42, 42,42, 42,42, 42,42, 42,42, 42,42, 42,42, 42,42, 42,42, /* Spider */ 64,44, 64,44, 64,44, 64,44, 64,44, 64,44, 64,44, 64,44, 64,44, 64,44, /* Drag */ 19,36, 19,36, 19,36, 19,36, 19,36, 19,36, 19,36, 19,36, 19,36}; - // Load all sprite files - for (int i = 0; i < 19; i++) { - files[i] = loadIFF(spriteNames[i]); - } - // s = current sprite index, f = current file index, n = current number of sprites for this file int s = 0; - for (int f = 0; f < 19; f++) { + for (int f = 0; f < 21; f++) { + // For every sprite file, open it and get the pointer + Common::SeekableReadStream *file = loadIFF(spriteNames[f]); + for (int n = 0; n < (spriteNum[f] * 2); n += 2, s++) { + // For every data sprite in the file, make a datasprite and initialize it DataSprite d; + initDataSprite(file, &d, n/2, centerXY[s * 2], centerXY[(s * 2) + 1]); _dataSprites[s] = d; - setSpriteCenter(files[f], s, centerXY[s * 2], centerXY[(s * 2) + 1]); } } - } void ImmortalEngine::loadWindow() { @@ -232,14 +490,14 @@ void ImmortalEngine::loadWindow() { void ImmortalEngine::loadFont() { // Initialize the font data sprite Common::SeekableReadStream *f = loadIFF("FONT.SPR"); - DataSprite d; - _dataSprites[kFont] = d; if (f) { - setSpriteCenter(f, kFont, 16, 0); + initDataSprite(f, &d, 0, 16, 0); + _dataSprites[kFont] = d; + } else { - debug("oh nose :("); + debug("file doesn't exit?!"); } } @@ -281,11 +539,12 @@ Common::SeekableReadStream *ImmortalEngine::loadIFF(Common::String fileName) { f.seek(12); return unCompress(&f, len); } + // Gotta remember we just moved the cursor around a bunch, need to reset it to read the file + f.seek(SEEK_SET); byte *out = (byte *)malloc(f.size()); f.read(out, f.size()); return new Common::MemoryReadStream(out, f.size(), DisposeAfterUse::YES); - } @@ -335,10 +594,10 @@ void ImmortalEngine::setColors(uint16 pal[]) { // Green is already the correct size, being the second nyble (00G0) // Red is in the first nyble of the high byte, so it needs to move right by 4 bits (0R00 -> 00R0) // Blue is the first nyble of the first byte, so it needs to move left by 4 bits (000B -> 00B0) - // We also need to repeat the bits so that the colour is the same proportion of 255 as it is 15 + // We also need to repeat the bits so that the colour is the same proportion of 255 as it is of 15 _palRGB[(i * 3)] = ((pal[i] & kMaskRed) >> 4) | ((pal[i] & kMaskRed) >> 8); - _palRGB[(i * 3) + 1] = (pal[i] & kMaskGreen) | ((pal[i] & kMaskGreen) >> 4) ; - _palRGB[(i * 3) + 2] = (pal[i] & kMaskBlue) | ((pal[i] & kMaskBlue) << 4); + _palRGB[(i * 3) + 1] = (pal[i] & kMaskGreen) | ((pal[i] & kMaskGreen) >> 4); + _palRGB[(i * 3) + 2] = (pal[i] & kMaskBlue) | ((pal[i] & kMaskBlue) << 4); } } // Palette index to update first is 0, and there are 16 colours to update @@ -382,14 +641,14 @@ void ImmortalEngine::fadePal(uint16 pal[], int count, uint16 target[]) { * but will not touch the window frame palette. It essentially takes the * color value nyble, multiplies it by a multiplier, then takes the whole * number result and inserts it into the word at the palette index of the - * temporary palette. This could I'm sure be done with regular multiplication + * temporary palette. This could I'm sure, be done with regular multiplication * and division operators, but in case the bits that get dropped are otherwise * kept, this is a direct translation of the bit manipulation sequence. */ - int maskPal[16] = {0xFFFF, 0x0000, 0x0000, 0x0000, - 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, - 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, - 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF}; + uint16 maskPal[16] = {0xFFFF, 0x0000, 0x0000, 0x0000, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF}; uint16 result; uint16 temp; @@ -397,17 +656,20 @@ void ImmortalEngine::fadePal(uint16 pal[], int count, uint16 target[]) { for (int i = 15; i >= 0; i--) { result = maskPal[i]; if (result == 0) { + // If the equivalent maskPal entry is 0, then it is a colour we want to fade result = pal[i]; if (result != 0xFFFF) { - // Blue = 0RGB -> 000B -> 0BBB -> BB0B -> 000B + // If we have not reached FFFF in one direction or the other, we keep going + + // Blue = 0RGB -> 000B -> 0Bbb -> bb0B -> 000B result = (xba(mult16((result & kMaskFirst), count))) & kMaskFirst; - // Green = 0RGB -> 00RG -> 000G -> 0GGG -> GG0G -> 000G -> 00G0 -> 00GB + // Green = 0RGB -> 00RG -> 000G -> 0Ggg -> gg0G -> 000G -> 00G0 -> 00GB temp = mult16(((pal[i] >> 4) & kMaskFirst), count); temp = (xba(temp) & kMaskFirst) << 4; result = temp | result; - // Red = 0RGB -> GB0R -> 000R -> 0RRR -> RR0R -> 000R -> 0R00 -> 0RGB + // Red = 0RGB -> GB0R -> 000R -> 0Rrr -> rr0R -> 000R -> 0R00 -> 0RGB temp = xba(pal[i]) & kMaskFirst; temp = xba(mult16(temp, count)); temp = xba(temp & kMaskFirst); @@ -487,9 +749,21 @@ void ImmortalEngine::useDim() { void ImmortalEngine::userIO() {} void ImmortalEngine::pollKeys() {} void ImmortalEngine::noNetwork() {} -void ImmortalEngine::keyTraps() {} + +void ImmortalEngine::waitKey() { + bool wait = true; + while (wait == true) { + if (getInput() == true) { + wait = false; + } + } +} + void ImmortalEngine::blit8() {} -void ImmortalEngine::getInput() {} +bool ImmortalEngine::getInput() { + return true; +} + void ImmortalEngine::addKeyBuffer() {} void ImmortalEngine::clearKeyBuff() {} @@ -502,6 +776,63 @@ void ImmortalEngine::clearKeyBuff() {} * */ +void ImmortalEngine::toggleSound() { + // Interestingly, this does not mute or turn off the sound, it actually pauses it + _themePaused = !_themePaused; + fixPause(); +} + +void ImmortalEngine::fixPause() { + /* The code for this is a little strange, but the idea is that you have + * a level theme, and a combat theme, that can both be active. So first you + * pause the level theme, and then you pause the combat theme. + * The way it does it is weird though. Here's the logic: + * if playing either text or maze song, check if the theme is paused. else, just go ahead and pause. + * Same thing for combat song. A little odd. + */ + + // This is a nasty bit of code isn't it? It's accurate to the source though :D + switch (_playing) { + case kSongText: + case kSongMaze: + if (_themePaused) { + musicUnPause(_themeID); + break; + } + default: + musicPause(_themeID); + break; + } + + // Strictly speaking this should probably be a single function called twice, but the source writes out both so I will too + switch (_playing) { + case kSongCombat: + if (_themePaused) { + musicUnPause(_combatID); + break; + } + default: + musicPause(_combatID); + break; + } + +} + +// *** These two functions will be in music.cpp, they just aren't implemented yet *** +void ImmortalEngine::musicPause(int sID) {} +void ImmortalEngine::musicUnPause(int sID) {} +// *** + +Song ImmortalEngine::getPlaying() { + return kSongMaze; +} + +void ImmortalEngine::playMazeSong() { +} + +void ImmortalEngine::playCombatSong() { +} + void ImmortalEngine::loadSingles(Common::String songName) { debug("%s", songName.c_str()); } diff --git a/engines/immortal/sprites.cpp b/engines/immortal/sprites.cpp index 1bad636a6729..ae93b2f4258e 100644 --- a/engines/immortal/sprites.cpp +++ b/engines/immortal/sprites.cpp @@ -31,17 +31,49 @@ namespace Immortal { * */ -void ImmortalEngine::setSpriteCenter(Common::SeekableReadStream *f, int num, uint8 cenX, uint8 cenY) { - // Very simple, just initialize what we can of the data sprite - _dataSprites[num]._cenX = cenX; - _dataSprites[num]._cenY = cenY; - _dataSprites[num]._file = f; +// This function is basically setSpriteCenter + getSpriteInfo from the source +void ImmortalEngine::initDataSprite(Common::SeekableReadStream *f, DataSprite *d, int index, uint16 cenX, uint16 cenY) { + // We set the center X and Y, for some reason + d->_cenX = cenX; + d->_cenY = cenY; + + // But now we need to get the rest of the meta data for each frame + // index is the index of the sprite within the file (not the same as the sprite name enum) + index *= 8; + f->seek(index); + + index = f->readUint16LE(); + uint16 numFrames = f->readUint16LE(); + + d->_numFrames = numFrames; + debug("Number of Frames: %d", numFrames); + + // Only here for dragon, but just in case, it's a high number so it should catch others + if (numFrames >= 0x0200) { + debug("** Crazy large value, this isn't a frame number **"); + return; + } + + Common::Array frames; + + for (int i = 0; i < numFrames; i++) { + Frame newFrame; + f->seek(index + (i*2)); + int ptrFrame = f->readUint16LE(); + f->seek(ptrFrame); + newFrame._deltaX = f->readUint16LE() << 1; // the ASL might not be required, depending on how I translate the sprite drawing + newFrame._deltaY = f->readUint16LE(); + newFrame._rectX = f->readUint16LE(); + newFrame._rectY = f->readUint16LE(); + frames.push_back(newFrame); + // This is probably where we will get the bitmap when I know how to get it + } + + d->_frames = frames; } - - - +void ImmortalEngine::superSprite(int s, uint16 x, uint16 y, Frame f, int bmw, byte *dst, int sT, int sB) {} } // namespace Immortal From 09a1bba0d0586210f1f78d43d761a7be47bb362f Mon Sep 17 00:00:00 2001 From: Quote58 Date: Fri, 29 Jul 2022 05:40:02 -0400 Subject: [PATCH 310/412] IMMORTAL: Add _playing and _themePaused --- engines/immortal/immortal.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/engines/immortal/immortal.cpp b/engines/immortal/immortal.cpp index c07bcfdda3d7..623a5cdc3dc5 100644 --- a/engines/immortal/immortal.cpp +++ b/engines/immortal/immortal.cpp @@ -162,8 +162,8 @@ Common::Error ImmortalEngine::run() { loadWindow(); // Load the window background loadSingles("Song A"); // Music loadSprites(); // Get all the sprite data into memory - // playing = kPlayingNothing; - // themepaused = 0; + _playing = kSongNothing; + _themePaused = 0; clearSprites(); // Clear the sprites before we start logicInit(); // Init the game logic From db485ce3493610a321e04c6de4216b5ee221fe91 Mon Sep 17 00:00:00 2001 From: Quote58 Date: Fri, 29 Jul 2022 05:40:46 -0400 Subject: [PATCH 311/412] IMMORTAL: Fill out much of logic.cpp skeleton --- engines/immortal/logic.cpp | 328 ++++++++++++++++++++++++++++++++++--- engines/immortal/misc.cpp | 8 +- engines/immortal/module.mk | 6 +- 3 files changed, 312 insertions(+), 30 deletions(-) diff --git a/engines/immortal/logic.cpp b/engines/immortal/logic.cpp index c7061c8b5292..52b3c425d655 100644 --- a/engines/immortal/logic.cpp +++ b/engines/immortal/logic.cpp @@ -23,40 +23,295 @@ namespace Immortal { -bool ImmortalEngine::trapKeys() { - // This weirdly named routine just checks if you want to restart the game. On the NES it pulls up a dialog with a yes/no, - // But on the Apple IIGS it's just the R key - getInput(); - if (_pressedAction == kActionRestart) { - gameOver(); - return true; - } else if (_pressedAction == kActionSound) { - //toggleSound(); - } - return false; -} - -// There's no way this routine needs to still be here. In fact I'm not sure it needed to be in the game anyway? -int ImmortalEngine::getLevel() { - return _level; -} - void ImmortalEngine::logicInit() { _titlesShown = 0; _time = 0; _promoting = 0; - _restart = 1; + _restart = true; //level_initAtStartOfGameOnly _lastCertLen = 0; } +void ImmortalEngine::restartLogic() { + _singleStep = false; + _levelOver = false; + _gameFlags = kSavedNone; + + // Here's where the majority of the game actually gets initialized + //miscInit(); + //qarrayInit(); + //cycInit(); <-- room.initCycles() + //fsetInit(); <-- room.initTorches() + //levelInit(); <-- presumably creates room + //roomInit(); <-- will be run in constructor of room + //monstInit(); <-- room.initMonsters() \ + //objectInit(); <-- room.initObjects() + //doorInit(); <-- room.initDoors() |- probably all get run from room constructor + //sparkInit(); <-- room.initSparks() + //bulletInit(); <-- room.initProjectiles() / + //objectInit(); <-- again? Odd... + //genericSpriteInit(); <-- room.initGenSprites() + + // Probably will be written as: + // qarrayInit(); <-- will probably just be like, _qarray = new Common::Array(); + // levelInit(); + + if (fromOldGame() == false) { + _level = 0; + //levelNew(); + } + + if (_level != 7) { + _themePaused = true; // and #-1-2 = set both flags for themePaused + } +} + void ImmortalEngine::logic() { + trapKeys(); // First thing in any gameloop is to check if we should restart/toggle sound _time += 1; - // if time overflows the counter, inc the high byte? What the heck... + /* This is actually the main game state loop. I think the best way to translate it + * is as a do-while loop. As in, check if the gamestate says we need to restart, + * and if so, restart the logic and check again + * Personally, I think this should have been a jump table for the different + * game state routines, indexed by a single game state variable. + * Ie. LDX _gameState : JMP (gameStates),X + * Much cleaner I think. Regardless, this will probably be a switch statement eventually. + */ + do { + + if (_restart == true) { + restartLogic(); + _restart = false; + } + + // This is the original logic, but I think it makes more sense if this were an else if statement + if (_gameOverFlag == true) { + gameOver(); + _gameOverFlag = false; + _restart = true; + + } else if (_levelOver == true) { + _themePaused = true; + _levelOver = false; + + if (_level == (_maxLevels-1)) { + //textPrint(kPrintYouWin); + debug("YOU WIN"); + + } else { + //makeCertificate(); + //printCertificate(); + if (_level == 0) { + //manual2(); // <- debug? + } + _promoting = 1; + } + _restart = true; + + } else { + + // Here's where the gameplay sequence actually happens! + doSingleStep(); // Debug step function + //monstRunAll(); + //objectRunAll(); + //doInfiniteHallways(); + //levelDrawAll(); + updateHitGauge(); + + // What the heck? Check if we are in level 0: room 0, with no lit torches, and no projectiles + // If so, dim the screen + _dim = 0; + if ((_level == 0) && (/*_currentLevel.getShowRoom()*/0 == 0) && (/*roomLighted()*/false == false) && (/*getNumBullets()*/ 0 == 0)) { + _dim += 1; + } + + if (_level == 7) { + doGroan(); + } + + if (/*monstIsCombat(kPlayerID)*/true == true) { + if (getPlaying() != kSongCombat) { + playCombatSong(); + } + } else { + if (getPlaying() != kSongMaze) { + playMazeSong(); + } + } + } + + } while (_restart == true); } -void ImmortalEngine::restartLogic() { +void ImmortalEngine::trapKeys() { + /* Weird name for a normal routine. It simply checks for the + * restart key (or button on the nes), or the sound toggle, + * (if debug mode is active it also checks for the + * _singleStep key), and then performs a high level action + * (on the NES it only checks restart, and it opens a dialog to do it) + */ + getInput(); + switch (_pressedAction) { + case kActionDBGStep: + _singleStep = true; + break; + case kActionRestart: + gameOver(); + break; + case kActionSound: + toggleSound(); + default: + break; + } +} + +void ImmortalEngine::doSingleStep() { + /* This is a very cool debug routine. If you press the _singleStep key, + * the engine enters this debug mode where it waits for another key press. + * If the key is anything other than the _singleStep key, it will advance + * the engine one frame (or rather, until we hit this routine again, which + * should be one frame). If you hit the _singleStep key, it will exit the mode + * and advance normally again. + */ + if (_singleStep == true) { + // If singleStep mode is active, stop the engine until we get input + waitKey(); + // If the input is anything other than DGBStep, advance one frame + if (_pressedAction == kActionDBGStep) { + // Otherwise, we want to exit the mode + _singleStep = false; + } + } +} + +void ImmortalEngine::updateHitGauge() { + /* This HUD (essentially) drawing routine is a bit weird because + * the game was originally meant to have multiple player characters + * in the room at once. So the engine sees the player as a 'monster' + * in the same way it sees enemies (and presumably would have seen other players). + * As such, this routine asks the room to ask the monster called player, + * what their health is. If the game considered the player unique, this would + * probably just check a global 'health' variable instead. + */ + //int h = _rooms[_currentRoom]._monsters[kPlayerID]._getHits(); + int hits = 0; + if (hits != _lastGauge) { + // Update the mirror value if the health has changed since last frame + _lastGauge = hits; + drawGauge(hits); + } +} + +void ImmortalEngine::drawGauge(int h) { + /* Draw the health bar: + * We have two variables, the current health (number of hits remaining), + * and the difference betweeen the current health and max health (16). + * We then do some silly branching logic that is functionally the same + * as a for loop for the available health, and then another for unavailable health. + * But we could also write it much more efficiently like this: + * sta tmp : lda #$16 : tay : dey : sub tmp : tax + * - + * txa : beq + + * lda #$1 : dex + * + + * jsr draw + * dey : bpl - + * Ie. Loop over the entire bar, and once you run out of one icon to draw, that 0 becomes + * the index of the chr for the other icons. + */ + int r = 16 - h; + _penX = kGaugeX; + _penY = kGaugeY; + h--; + if (h >= 0) { + // This could be written as a regular for loop, but the game thinks of start/stop as different from on + printChr(kGaugeStart); + h--; + for (; h >= 0; h--) { + if (h == 0) { + // Redundant code is redundant + printChr(kGaugeStop); + + } else { + printChr(kGaugeOn); + } + } + + } else { + // Oh hey, this one is indeed a normal for loop + for (; r >= 0; r--) { + printChr(kGaugeOff); + } + } +} + +void ImmortalEngine::doGroan() { + //getRandom(); +} + +bool ImmortalEngine::printAnd(const Common::String s) { + // Just prints what it's given and then checks for input + textPrint(s); + getInput(); + if (_heldAction != kActionNothing) { + return true; + } + return false; +} + +bool ImmortalEngine::fromOldGame() { + /* + if (_titlesShown == 0) { + _titlesShown++; + _dontResetColors = 1; + printAnd(kTitle0); + printAnd(kTitle4); + getInput(); + return false; + } + + _dontResetColors = 0; + if (_promoting == 1) { + _promoting = 0; + + } else { + + do { + if (!textPrint(kOldGameString)) { + // They choose not to load an old game + return false; + } + } while (getCertificate()); + + if (_lastCertLen == 0) { + return false; + } + } + + _level = _cert + kCertLevel; + setGameFlags(((_cert + kCertHiGameFlags) << 4) | (_cert + kCertLoGameFlags)); + uint16 hits = _cert + kCertHits; + uint16 quick = _cert + kCertQuickness; + uint16 gold = ((_cert + kCertGoldHi) << 4) | (_cert + kCertGoldLo); + // monstMakePlayer(hits, quick, gold); <- will become room.makePlayer(); + + uint8 tmp = 3; + uint8 flags = kObjIsRunning; + uint8 frame; + uint8 type; + + // room.makeObject(tmp, flags, gold, )*/ + return true; +} + +void ImmortalEngine::setGameFlags(uint16 f) { + +} + +// There's no way this routine needs to still be here. In fact I'm not sure it needed to be in the game anyway? +int ImmortalEngine::getLevel() { + return _level; } int ImmortalEngine::logicFreeze() { @@ -66,8 +321,9 @@ int ImmortalEngine::logicFreeze() { } void ImmortalEngine::gameOverDisplay() { - _themePaused |= 2; + _themePaused = true; //text_print(kGameOverString) + debug("GAME OVER"); } void ImmortalEngine::gameOver() { @@ -78,6 +334,34 @@ void ImmortalEngine::levelOver() { _levelOver = 1; } +void ImmortalEngine::setSavedKing() { + _gameFlags |= kSavedKing; +} + +bool ImmortalEngine::isSavedKing() { + if ((_gameFlags & kSavedKing) == 1) { + return true; + } else { + return false; + } +} + +void ImmortalEngine::setSavedAna() { + _gameFlags |= kSavedAna; +} + +bool ImmortalEngine::isSavedAna() { + if ((_gameFlags & kSavedAna) == 1) { + return true; + } else { + return false; + } +} + +bool ImmortalEngine::getCertificate() { + return true; +} + } // namespace Immortal diff --git a/engines/immortal/misc.cpp b/engines/immortal/misc.cpp index f55680f21fad..8f49b2243633 100644 --- a/engines/immortal/misc.cpp +++ b/engines/immortal/misc.cpp @@ -57,7 +57,9 @@ void ImmortalEngine::myDelay() {} * */ -void ImmortalEngine::textPrint(int num) {} +bool ImmortalEngine::textPrint(const Common::String s) { + return true; +} void ImmortalEngine::textSub() {} void ImmortalEngine::textEnd() {} void ImmortalEngine::textMiddle() {} @@ -87,10 +89,6 @@ void ImmortalEngine::firePressed() {} void ImmortalEngine::inside(int p, int p2, int a) {} void ImmortalEngine::insideRect(int p, int r) {} -void ImmortalEngine::updateHitGuage() {} - - - } // namespace Immortal diff --git a/engines/immortal/module.mk b/engines/immortal/module.mk index fa12eb2f94f9..6e2c6e8c62cb 100644 --- a/engines/immortal/module.mk +++ b/engines/immortal/module.mk @@ -1,13 +1,13 @@ MODULE := engines/immortal MODULE_OBJS = \ - immortal.o \ - disk.o \ metaengine.o \ - compression.o \ + disk.o \ + immortal.o \ kernal.o \ logic.o \ sprites.o \ + compression.o \ misc.o \ cycle.o From 8391e33c71126f0a7586808a87aacc1f22a3c693 Mon Sep 17 00:00:00 2001 From: Quote58 Date: Fri, 29 Jul 2022 05:54:13 -0400 Subject: [PATCH 312/412] IMMORTAL: Add SpriteFrame enum --- engines/immortal/sprite_list.h | 62 ++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/engines/immortal/sprite_list.h b/engines/immortal/sprite_list.h index 2411936dcf88..b4e80963e624 100644 --- a/engines/immortal/sprite_list.h +++ b/engines/immortal/sprite_list.h @@ -24,6 +24,68 @@ namespace Immortal { +enum SpriteFrame { + // Chest frames + kChest0Frame, + kOpenChestFrame, + kRingFrame, + kKnifeFrame, + kDeadGoblinFrame, + + // Normal frames + kSwordFrame, + kKeyFrame, + kYesIconOff, + kYesIconOn, + kNoIconOff, + kNoIconOn, + kChoiceFrame, + kEraseChoseFrame, + kSwordBigFrame, + kVaseBigFrame, + kVaseFrame, + kBrokenFrame, + kKeyBigFrame, + kBagFrame, + kBagBigFrame, + kBookBigFrame, + kBookFrame, + kScrollFrame, + kScrollBigFrame, + kOkayFrame, + kAltarFrame, + kGoldBigFrame, + kMapBigFrame, + kSemblanceFrame, + kTrapDoorFrame, + kBonesFrame, + kSackBigFrame, + kSporesFrame, + kGemGlintFrame, + kStoneFrame, + kGreenStoneFrame, + kGemBigFrame, + kStoneBigFrame, + kPileFrame, + kNoteBigFrame, + + // 45 - 48 are Merchant frames + kMerchantFrame, + + // Remaining frames + kCoinBigFrame = 49, + kPileBigFrame, + kKingFrame, + kDeadKingFrame, + kBombBigFrame, + kRingBigFrame, + kKnifeBigFrame, + kCarpetBigFrame, + kAnaInHoleFrame, + kAnaNotInHoleFrame, + kInvisRingFrame +}; + enum SpriteName { // Moresprites 10 kCandle, From c942b7f0957cd626fade9287e0ccee684e78e246 Mon Sep 17 00:00:00 2001 From: Quote58 Date: Sat, 30 Jul 2022 20:55:08 -0400 Subject: [PATCH 313/412] IMMORTAL: Add drawChr.cpp with function declarations and entry in module.mk --- engines/immortal/drawChr.cpp | 41 ++++++++++++++++++++++++++++++++++++ engines/immortal/module.mk | 13 +++++++++++- 2 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 engines/immortal/drawChr.cpp diff --git a/engines/immortal/drawChr.cpp b/engines/immortal/drawChr.cpp new file mode 100644 index 000000000000..7ef77391543b --- /dev/null +++ b/engines/immortal/drawChr.cpp @@ -0,0 +1,41 @@ +/* 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 "immortal/immortal.h" + +namespace Immortal { + +int ImmortalEngine::mungeCBM(int numChrs) { + return 0; +} +void ImmortalEngine::storeAddr() {} +void ImmortalEngine::mungeSolid() {} +void ImmortalEngine::mungeLRHC() {} +void ImmortalEngine::mungeLLHC() {} +void ImmortalEngine::mungeULHC() {} +void ImmortalEngine::mungeURHC() {} +void ImmortalEngine::drawSolid(int chr, int x, int y) {} +void ImmortalEngine::drawULHC(int chr, int x, int y) {} +void ImmortalEngine::drawURHC(int chr, int x, int y) {} +void ImmortalEngine::drawLLHC(int chr, int x, int y) {} +void ImmortalEngine::drawLRHC(int chr, int x, int y) {} + +} // namespace immortal \ No newline at end of file diff --git a/engines/immortal/module.mk b/engines/immortal/module.mk index 6e2c6e8c62cb..18b5dfdf28b8 100644 --- a/engines/immortal/module.mk +++ b/engines/immortal/module.mk @@ -9,7 +9,18 @@ MODULE_OBJS = \ sprites.o \ compression.o \ misc.o \ - cycle.o + cycle.o \ + drawChr.o + +# level.o \ +# universe.o \ +# room.o \ +# object.o \ +# door.o \ +# flameset.o \ +# bullet.o \ +# monster.o \ +# motives.o # This module can be built as a plugin ifeq ($(ENABLE_IMMORTAL), DYNAMIC_PLUGIN) From 076742aa14fe55251fcaa7137c7ff1872e1063cc Mon Sep 17 00:00:00 2001 From: Quote58 Date: Sat, 30 Jul 2022 21:05:09 -0400 Subject: [PATCH 314/412] IMMORTAL: Logic skeleton filled out and necessary parts of story.h added --- engines/immortal/immortal.h | 161 +++++++++--------- engines/immortal/kernal.cpp | 27 ++- engines/immortal/logic.cpp | 325 ++++++++++++++++++++++++++++++------ engines/immortal/misc.cpp | 8 +- engines/immortal/story.h | 75 +++++++++ 5 files changed, 454 insertions(+), 142 deletions(-) create mode 100644 engines/immortal/story.h diff --git a/engines/immortal/immortal.h b/engines/immortal/immortal.h index fc489eacb28e..584e7dc0f778 100644 --- a/engines/immortal/immortal.h +++ b/engines/immortal/immortal.h @@ -50,6 +50,7 @@ #include "immortal/disk.h" #include "immortal/sprite_list.h" // This is an enum of all available sprites +#include "immortal/story.h" namespace Immortal { @@ -71,12 +72,20 @@ enum BitMask8 : uint8 { kMask8Low = 0x0F }; -enum ColourMask : uint16 { +enum ColourBitMask : uint16 { kMaskRed = 0x0F00, kMaskGreen = 0x00F0, kMaskBlue = 0x000F }; +enum ChrMask : uint16 { + kChr0 = 0x0000, + kChrL = 0x0001, + kChrR = 0xFFFF, + kChrLD = 0x0002, + kChrRD = 0xFFFE +}; + enum Screen { // These are constants that are used for defining screen related arrays kMaxRooms = 16, // Should probably put this in a different enum kMaxSprites = 32, // Number of sprites allowed at once @@ -87,10 +96,11 @@ enum Screen { // These are constants that are used for defining screen enum InputAction { kActionNothing, + kActionKey, kActionRestart, // Key "R" <-- Debug? kActionSound, kActionFire, - kActionButton, + kActionButton, // Does this just refer to whatever is not the fire button? kActionDBGStep // Debug key for moving engine forward one frame at a time }; @@ -101,24 +111,6 @@ enum InputDirection { kDirectionRight }; -enum ObjFlag : uint8 { - kObjUsesFireButton = 0x40, - kObjIsInvisible = 0x20, - kObjIsRunning = 0x10, - kObjIsChest = 0x08, - kObjIsOnGround = 0x04, - kObjIsF1 = 0x02, - kObjIsF2 = 0x01 -}; - -enum Monster { - kPlayerID -}; - -enum Str { - kStrGold -}; - enum CertIndex : uint8 { kCertHits, kCertLevel, @@ -168,15 +160,6 @@ struct Sprite { DataSprite *_dSprite; }; -struct ObjType { - Str _str; - Str _desc; - int _size; - //_pickup; - //_use; - //_run; -}; - struct ImmortalGameDescription; // Forward declaration because we will need the Disk class @@ -215,6 +198,19 @@ class ImmortalEngine : public Engine { */ // Misc constants + const int kNumLengths = 21; + const int kNiceTime = 36; + const int kMaxCertificate = 16; + + // this should really be a char array, but inserting frame values will be stupid so it's just a string instead + const Common::String genStr[11] = {"New game?%", "Enter certificate:&-=", "Invalid certificate.@", + "End of level!&Here is your certificate:&&=", "&@", + " Electronic Arts presents&& The Immortal&&&&  1990 Will Harvey|]]]]]]]]]=", // Might need \ for something + " written by&& Will Harvey& Ian Gooding& Michael Marcantel& Brett G. Durrett& Douglas Fulton|]]]]]]]/=", + "#" + Common::String(kGoldBigFrame) + "$0 gold@", + "Congratulations!&&Play again?@", + "Enter certificate:&-=", + "Game Over&&Play again?@"}; // Screen constants const int kResH = 320; @@ -231,20 +227,31 @@ class ImmortalEngine : public Engine { const int kGaugeX = 0; const int kGaugeY = -13; // ??? const int kScreenBMW = 160; // Literally no idea yet - const int kChrW = 64; - const int kChrH = 32; + const uint16 kChrW = 64; + const uint16 kChrH = 32; + const uint16 kChrH2 = kChrH * 2; + const uint16 kChrH3 = kChrH * 3; const int kChrLen = (kChrW / 2) * kChrH; const int kChrBMW = kChrW / 2; - - uint16 _tChrMask[] = {0,0,0,0,-1,1,0,1,-1,0,0,2,0,-1,2,-2,0,-2,1}; - - uint16 _isBackground[] = {1,0,0,0,0,0,0,0, - 0,1,1,0,0,0,0,0, - 0,0,0, - 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0, - 0}; - + const int kLCutaway = 4; + + const uint16 kChrDy[19] = {kChr0, kChrH, kChrH2, kChrH, kChrH2, + kChrH2, kChrH, kChrH2, kChrH2, kChr0, + kChr0, kChrH2, kChrH, kChrH2, kChrH2, + kChrH2, kChrH, kChrH2, kChrH2}; + + const uint16 kChrMask[19] = {kChr0, kChr0, kChr0, kChr0, + kChrR, kChrL, kChr0, kChrL, + kChrR, kChr0, kChr0, kChrLD, + kChr0, kChrR, kChrLD, kChrRD, + kChr0, kChrRD, kChrL}; + + const uint16 kIsBackground[36] = {1, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0}; // Disk offsets const int kPaletteOffset = 21205; // This is the byte position of the palette data in the disk @@ -272,25 +279,20 @@ class ImmortalEngine : public Engine { const int kWizardY = 37; // Asset constants - const char kGaugeOn = 1; // On uses the sprite at index 1 of the font spriteset - const char kGaugeOff = 0; // Off uses the sprite at index 0 of the font spriteset - const char kGaugeStop = 1; // Literally just means the final kGaugeOn char to draw - const char kGaugeStart = 1; // First kGaugeOn char to draw - - // General Strings - const Common::String kOldGameString = "New game?%"; - const Common::String kEnterCertificate = "Enter certificate:&-="; - const Common::String kBadCertificate = "Invalid certificate.@"; - const Common::String kCertString = "End of level!&Here is your certificate:&&="; - const Common::String kCert2String = "&@"; - const Common::String kTitle0 = " Electronic Arts presents&& The Immortal&&&&  1990 Will Harvey|]]]]]]]]]="; // Might need \ for something - const Common::String kTitle4 = " written by&& Will Harvey& Ian Gooding& Michael Marcantel& Brett G. Durrett& Douglas Fulton|]]]]]]]/="; + const char kGaugeOn = 1; // On uses the sprite at index 1 of the font spriteset + const char kGaugeOff = 0; // Off uses the sprite at index 0 of the font spriteset + const char kGaugeStop = 1; // Literally just means the final kGaugeOn char to draw + const char kGaugeStart = 1; // First kGaugeOn char to draw + + /* * 'global' members */ // Misc Common::ErrorCode _err; // If this is not kNoError at any point, the engine will stop + uint8 _certificate[16]; // The certificate (password) is basically the inventory/equipment array + uint8 _lastCertLen = 0; bool _draw = 0; // Whether the screen should draw this frame int _zero = 0; // No idea what this is yet bool _gameOverFlag = false; @@ -300,14 +302,12 @@ class ImmortalEngine : public Engine { int _time = 0; int _promoting = 0; // I think promoting means the title stuff bool _restart = false; - int _lastCertLen = 0; - int _cert = 0; // This will probably not be an int // Level members - int _maxLevels = 0; // This is determined when loading in story files - int _level = 0; - bool _levelOver = false; - Room *_rooms[kMaxRooms]; // Rooms within the level + int _maxLevels = 0; // This is determined when loading in story files + int _level = 0; + bool _levelOver = false; + Room *_rooms[kMaxRooms]; // Rooms within the level // Debug members bool _singleStep; // Flag for _singleStep mode @@ -327,17 +327,17 @@ class ImmortalEngine : public Engine { int _numSprites = 0; // This is more accurately actually the index within the sprite array, so _numSprites + 1 is the current number of sprites DataSprite _font; // The font sprite data is loaded separate from other sprite stuff Sprite _sprites[kMaxSprites]; // All the sprites shown on screen - DataSprite _dataSprites[kFont+1]; // All the sprite data, indexed by SpriteFile + DataSprite _dataSprites[kFont + 1]; // All the sprite data, indexed by SpriteFile // Screen members - byte *_window; // Bitmap of the window around the game - byte *_screenBuff; // The final buffer that will transfer to the screen - uint16 _myCNM[(kViewPortCW+1)][(kViewPortCH+1)]; - uint16 _myModCNM[(kViewPortCW+1)][(kViewPortCH+1)]; - uint16 _myModLCNM[(kViewPortCW+1)][(kViewPortCH+1)]; - uint16 _columnX[kViewPortCW+1]; - uint16 _columnTop[kViewPortCW+1]; - uint16 _columnIndex[kViewPortCW+1]; // Why the heck is this an entire array, when it's just an index that gets zeroed before it gets used anyway... + byte *_window; // Bitmap of the window around the game + byte *_screenBuff; // The final buffer that will transfer to the screen + uint16 _myCNM[(kViewPortCW + 1)][(kViewPortCH + 1)]; + uint16 _myModCNM[(kViewPortCW + 1)][(kViewPortCH + 1)]; + uint16 _myModLCNM[(kViewPortCW + 1)][(kViewPortCH + 1)]; + uint16 _columnX[kViewPortCW + 1]; + uint16 _columnTop[kViewPortCW + 1]; + uint16 _columnIndex[kViewPortCW + 1]; // Why the heck is this an entire array, when it's just an index that gets zeroed before it gets used anyway... uint16 _tIndex[kMaxDrawItems]; uint16 _tPriority[kMaxDrawItems]; uint16 _viewPortX; @@ -353,14 +353,14 @@ class ImmortalEngine : public Engine { Graphics::Surface *_mainSurface; // Palette members - bool _dim = 0; // Whether the palette is dim + int _dontResetColors = 0; // Not sure yet + bool _usingNormal = 0; // Whether the palette is using normal + bool _dim = 0; // Whether the palette is dim uint16 _palDefault[16]; uint16 _palWhite[16]; uint16 _palBlack[16]; uint16 _palDim[16]; byte _palRGB[48]; // Palette that ScummVM actually uses, which is an RGB conversion of the original - int _dontResetColors = 0; // Not sure yet - bool _usingNormal = 0; // Whether the palette is using normal /* @@ -376,6 +376,7 @@ class ImmortalEngine : public Engine { void clearScreen(); // Draws a black rectangle on the screen buffer but only inside the frame void whiteScreen(); // Draws a white rectanlge on the screen buffer (but does not do anything with resetColors) void rect(int x, int y, int w, int h); // Draws a solid rectangle at x,y with size w,h. Also shadows for blit? + void backspace(); // Moves draw position back and draws empty rect in place of char void printChr(char c); void loadWindow(); // Gets the window.bm file void drawUniv(); // Draw the background, add the sprites, determine draw order, draw the sprites @@ -392,7 +393,6 @@ class ImmortalEngine : public Engine { void sortDrawItems(); // Sort said items void drawItems(); // Draw the items over the background - // Music void toggleSound(); // Actually pauses the sound, doesn't just turn it off/mute void fixPause(); @@ -423,6 +423,7 @@ class ImmortalEngine : public Engine { // Assets Common::SeekableReadStream *loadIFF(Common::String fileName); // Loads a file and uncompresses if it is compressed + //void loadMazeGraphics(); // Creates a universe with a maze void loadFont(); // Gets the font.spr file, and centers the sprite void clearSprites(); // Clears all sprites before drawing the current frame void loadSprites(); // Loads all the sprite files and centers their sprites (in spritelist, but called from kernal) @@ -461,18 +462,22 @@ class ImmortalEngine : public Engine { // Main void trapKeys(); // Poorly named, this checks if the player wants to restart/pause music/use debug step + int keyOrButton(); // Returns value based on whether it was a keyboard key or a button press void logicInit(); void logic(); // Keeps time, handles win and lose conditions, then general logic void restartLogic(); // This is the actual logic init int logicFreeze(); // Overcomplicated way to check if game over or level over void updateHitGauge(); void drawGauge(int h); + void calcCheckSum(int l, uint8 checksum[]); // Checksum is one word, but the source called it CheckSum bool getCertificate(); + void printCertificate(); // Misc - bool printAnd(const Common::String s); + bool printAnd(Str s); bool fromOldGame(); void setGameFlags(uint16 f); + uint16 getGameFlags(); void setSavedKing(); bool isSavedKing(); void setSavedAna(); @@ -497,11 +502,11 @@ class ImmortalEngine : public Engine { void myDelay(); // Text printing - bool textPrint(const Common::String s); + bool textPrint(Str s); void textSub(); - void textEnd(); - void textMiddle(); - void textBeginning(); + void textEnd(Str s); + void textMiddle(Str s); + void textBeginning(Str s); void yesNo(); // Input related diff --git a/engines/immortal/kernal.cpp b/engines/immortal/kernal.cpp index 8e5deb0d82ae..79b15bfb514e 100644 --- a/engines/immortal/kernal.cpp +++ b/engines/immortal/kernal.cpp @@ -207,15 +207,15 @@ void ImmortalEngine::drawBGRND() { for (int x = 0; x < (kViewPortCW + 1); x += (kViewPortCW + 1)) { uint16 BTS = _myModLCNM[y2][x]; - if (_tIsBackground[BTS] != 0) { + if (kIsBackground[BTS] != 0) { // Low Floor value, draw tile as background drawSolid(_myCNM[y2][x], pointX, pointY); - } else if (_tChrMask[BTS] >= 0x8000) { + } else if (kChrMask[BTS] >= 0x8000) { // Right Mask, draw upper left hand corner (ULHC) of floor drawULHC(_myCNM[y2][x], pointX, pointY); - } else if (_tChrMask[BTS] != 0) { + } else if (kChrMask[BTS] != 0) { // Left Mask, draw upper right hand corner (UPHC) of floor drawURHC(_myCNM[y2][x], pointX, pointY); } @@ -254,17 +254,20 @@ void ImmortalEngine::drawItems() { //draw the column of rows while (_columnIndex[i] < ((kViewPortCW + 1) * (kViewPortCH + 1))) { - k = _myModLCNM[i][_columnIndex[i]]; - if ((rowY - _tChrDy[k]) < _columnTop[i]) { + uint16 k = _myModLCNM[i][_columnIndex[i]]; + // ******* This is just so that the array can be indexed right now, will remove when myModLCNM is actually useable + k = 0; + // ***************************** + if ((rowY - kChrDy[k]) < _columnTop[i]) { break; } - if (_tIsBackground[k] == 0) { + if (kIsBackground[k] == 0) { // If it's a background tile, we already drew it (why is it in here then??) - if (_tChrMask[k] >= 0x8000) { + if (kChrMask[k] >= 0x8000) { // Right Mask, draw lower right hand corner (LRHC) drawLRHC(_myCNM[i][_columnIndex[i]], _columnTop[i], _columnX[i]); - } else if (_tChrMask[k] == 0) { + } else if (kChrMask[k] == 0) { // Floor or cover, draw the whole CHR drawSolid(_myCNM[i][_columnIndex[i]], _columnTop[i], _columnX[i]); @@ -274,7 +277,7 @@ void ImmortalEngine::drawItems() { } } _columnTop[i] += kChrH; - _columnIndex += (kViewPortCW + 1); + _columnIndex[i] += (kViewPortCW + 1); } } @@ -288,6 +291,12 @@ void ImmortalEngine::drawItems() { } while (n != _num2DrawItems); } +void ImmortalEngine::backspace() { + // Just moves the drawing position back by a char, and then draws an empty rect there (I think) + _penX -= 8; + //rect(_penX + 32, 40, 8, 16, 0); +} + void ImmortalEngine::printChr(char c) { // This draws a character from the font sprite table, indexed as an ascii char, using superSprite c &= kMaskASCII; // Grab just the non-extended ascii part diff --git a/engines/immortal/logic.cpp b/engines/immortal/logic.cpp index 52b3c425d655..d8191ae78814 100644 --- a/engines/immortal/logic.cpp +++ b/engines/immortal/logic.cpp @@ -23,6 +23,12 @@ namespace Immortal { +int ImmortalEngine::logicFreeze() { + // Very silly way of checking if the level is over and/or the game is over + int g = _gameOverFlag | _levelOver; + return (g ^ 1) >> 1; +} + void ImmortalEngine::logicInit() { _titlesShown = 0; _time = 0; @@ -58,7 +64,7 @@ void ImmortalEngine::restartLogic() { if (fromOldGame() == false) { _level = 0; - //levelNew(); + //levelNew(_level); } if (_level != 7) { @@ -96,8 +102,7 @@ void ImmortalEngine::logic() { _levelOver = false; if (_level == (_maxLevels-1)) { - //textPrint(kPrintYouWin); - debug("YOU WIN"); + textPrint(kStrYouWin); } else { //makeCertificate(); @@ -123,7 +128,7 @@ void ImmortalEngine::logic() { // If so, dim the screen _dim = 0; if ((_level == 0) && (/*_currentLevel.getShowRoom()*/0 == 0) && (/*roomLighted()*/false == false) && (/*getNumBullets()*/ 0 == 0)) { - _dim += 1; + //_dim += 1; } if (_level == 7) { @@ -166,6 +171,25 @@ void ImmortalEngine::trapKeys() { } } +int ImmortalEngine::keyOrButton() { + // Returns a key if a key was pressed, or 13 if a button was pressed + + int button = 0; + while (button == 0) { + getInput(); + switch (_pressedAction) { + case kActionKey: + button = _pressedAction; + case kActionFire: + case kActionButton: + button = 13; + default: + break; + } + } + return button; +} + void ImmortalEngine::doSingleStep() { /* This is a very cool debug routine. If you press the _singleStep key, * the engine enters this debug mode where it waits for another key press. @@ -194,7 +218,7 @@ void ImmortalEngine::updateHitGauge() { * what their health is. If the game considered the player unique, this would * probably just check a global 'health' variable instead. */ - //int h = _rooms[_currentRoom]._monsters[kPlayerID]._getHits(); + //int hits = _rooms[_currentRoom]._monsters[kPlayerID]._getHits(); int hits = 0; if (hits != _lastGauge) { // Update the mirror value if the health has changed since last frame @@ -246,11 +270,8 @@ void ImmortalEngine::drawGauge(int h) { } } -void ImmortalEngine::doGroan() { - //getRandom(); -} - -bool ImmortalEngine::printAnd(const Common::String s) { +bool ImmortalEngine::printAnd(Str s) { + // Only ever used by fromOldGame() // Just prints what it's given and then checks for input textPrint(s); getInput(); @@ -261,12 +282,16 @@ bool ImmortalEngine::printAnd(const Common::String s) { } bool ImmortalEngine::fromOldGame() { - /* + /* This is the basic load game routine (and also title display). + * It lets the user enter a password, or start a new game. + * Either way it sets up the inventory for the level, and also + * various object related things for the specific level. + */ if (_titlesShown == 0) { _titlesShown++; _dontResetColors = 1; - printAnd(kTitle0); - printAnd(kTitle4); + printAnd(kStrTitle0); + printAnd(kStrTitle4); getInput(); return false; } @@ -278,52 +303,260 @@ bool ImmortalEngine::fromOldGame() { } else { do { - if (!textPrint(kOldGameString)) { + if (!textPrint(kStrOldGame)) { // They choose not to load an old game return false; } - } while (getCertificate()); + } while (getCertificate() == true); if (_lastCertLen == 0) { return false; } } - _level = _cert + kCertLevel; - setGameFlags(((_cert + kCertHiGameFlags) << 4) | (_cert + kCertLoGameFlags)); - uint16 hits = _cert + kCertHits; - uint16 quick = _cert + kCertQuickness; - uint16 gold = ((_cert + kCertGoldHi) << 4) | (_cert + kCertGoldLo); + // Set game flags + _level = _certificate[kCertLevel]; + + setGameFlags((_certificate[kCertHiGameFlags] << 4) | _certificate[kCertLoGameFlags]); + + // Create the player + + //uint8 hits = _certificate[kCertHits]; + //uint8 quick = _certificate[kCertQuickness]; + //uint8 gold = (_certificate[kCertGoldHi] << 4) | _certificate[kCertGoldLo]; // monstMakePlayer(hits, quick, gold); <- will become room.makePlayer(); - uint8 tmp = 3; - uint8 flags = kObjIsRunning; - uint8 frame; - uint8 type; + // Create the inventory + // room.makeObject(3, kObjIsRunning, 0, goldType); + + // Hi bits of inventory + int certInv = _certificate[kCertInvHi]; + + if ((certInv & 1) != 0 ) { + if (_level < 2) { + //room.makeObject(3, 0, 0, waterType); + } + } + + if ((certInv & 2) != 0) { + //room.makeObject(3, 0, kRingFrame, dunRingType); + } - // room.makeObject(tmp, flags, gold, )*/ + if ((certInv & 4) != 0) { + if (_level < 6) { + //room.makeObject(3, 0, kSporesFrame, wormFoodType); + } + } + + if ((certInv & 8) != 0) { + //room.makeObject(3, 0, 0 (?), coinType); + } + + + // Low bits of inventory + certInv = _certificate[kCertInvLo]; + + // This would have been much more clean as a set of tables instead of a long branching tree + switch (_certificate[kCertLevel]) { + case 1: + if ((certInv & 2) != 0) { + //room.makeObject(3, 0, kSporesFrame, sporesType); + } + + if ((certInv & 4) != 0) { + //room.makeObject(3, 0, kSporesFrame, wowCharmType); + } + + break; + case 4: + if ((certInv & 2) != 0) { + //room.makeObject(3, kIsInvisible, kSporesFrame, coffeeType); + } + + break; + case 3: + if ((certInv & 1) != 0) { + //room.makeObject(3, kIsRunning, kRingFrame, faceRingType); + } + + break; + case 7: + if ((certInv & 1) != 0) { + //room.makeObject(6, kUsesFireButton, kSporesFrame, bronzeType); + } + + if ((certInv & 2) != 0) { + //room.makeObject(3, 0, kSporesFrame, tractorType); + } + + if ((certInv & 4) != 0) { + //room.makeObject(3, 0, kSporesFrame, antiType); + } + + default: + break; + } + //levelNew(_level) return true; } +void ImmortalEngine::calcCheckSum(int l, uint8 checksum[]) { + checksum[0] = 4; + checksum[1] = 0xa5; + + /* The game logic seems to allow a len of 4 (cmp 4 : bcc), + * but the checksum iny before it checks if the sizes are the same, + * so shouldn't a cert of len 4 cause it to loop 0xfffc times? + */ + for (int i = 4; i <= l; i++) { + checksum[0] = (_certificate[i] + checksum[0]) ^ checksum[1]; + checksum[1] = (_certificate[i] << 1) + checksum[1]; + } + + checksum[3] = checksum[1] >> 4; + checksum[2] = checksum[1] & 0xf; + checksum[1] = checksum[0] >> 4; + checksum[0] = checksum[0] & 0xf; +} + +bool ImmortalEngine::getCertificate() { + textPrint(kStrCertificate); + int certLen = 0; + bool entered = false; + int k = 0; + + // My goodness the logic for this is a mess. + while (entered == false) { + k = keyOrButton(); + if (k == 13) { + entered = true; + + } else if (k == 0x7f) { + // The input was a backspace + if (certLen != 0) { + // Length is one smaller now + // move the drawing position back and reprint the '-' char + certLen--; + backspace(); + backspace(); + printChr('-'); + } + + } else { + // The input was a key + + if (certLen != kMaxCertificate) { + if ((k >= 'a') && (k < '{')) { + k -= 0x20; + } + + if (k >= '0') { + if (k < ('9' + 1)) { + k -= '0'; + } + + else { + if (k < 'A') { + // Terrible, I know. But this seems to be the logic. + continue; + } + + if (k < ('F' + 1)) { + k -= ('A' - 10); + } + } + + int certK = k; + if ((k < ('Z' + 1)) && (k >= 'A')) { + k += ('a' - 'A'); + } + backspace(); + printChr(k); + printChr('-'); + _certificate[certLen] = certK; + certLen++; + } + } + } + } + + // Input of certificate is finished + if (certLen == 0) { + certLen = _lastCertLen; + } + if (certLen != 0) { + if (certLen < 4) { + textPrint(kStrBadCertificate); + return false; + } + uint8 checksum[4]; + calcCheckSum(certLen, checksum); + for (int i = 0; i < 4; i++) { + if (checksum[i] != _certificate[i]) { + textPrint(kStrBadCertificate); + return false; + } + } + } + + // Cert is good + _lastCertLen = certLen; + return true; +} + +void ImmortalEngine::printCertificate() { + /* In contrast to the other certificate routines, + * this one is nice and simple. You could also + * just add the appropriate offset for the letters, + * but grabbing it from a table is faster and doesn't + * use a lot of space (especially if it's used anywhere else). + * Why doesn't the game use rom table indexing like this more often? + */ + char toHex[] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}; + + textBeginning(kStrCertificate); + for (int i = 0; i < _lastCertLen; i++) { + printChr(toHex[_certificate[i]]); + } + textEnd(kStrCertificate2); +} + +bool ImmortalEngine::isSavedKing() { + if ((_gameFlags & kSavedKing) == 1) { + return true; + } else { + return false; + } +} + +bool ImmortalEngine::isSavedAna() { + if ((_gameFlags & kSavedAna) == 1) { + return true; + } else { + return false; + } +} + + +/* + * Functions that don't really need to be functions + */ + void ImmortalEngine::setGameFlags(uint16 f) { + _gameFlags = f; +} +uint16 ImmortalEngine::getGameFlags() { + return _gameFlags; } -// There's no way this routine needs to still be here. In fact I'm not sure it needed to be in the game anyway? int ImmortalEngine::getLevel() { return _level; } -int ImmortalEngine::logicFreeze() { - // Very silly way of checking if the level is over and/or the game is over - int g = _gameOverFlag | _levelOver; - return (g ^ 1) >> 1; -} - void ImmortalEngine::gameOverDisplay() { _themePaused = true; - //text_print(kGameOverString) - debug("GAME OVER"); + textPrint(kStrGameOver); } void ImmortalEngine::gameOver() { @@ -338,30 +571,20 @@ void ImmortalEngine::setSavedKing() { _gameFlags |= kSavedKing; } -bool ImmortalEngine::isSavedKing() { - if ((_gameFlags & kSavedKing) == 1) { - return true; - } else { - return false; - } -} - void ImmortalEngine::setSavedAna() { _gameFlags |= kSavedAna; } -bool ImmortalEngine::isSavedAna() { - if ((_gameFlags & kSavedAna) == 1) { - return true; - } else { - return false; - } -} -bool ImmortalEngine::getCertificate() { - return true; +/* + * Not relevant yet (music) + */ + +void ImmortalEngine::doGroan() { + //getRandom(); } + } // namespace Immortal diff --git a/engines/immortal/misc.cpp b/engines/immortal/misc.cpp index 8f49b2243633..39a865655587 100644 --- a/engines/immortal/misc.cpp +++ b/engines/immortal/misc.cpp @@ -57,13 +57,13 @@ void ImmortalEngine::myDelay() {} * */ -bool ImmortalEngine::textPrint(const Common::String s) { +bool ImmortalEngine::textPrint(Str s) { return true; } void ImmortalEngine::textSub() {} -void ImmortalEngine::textEnd() {} -void ImmortalEngine::textMiddle() {} -void ImmortalEngine::textBeginning() {} +void ImmortalEngine::textEnd(Str s) {} +void ImmortalEngine::textMiddle(Str s) {} +void ImmortalEngine::textBeginning(Str s) {} void ImmortalEngine::yesNo() {} diff --git a/engines/immortal/story.h b/engines/immortal/story.h new file mode 100644 index 000000000000..644bbb13bc69 --- /dev/null +++ b/engines/immortal/story.h @@ -0,0 +1,75 @@ +/* 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 . + * + */ + +#ifndef IMMORTAL_STORY_H +#define IMMORTAL_STORY_H + +namespace Immortal { + +enum ObjFlag : uint8 { + kObjUsesFireButton = 0x40, + kObjIsInvisible = 0x20, + kObjIsRunning = 0x10, + kObjIsChest = 0x08, + kObjIsOnGround = 0x04, + kObjIsF1 = 0x02, + kObjIsF2 = 0x01 +}; + +enum MonsterID { + kPlayerID +}; + +enum Str { + kStrOldGame, + kStrEnterCertificate, + kStrBadCertificate, + kStrCertificate, + kStrCertificate2, + kStrTitle0, + kStrTitle4, + kStrGold, + kStrYouWin, + kStrGameOver +}; + +struct Pickup { + //pointer to function + int _param; +}; + +struct Use { + //pointer to function + int _param; +}; + +struct ObjType { + Str _str; + Str _desc; + int _size; + Pickup _pickup; + Use _use; + Use _run; +}; + +} // namespace immortal + +#endif \ No newline at end of file From daa43ce02b56588c96a4e5eca164fdb0cc8a81f6 Mon Sep 17 00:00:00 2001 From: Quote58 Date: Sat, 30 Jul 2022 21:08:29 -0400 Subject: [PATCH 315/412] IMMORTAL: Space/tab formatting --- engines/immortal/compression.cpp | 2 +- engines/immortal/metaengine.cpp | 16 +++++++--------- engines/immortal/misc.cpp | 2 +- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/engines/immortal/compression.cpp b/engines/immortal/compression.cpp index aa0b2eae8cfd..0f39f6ff806e 100644 --- a/engines/immortal/compression.cpp +++ b/engines/immortal/compression.cpp @@ -1,4 +1,4 @@ - /* ScummVM - Graphic Adventure Engine +/* 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 diff --git a/engines/immortal/metaengine.cpp b/engines/immortal/metaengine.cpp index 1448f05a6631..95fcb9ece993 100644 --- a/engines/immortal/metaengine.cpp +++ b/engines/immortal/metaengine.cpp @@ -33,15 +33,13 @@ Common::Error ImmortalMetaEngine::createInstance(OSystem *syst, Engine **engine, } bool ImmortalMetaEngine::hasFeature(MetaEngineFeature f) const { - return false; -/* return - (f == kSavesUseExtendedFormat) || - (f == kSimpleSavesNames) || - (f == kSupportsListSaves) || - (f == kSupportsDeleteSave) || - (f == kSavesSupportMetaInfo) || - (f == kSavesSupportThumbnail) || - (f == kSupportsLoadingDuringStartup); */ + return (f == kSavesUseExtendedFormat) || + (f == kSimpleSavesNames) || + (f == kSupportsListSaves) || + (f == kSupportsDeleteSave) || + (f == kSavesSupportMetaInfo) || + (f == kSavesSupportThumbnail) || + (f == kSupportsLoadingDuringStartup); } #if PLUGIN_ENABLED_DYNAMIC(IMMORTAL) diff --git a/engines/immortal/misc.cpp b/engines/immortal/misc.cpp index 39a865655587..fadbb9f4d6f5 100644 --- a/engines/immortal/misc.cpp +++ b/engines/immortal/misc.cpp @@ -58,7 +58,7 @@ void ImmortalEngine::myDelay() {} */ bool ImmortalEngine::textPrint(Str s) { - return true; + return true; } void ImmortalEngine::textSub() {} void ImmortalEngine::textEnd(Str s) {} From a1b5ea7187d48cc3f7559d242ab5ab0addc57f97 Mon Sep 17 00:00:00 2001 From: Quote58 Date: Sun, 31 Jul 2022 18:38:18 -0400 Subject: [PATCH 316/412] IMMORTAL: Final two functions of Logic skeleton filled out (makecertificate() and miscinit()) --- engines/immortal/immortal.h | 9 ++-- engines/immortal/logic.cpp | 102 ++++++++++++++++++++++++++++++++---- engines/immortal/misc.cpp | 6 ++- 3 files changed, 102 insertions(+), 15 deletions(-) diff --git a/engines/immortal/immortal.h b/engines/immortal/immortal.h index 584e7dc0f778..3f86e6764dc3 100644 --- a/engines/immortal/immortal.h +++ b/engines/immortal/immortal.h @@ -202,7 +202,7 @@ class ImmortalEngine : public Engine { const int kNiceTime = 36; const int kMaxCertificate = 16; - // this should really be a char array, but inserting frame values will be stupid so it's just a string instead + // This should really be a char array, but inserting frame values will be stupid so it's just a string instead const Common::String genStr[11] = {"New game?%", "Enter certificate:&-=", "Invalid certificate.@", "End of level!&Here is your certificate:&&=", "&@", " Electronic Arts presents&& The Immortal&&&&  1990 Will Harvey|]]]]]]]]]=", // Might need \ for something @@ -469,6 +469,7 @@ class ImmortalEngine : public Engine { int logicFreeze(); // Overcomplicated way to check if game over or level over void updateHitGauge(); void drawGauge(int h); + void makeCertificate(); void calcCheckSum(int l, uint8 checksum[]); // Checksum is one word, but the source called it CheckSum bool getCertificate(); void printCertificate(); @@ -526,10 +527,10 @@ class ImmortalEngine : public Engine { Common::SeekableReadStream *unCompress(Common::File *src, int srcLen); // Subroutines called by unCompress - void setupDictionary(uint16 start[], uint16 ptk[], uint16 &findEmpty); - int getInputCode(bool &carry, Common::File *src, int &srcLen, uint16 &evenOdd); + void setupDictionary(uint16 start[], uint16 ptk[], uint16 &findEmpty); + int getInputCode(bool &carry, Common::File *src, int &srcLen, uint16 &evenOdd); uint16 getMember(uint16 codeW, uint16 k, uint16 &findEmpty, uint16 start[], uint16 ptk[]); - void appendList(uint16 codeW, uint16 k, uint16 &hash, uint16 &findEmpty, uint16 start[], uint16 ptk[], uint16 &tmp); + void appendList(uint16 codeW, uint16 k, uint16 &hash, uint16 &findEmpty, uint16 start[], uint16 ptk[], uint16 &tmp); /* diff --git a/engines/immortal/logic.cpp b/engines/immortal/logic.cpp index d8191ae78814..2a577a1e1698 100644 --- a/engines/immortal/logic.cpp +++ b/engines/immortal/logic.cpp @@ -44,7 +44,7 @@ void ImmortalEngine::restartLogic() { _gameFlags = kSavedNone; // Here's where the majority of the game actually gets initialized - //miscInit(); + miscInit(); //qarrayInit(); //cycInit(); <-- room.initCycles() //fsetInit(); <-- room.initTorches() @@ -105,11 +105,8 @@ void ImmortalEngine::logic() { textPrint(kStrYouWin); } else { - //makeCertificate(); - //printCertificate(); - if (_level == 0) { - //manual2(); // <- debug? - } + makeCertificate(); + printCertificate(); _promoting = 1; } _restart = true; @@ -400,6 +397,93 @@ bool ImmortalEngine::fromOldGame() { return true; } +void ImmortalEngine::makeCertificate() { + /* The code for this bit doesn't really make sense, + * so I will write it as it is, but I am noting here + * that it should be: + * jsr monst_getGold : ... sta certificate+certgoldhi + * jsr monst_getQuickness : sta certificate+certquickness + * instead of getquickness : get gold : sta gold : sta quickness + * also no need to ldx 0 since this is player only ram right? + */ + + //uint8 q = room._playerQuickness + //uint16 g = room._playerGold + uint16 g = 0; + + _certificate[kCertGoldLo] = g & 0xf; + _certificate[kCertGoldHi] = g >> 4; + _certificate[kCertQuickness] = g >> 4; // Should actually be = q, but this is what the game does + + _certificate[kCertHits] = 0; //room._playerHits + _certificate[kCertLoGameFlags] = getGameFlags() & 0xf; + _certificate[kCertLoGameFlags] = getGameFlags() >> 4; + + _certificate[kCertLevel] = _level + 1; + _certificate[kCertInvLo] = 0; + _certificate[kCertInvHi] = 0; + + if (true/*room.monster[kPlayerID].hasObject(waterType)*/) { + _certificate[kCertInvHi] |= 1; + } + + if (true/*room.monster[kPlayerID].hasObject(dunRingType)*/) { + _certificate[kCertInvHi] |= 2; + } + + if (true/*room.monster[kPlayerID].hasObject(wormFoodType)*/) { + _certificate[kCertInvHi] |= 4; + } + + if (true/*room.monster[kPlayerID].hasObject(coinType)*/) { + _certificate[kCertInvHi] |= 8; + } + + // The lo byte of the inventory is used for items that only exist on a specific level, and are removed after + switch (_certificate[kCertLevel]) { + case 1: + if (true/*room.monster[kPlayerID].hasObject(sporesType)*/) { + _certificate[kCertInvLo] |= 2; + } + + if (true/*room.monster[kPlayerID].hasObject(wowCharmType)*/) { + _certificate[kCertInvLo] |= 4; + } + + case 3: + if (true/*room.monster[kPlayerID].hasObject(faceRingType)*/) { + _certificate[kCertInvLo] |= 1; + } + + case 4: + if (true/*room.monster[kPlayerID].hasObject(coffeeType)*/) { + _certificate[kCertInvLo] |= 2; + } + + case 7: + if (true/*room.monster[kPlayerID].hasObject(bronzeType)*/) { + _certificate[kCertInvLo] |= 1; + } + + if (true/*room.monster[kPlayerID].hasObject(tractorType)*/) { + _certificate[kCertInvLo] |= 2; + } + + if (true/*room.monster[kPlayerID].hasObject(antiType)*/) { + _certificate[kCertInvLo] |= 4; + } + + default: + _lastCertLen = 13; + uint8 checksum[4]; + calcCheckSum(_lastCertLen, checksum); + _certificate[0] = checksum[0]; + _certificate[1] = checksum[1]; + _certificate[2] = checksum[2]; + _certificate[3] = checksum[3]; + } +} + void ImmortalEngine::calcCheckSum(int l, uint8 checksum[]) { checksum[0] = 4; checksum[1] = 0xa5; @@ -434,10 +518,8 @@ bool ImmortalEngine::getCertificate() { } else if (k == 0x7f) { // The input was a backspace if (certLen != 0) { - // Length is one smaller now - // move the drawing position back and reprint the '-' char - certLen--; - backspace(); + certLen--; // Length is one smaller now + backspace(); // move the drawing position back and reprint the '-' char backspace(); printChr('-'); } diff --git a/engines/immortal/misc.cpp b/engines/immortal/misc.cpp index fadbb9f4d6f5..379e2571c1c1 100644 --- a/engines/immortal/misc.cpp +++ b/engines/immortal/misc.cpp @@ -43,7 +43,11 @@ void ImmortalEngine::delay8(int j) { // 1/8 jiffies are 7.02ms g_system->delayMillis(j * 7); } -void ImmortalEngine::miscInit() {} +void ImmortalEngine::miscInit() { + // In the source, this is where the seed for the rng is set, but we don't need to do that as we used _randomSource + _lastGauge = 0; +} + void ImmortalEngine::setRandomSeed() {} void ImmortalEngine::getRandom() {} void ImmortalEngine::myDelay() {} From 09078a9de521e1825e1ea4ac9ef240779e9007a9 Mon Sep 17 00:00:00 2001 From: Quote58 Date: Sun, 31 Jul 2022 18:39:44 -0400 Subject: [PATCH 317/412] IMMORTAL: MonsterID enum moved to immortal.h --- engines/immortal/immortal.h | 4 ++++ engines/immortal/story.h | 4 ---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/engines/immortal/immortal.h b/engines/immortal/immortal.h index 3f86e6764dc3..d56022d9bcec 100644 --- a/engines/immortal/immortal.h +++ b/engines/immortal/immortal.h @@ -111,6 +111,10 @@ enum InputDirection { kDirectionRight }; +enum MonsterID { + kPlayerID +}; + enum CertIndex : uint8 { kCertHits, kCertLevel, diff --git a/engines/immortal/story.h b/engines/immortal/story.h index 644bbb13bc69..bfd5d5435e7c 100644 --- a/engines/immortal/story.h +++ b/engines/immortal/story.h @@ -34,10 +34,6 @@ enum ObjFlag : uint8 { kObjIsF2 = 0x01 }; -enum MonsterID { - kPlayerID -}; - enum Str { kStrOldGame, kStrEnterCertificate, From 8ecffca96630f151dc7ac82be7dcb099a6433ae0 Mon Sep 17 00:00:00 2001 From: Quote58 Date: Sat, 6 Aug 2022 21:25:24 -0400 Subject: [PATCH 318/412] IMMORTAL: Add level skeleton --- engines/immortal/immortal.h | 112 ++++++++++++++++------- engines/immortal/kernal.cpp | 6 +- engines/immortal/level.cpp | 175 ++++++++++++++++++++++++++++++++++++ engines/immortal/logic.cpp | 10 +-- engines/immortal/module.mk | 4 +- engines/immortal/story.h | 15 ++++ 6 files changed, 281 insertions(+), 41 deletions(-) create mode 100644 engines/immortal/level.cpp diff --git a/engines/immortal/immortal.h b/engines/immortal/immortal.h index d56022d9bcec..913e6d2fac7f 100644 --- a/engines/immortal/immortal.h +++ b/engines/immortal/immortal.h @@ -115,6 +115,12 @@ enum MonsterID { kPlayerID }; +enum LevelType { + kRoomType, + kMonsterType, + kObjectType +}; + enum CertIndex : uint8 { kCertHits, kCertLevel, @@ -206,15 +212,16 @@ class ImmortalEngine : public Engine { const int kNiceTime = 36; const int kMaxCertificate = 16; + // Max strings = 250 // This should really be a char array, but inserting frame values will be stupid so it's just a string instead - const Common::String genStr[11] = {"New game?%", "Enter certificate:&-=", "Invalid certificate.@", - "End of level!&Here is your certificate:&&=", "&@", - " Electronic Arts presents&& The Immortal&&&&  1990 Will Harvey|]]]]]]]]]=", // Might need \ for something - " written by&& Will Harvey& Ian Gooding& Michael Marcantel& Brett G. Durrett& Douglas Fulton|]]]]]]]/=", - "#" + Common::String(kGoldBigFrame) + "$0 gold@", - "Congratulations!&&Play again?@", - "Enter certificate:&-=", - "Game Over&&Play again?@"}; + const Common::String stringPtrs[250] = {"New game?%", "Enter certificate:&-=", "Invalid certificate.@", + "End of level!&Here is your certificate:&&=", "&@", + " Electronic Arts presents&& The Immortal&&&&  1990 Will Harvey|]]]]]]]]]=", // Might need \ for something + " written by&& Will Harvey& Ian Gooding& Michael Marcantel& Brett G. Durrett& Douglas Fulton|]]]]]]]/=", + "#" + Common::String(kGoldBigFrame) + "$0 gold@", + "Congratulations!&&Play again?@", + "Enter certificate:&-=", + "Game Over&&Play again?@"}; // Screen constants const int kResH = 320; @@ -288,6 +295,10 @@ class ImmortalEngine : public Engine { const char kGaugeStop = 1; // Literally just means the final kGaugeOn char to draw const char kGaugeStart = 1; // First kGaugeOn char to draw + // Level constants + const int kMaxFilesPerLevel = 16; + const int kMaxPartInstances = 4; + const int kLevelToMaze[8] = {0,0,1,1,2,2,2,3}; /* * 'global' members @@ -311,6 +322,24 @@ class ImmortalEngine : public Engine { int _maxLevels = 0; // This is determined when loading in story files int _level = 0; bool _levelOver = false; + int _count; + int _lastLevelLoaded; + int _lastSongLoaded; + int _storyLevel; + int _storyX; + int _loadA; + int _loadY; + uint16 _initialX; + uint16 _initialY; + int _initialBX; + int _initialBY; + int _dRoomNum; + int _initialRoom; + int _currentRoom; + int _lastType; + int _roomCellX; + int _roomCellY; + Story _stories[8]; Room *_rooms[kMaxRooms]; // Rooms within the level // Debug members @@ -404,6 +433,7 @@ class ImmortalEngine : public Engine { void playMazeSong(); void playCombatSong(); void doGroan(); + void stopMusic(); void musicPause(int sID); void musicUnPause(int sID); void loadSingles(Common::String songName); // Loads and then parse the maze song @@ -447,14 +477,22 @@ class ImmortalEngine : public Engine { /* - * [Sprites.cpp] Functions from Sprites.GS and spriteList.GS + * [DrawChr.cpp] Functions from DrawChr.cpp */ - // Init - void initDataSprite(Common::SeekableReadStream *f, DataSprite *d, int index, uint16 cenX, uint16 cenY); // Initializes the data sprite - // Main - void superSprite(int s, uint16 x, uint16 y, Frame f, int bmw, byte *dst, int sT, int sB); + int mungeCBM(int numChrs); + void storeAddr(); + void mungeSolid(); + void mungeLRHC(); + void mungeLLHC(); + void mungeULHC(); + void mungeURHC(); + void drawSolid(int chr, int x, int y); + void drawULHC(int chr, int x, int y); + void drawURHC(int chr, int x, int y); + void drawLLHC(int chr, int x, int y); + void drawLRHC(int chr, int x, int y); /* @@ -523,6 +561,34 @@ class ImmortalEngine : public Engine { void insideRect(int p, int r); + /* + * [Level.cpp] Functions from level.GS + */ + // Init + void levelInitAtStartOfGameOnly(); + void levelInit(); + + // Main + void levelStory(int l); + void levelLoadFile(int l); + void levelNew(int l); + void levelDrawAll(); + void levelShowRoom(int r, int bX, int bY); + bool levelIsShowRoom(int r); + bool levelIsLoaded(int l); + void univAtNew(int l); + + /* + * [Sprites.cpp] Functions from Sprites.GS and spriteList.GS + */ + + // Init + void initDataSprite(Common::SeekableReadStream *f, DataSprite *d, int index, uint16 cenX, uint16 cenY); // Initializes the data sprite + + // Main + void superSprite(int s, uint16 x, uint16 y, Frame f, int bmw, byte *dst, int sT, int sB); + + /* * [Compression.cpp] Functions from Compression.GS */ @@ -543,26 +609,6 @@ class ImmortalEngine : public Engine { // Misc - - /* - * [DrawChr.cpp] Functions from DrawChr.cpp - */ - - // Main - int mungeCBM(int numChrs); - void storeAddr(); - void mungeSolid(); - void mungeLRHC(); - void mungeLLHC(); - void mungeULHC(); - void mungeURHC(); - void drawSolid(int chr, int x, int y); - void drawULHC(int chr, int x, int y); - void drawURHC(int chr, int x, int y); - void drawLLHC(int chr, int x, int y); - void drawLRHC(int chr, int x, int y); - - /* * --- ScummVM general engine Functions --- * diff --git a/engines/immortal/kernal.cpp b/engines/immortal/kernal.cpp index 79b15bfb514e..50f9fa16cafd 100644 --- a/engines/immortal/kernal.cpp +++ b/engines/immortal/kernal.cpp @@ -846,7 +846,11 @@ void ImmortalEngine::loadSingles(Common::String songName) { debug("%s", songName.c_str()); } - +void ImmortalEngine::stopMusic() { + //musicStop(-1) + _playing = kSongNothing; + //stopSound(); +} } // namespace Immortal diff --git a/engines/immortal/level.cpp b/engines/immortal/level.cpp new file mode 100644 index 000000000000..878bbf0c5dc2 --- /dev/null +++ b/engines/immortal/level.cpp @@ -0,0 +1,175 @@ +/* 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 "immortal/immortal.h" + +namespace Immortal { + +void ImmortalEngine::levelInitAtStartOfGameOnly() { + _lastLevelLoaded = -1; + _lastSongLoaded = -1; +} + +void ImmortalEngine::levelInit() { + _count = 0; +} + +void ImmortalEngine::levelNew(int l) { + stopMusic(); + clearScreen(); + /* commented out in the source for some reason? */ + for (int i = 0; i < kMaxRooms; i++) { + //_rooms[i].delete(); + } + + levelStory(l); + if (kLevelToMaze[l] != _lastLevelLoaded) { + _lastLevelLoaded = kLevelToMaze[l]; + //loadMaze(l); + } + + if (_level != _lastSongLoaded) { + //loadSong(l); + } + + //startMusic(); + //monstSetXY -> _rooms[_currentRoom].monsters[kPlayerID].setXY(_initialBX, _initialBY); + + //univSetXY(_initialX << 3, _initialY << 3); + + levelShowRoom(_initialRoom, _initialBX, _initialBY); +} + +void ImmortalEngine::levelStory(int l) { + levelLoadFile(l); +} + +//loadStoryFiles() {} + +void ImmortalEngine::levelLoadFile(int l) { + /* Originally, this searched through story.gs and ignored the data entries. + * However, we have the STR entries separate from the story entries, so + * we can just index the story files array directly. + * It also used a 16 byte buffer to read in a story entry, but again this + * is equivalent to the overhead of reading the array entry I think. + */ + + _dRoomNum = 0; + bool done = false; + int type = 0;//story[l]; + + // instead of switch statement, just make a room for each, because the rooms will have the relevant info + + // Once again, would be better as an indexed JSR instead of a set of comparisons and branches + while (done == false) { + switch (type & kOPMaskRecord) { + case kOPMaskRoom: +// roomNew(); + break; + case kOPMaskInRoom: +// inRoomNew(); + break; + case kOPMaskFlame: +// fsetNew(); + break; + case kOPMaskUnivAt: + univAtNew(l); + break; + case kOPMaskMonster: +// monstNew(); + break; + case kOPMaskDoor: +// doorNew(); + break; + case kOPMaskObject: +// objectNew(); + break; + default: + done = true; + } + } +} + +void ImmortalEngine::univAtNew(int l) { + _initialRoom = _dRoomNum; + _initialX = 0;//_stories[l]._initialX; + _initialY = 0;//_stories[l]._initialY; + _initialBX = 0;//_stories[l]._initialBX; + _initialBY = 0;//_stories[l]._initialBY; + //doorToNextLevel(_stories[l]._doorToNextLevel, _initialBX, _initialBY); + //doorSetLadders(_stories[l]._doorSetLadders); + //roomSetHole(_stories[l]._setHole, _stories[l]._setHoleX, _stories[l]._setHoleY); + //monstRepos(kPlayerID); + +} + +void ImmortalEngine::levelDrawAll() { + _count++; + //univAutoCenter(); + clearSprites(); + //rooms[_currentRoom].drawContents(); +} + +void ImmortalEngine::levelShowRoom(int r, int bX, int bY) { + _currentRoom = r; + //univSetRoom(r, bX, bY); + //fset, spark, bullet, and door get set to the current room + //roomGetCell(r, bX, bY); + //x, y <- roomGetXY(r, bX, bY); + //x += bX; + //y += bY; + //x <<= 1; + //blister(); +} + +bool ImmortalEngine::levelIsLoaded(int l) { + if (l == _storyLevel) { + return true; + } + return false; +} + +bool ImmortalEngine::levelIsShowRoom(int r) { + if (r == _currentRoom) { + return true; + } + return false; +} + +} // namespace immortal + + + + + + + + + + + + + + + + + + diff --git a/engines/immortal/logic.cpp b/engines/immortal/logic.cpp index 2a577a1e1698..ebeea26369a1 100644 --- a/engines/immortal/logic.cpp +++ b/engines/immortal/logic.cpp @@ -34,7 +34,7 @@ void ImmortalEngine::logicInit() { _time = 0; _promoting = 0; _restart = true; - //level_initAtStartOfGameOnly + levelInitAtStartOfGameOnly(); _lastCertLen = 0; } @@ -48,7 +48,7 @@ void ImmortalEngine::restartLogic() { //qarrayInit(); //cycInit(); <-- room.initCycles() //fsetInit(); <-- room.initTorches() - //levelInit(); <-- presumably creates room + levelInit(); //roomInit(); <-- will be run in constructor of room //monstInit(); <-- room.initMonsters() \ //objectInit(); <-- room.initObjects() @@ -64,7 +64,7 @@ void ImmortalEngine::restartLogic() { if (fromOldGame() == false) { _level = 0; - //levelNew(_level); + levelNew(_level); } if (_level != 7) { @@ -118,7 +118,7 @@ void ImmortalEngine::logic() { //monstRunAll(); //objectRunAll(); //doInfiniteHallways(); - //levelDrawAll(); + levelDrawAll(); updateHitGauge(); // What the heck? Check if we are in level 0: room 0, with no lit torches, and no projectiles @@ -393,7 +393,7 @@ bool ImmortalEngine::fromOldGame() { default: break; } - //levelNew(_level) + levelNew(_level); return true; } diff --git a/engines/immortal/module.mk b/engines/immortal/module.mk index 18b5dfdf28b8..db9aab28f489 100644 --- a/engines/immortal/module.mk +++ b/engines/immortal/module.mk @@ -10,9 +10,9 @@ MODULE_OBJS = \ compression.o \ misc.o \ cycle.o \ - drawChr.o + drawChr.o \ + level.o -# level.o \ # universe.o \ # room.o \ # object.o \ diff --git a/engines/immortal/story.h b/engines/immortal/story.h index bfd5d5435e7c..42f0d009ea8c 100644 --- a/engines/immortal/story.h +++ b/engines/immortal/story.h @@ -24,6 +24,17 @@ namespace Immortal { +enum OPMask : uint8 { + kOPMaskRoom, + kOPMaskInRoom, + kOPMaskFlame, + kOPMaskUnivAt, + kOPMaskMonster, + kOPMaskDoor, + kOPMaskObject, + kOPMaskRecord +}; + enum ObjFlag : uint8 { kObjUsesFireButton = 0x40, kObjIsInvisible = 0x20, @@ -47,6 +58,10 @@ enum Str { kStrGameOver }; +struct Story { + int x; +}; + struct Pickup { //pointer to function int _param; From 8516b39aa1a50722b74a03526f87d6b222d7d687 Mon Sep 17 00:00:00 2001 From: Quote58 Date: Sun, 7 Aug 2022 06:48:45 -0400 Subject: [PATCH 319/412] IMMORTAL: Add story.cpp and related additions to story.h --- engines/immortal/immortal.h | 32 +++++-- engines/immortal/level.cpp | 3 +- engines/immortal/module.mk | 3 +- engines/immortal/story.cpp | 137 +++++++++++++++++++++++++++++ engines/immortal/story.h | 171 ++++++++++++++++++++++++++++++++++-- 5 files changed, 329 insertions(+), 17 deletions(-) create mode 100644 engines/immortal/story.cpp diff --git a/engines/immortal/immortal.h b/engines/immortal/immortal.h index 913e6d2fac7f..3296f741ea4f 100644 --- a/engines/immortal/immortal.h +++ b/engines/immortal/immortal.h @@ -87,13 +87,22 @@ enum ChrMask : uint16 { }; enum Screen { // These are constants that are used for defining screen related arrays - kMaxRooms = 16, // Should probably put this in a different enum kMaxSprites = 32, // Number of sprites allowed at once kViewPortCW = 256 / 64, kViewPortCH = 128 / kMaxSprites, kMaxDrawItems = kViewPortCH + 1 + kMaxSprites }; +enum StoryMaxes { + kMaxRooms = 16, + kMaxDoors = 10, + kMaxFlames = 32, + kMaxFlamesInRoom = 5, + kMaxObjects = 42, + kMaxMonsters = 20, + kMaxGenSprites = 6 +}; + enum InputAction { kActionNothing, kActionKey, @@ -141,9 +150,9 @@ enum Song { }; enum GameFlags : uint8 { - kSavedNone = 0, - kSavedKing = 1, - kSavedAna = 2 + kSavedNone, + kSavedKing, + kSavedAna }; struct Frame { @@ -222,7 +231,6 @@ class ImmortalEngine : public Engine { "Congratulations!&&Play again?@", "Enter certificate:&-=", "Game Over&&Play again?@"}; - // Screen constants const int kResH = 320; const int kResV = 200; @@ -296,9 +304,10 @@ class ImmortalEngine : public Engine { const char kGaugeStart = 1; // First kGaugeOn char to draw // Level constants + const int kStoryNull = 5; const int kMaxFilesPerLevel = 16; const int kMaxPartInstances = 4; - const int kLevelToMaze[8] = {0,0,1,1,2,2,2,3}; + const int kLevelToMaze[8] = {0,0,1,1,2,2,2,3}; /* * 'global' members @@ -318,6 +327,9 @@ class ImmortalEngine : public Engine { int _promoting = 0; // I think promoting means the title stuff bool _restart = false; + // Story members + Story _stories[8]; + // Level members int _maxLevels = 0; // This is determined when loading in story files int _level = 0; @@ -339,7 +351,6 @@ class ImmortalEngine : public Engine { int _lastType; int _roomCellX; int _roomCellY; - Story _stories[8]; Room *_rooms[kMaxRooms]; // Rooms within the level // Debug members @@ -578,6 +589,13 @@ class ImmortalEngine : public Engine { bool levelIsLoaded(int l); void univAtNew(int l); + + /* + * [Story.cpp] Functions from Story.cpp + */ + // Init + void loadStoryFiles(); + /* * [Sprites.cpp] Functions from Sprites.GS and spriteList.GS */ diff --git a/engines/immortal/level.cpp b/engines/immortal/level.cpp index 878bbf0c5dc2..1569990829dd 100644 --- a/engines/immortal/level.cpp +++ b/engines/immortal/level.cpp @@ -24,6 +24,7 @@ namespace Immortal { void ImmortalEngine::levelInitAtStartOfGameOnly() { + loadStoryFiles(); _lastLevelLoaded = -1; _lastSongLoaded = -1; } @@ -62,8 +63,6 @@ void ImmortalEngine::levelStory(int l) { levelLoadFile(l); } -//loadStoryFiles() {} - void ImmortalEngine::levelLoadFile(int l) { /* Originally, this searched through story.gs and ignored the data entries. * However, we have the STR entries separate from the story entries, so diff --git a/engines/immortal/module.mk b/engines/immortal/module.mk index db9aab28f489..6c460cff60a8 100644 --- a/engines/immortal/module.mk +++ b/engines/immortal/module.mk @@ -11,7 +11,8 @@ MODULE_OBJS = \ misc.o \ cycle.o \ drawChr.o \ - level.o + level.o \ + story.o # universe.o \ # room.o \ diff --git a/engines/immortal/story.cpp b/engines/immortal/story.cpp new file mode 100644 index 000000000000..a32b149c3a98 --- /dev/null +++ b/engines/immortal/story.cpp @@ -0,0 +1,137 @@ +/* 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 . + * + */ + +/* [Alternate Name: Level Subsystem/Script Data] + * --- Story File --- + * A story file (as defined in story.h) is a set of ROM + * data that describes the properties of a level. This includes + * the coordinates for each room, the doors in the level, + * the torches, objects, monsters, etc. It also included the string + * data in the source code, but technically it was writing those + * strings to a separate string bank, so they weren't contiguous + * with the story files. These story files are read in when loading + * a new level, and are used to construct the room object, the monster + * objects, and everything in the rooms. + */ + +#include "immortal/immortal.h" + +namespace Immortal { + +void ImmortalEngine::loadStoryFiles() { + /* The way I am doing this, there will be essentially duplicate data + * for the in-room objects. This is because the original also + * effectively duplicated data. There was less overhead of course, + * as these structs are considered classes by c++. However I think + * that logically speaking, this is what the original was doing. + * It's not ideal to do it this way, but my guess for why the source + * didn't just read directly (ex. door object data will never change, + * it is ROM) is that the story bank was too far from the general work + * memory used for the object data. Could be something else though. + */ + + // Level 0: Intro 1 + + _stories[0]._levelNum = 0; // These aren't really needed anymore + _stories[0]._partNum = 1; + + int univRoom = 4; // The room the player starts in when beginning this level + uint8 univRoomX = 512; + uint8 univRoomY = 416; + int byteArray[] = {-1, -1, kStoryNull, 2, 0, univRoom, (704 / 64),(544 / 32)}; + _stories[0]._UnivAt = UnivAt(1024 / 8, 480 / 8, (1152 - univRoomX) / 2, 464 - univRoomY, byteArray); + + // All of the rooms for level 0 + SRoom rooms[8] = {SRoom(384, 256, kRoomFlag0), SRoom(512, 64, kRoomFlag0), SRoom(640, 160, kRoomFlag0), SRoom(768, 224, kRoomFlag0), + SRoom(univRoomX, univRoomY, kRoomFlag0), SRoom(960, 512, kRoomFlag0), SRoom(1024, 352, kRoomFlag0), SRoom(896, 64, kRoomFlag0)}; + _stories[0]._rooms = rooms; + + // All of the doors for level 0 + SDoor doors[7] = {SDoor(kLeft, 704, 224, 0, 2, false), SDoor(kRight, 576, 352, 4, 0, true), + SDoor(kRight, 704,96, 2, 1, false), SDoor(kRight, 960,128, 7, 2, false), + SDoor(kRight, 1088,160, 3, 7, false), SDoor(kRight, 1088,320, 6, 3, false), + SDoor(kRight, 896,416, 4, 3, false)}; + _stories[0]._doors = doors; + + // All of the flames for level 0 + // Macro for flames is (x - roomx), (y - roomy), pattern number + SFlame f5[2] = {SFlame(512 - 384, (240 + 32) - 256, kFlameOff), SFlame(672 - 384, (240 + 32) - 256, kFlameOff)}; + SFlame f7[3] = {SFlame(576 - 384, (112 + 32) - 256, kFlameNormal), SFlame(576 - 384, (112 + 32) - 256, kFlameNormal), SFlame(928 - 384, (48 + 32) - 256, kFlameNormal)}; + SFlame f8[1] = {SFlame(800 - 640, (144 + 32) - 160, kFlameNormal)}; + SFlame f9[3] = {SFlame(768 - 768, (304 + 32) - 224, kFlameNormal), SFlame((928 - 768), (304 + 32) - 224, kFlameNormal), SFlame((1024 - 768), (240 + 32) - 224, kFlameNormal)}; + SFlame fA[3] = {SFlame(672 - 512, (400 + 32) - 416, kFlameNormal), SFlame((800 - 64) - 512, (496 - 32) - 416, kFlameNormal), SFlame(576 - 512, (528 + 32) - 416, kFlameNormal)}; + SFlame fD[1] = {SFlame(1024 - 960, (496 + 32) - 512, kFlameNormal)}; + SFlame fE[1] = {SFlame(1184 - 1024, 432 - 352, kFlameCandle)}; + SFlame fF[1] = {SFlame(1024 - 896, (144 + 32) - 64, kFlameNormal)}; + SFlame *flames[8] = {f5, f7, f8, f9, fA, fD, fE, fF}; + _stories[0]._flames = flames; + + // All of the objects for level 0 + SObj o5[3]; + SObj o7[1]; + SObj o8[1]; + SObj o9[9]; + SObj oE[4]; + SObj *objects[8] = {o5, o7, o8, o9, nullptr, nullptr, oE, nullptr}; + _stories[0]._objects = objects; + + // All of the monsters for level 0 + SMonster m5[2]; + SMonster m9[3]; + SMonster mE[1]; + SMonster mF[1]; + SMonster *monsters[8] = {m5, nullptr, nullptr, m9, nullptr, nullptr, mE, mF}; + _stories[0]._monsters = monsters; +} + +} // namespace Immortal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/engines/immortal/story.h b/engines/immortal/story.h index 42f0d009ea8c..3524a3c32700 100644 --- a/engines/immortal/story.h +++ b/engines/immortal/story.h @@ -24,6 +24,25 @@ namespace Immortal { +enum DoorDir : bool { + kLeft = false, + kRight = true +}; + +enum RoomFlag : uint8 { + kRoomFlag0 = 0x1, + kRoomFlag1 = 0x2, + kRoomFlag2 = 0x4, + kRoomFlag3 = 0x8 +}; + +enum FPattern { + kFlameNormal, + kFlameCandle, + kFlameOff, + kFlameGusty +}; + enum OPMask : uint8 { kOPMaskRoom, kOPMaskInRoom, @@ -45,6 +64,22 @@ enum ObjFlag : uint8 { kObjIsF2 = 0x01 }; +enum MonsterFlag : uint8 { + kMonstIsTough = 0x10, + kMonstIsDead = 0x20, + kMonstIsPoss = 0x40, + kMonstIsBaby = 0x40, + kMonstIsEngage = 0x80 +}; + +enum IsA : uint8 { + kIsAF1 = 0x20, + kIsAF2 = 0x40 +}; + +enum Program { // This will likely be moved to a monster ai specific file later +}; + enum Str { kStrOldGame, kStrEnterCertificate, @@ -55,11 +90,7 @@ enum Str { kStrTitle4, kStrGold, kStrYouWin, - kStrGameOver -}; - -struct Story { - int x; + kStrGameOver, }; struct Pickup { @@ -76,11 +107,137 @@ struct ObjType { Str _str; Str _desc; int _size; - Pickup _pickup; + Pickup _pickup; Use _use; Use _run; }; + +/* Strictly speaking, many of these structs (which were rom data written dynamically + * with compiler macros) combine multiple properties into single bytes (ex. room uses + * bits 0-2 of X to also hold the roomOP, and bits 0-2 of Y to hold flags). However + * for the moment there's no need to replicate this particular bit of space saving. + */ +struct SRoom { + uint8 _x; + uint8 _y; + RoomFlag _flags; + SRoom() {} + SRoom(uint8 x, uint8 y, RoomFlag f) { + _x = x; + _y = y; + _flags = f; + } +}; + +struct SDoor { + DoorDir _dir; + uint8 _x; + uint8 _y; + uint8 _fromRoom; + uint8 _toRoom; + bool _isLocked; + SDoor() {} + SDoor(DoorDir d, uint8 x, uint8 y, uint8 f, uint8 t, bool l) { + _dir = d; + _x = x; + _y = y; + _fromRoom = f; + _toRoom = t; + _isLocked = l; + } +}; + +struct SFlame { + uint8 _x; + uint8 _y; + FPattern _pattern; + SFlame() {} + SFlame(uint8 x, uint8 y, FPattern p) { + _x = x; + _y = y; + _pattern = p; + } +}; + +struct UnivAt { + uint8 _initialUnivX; + uint8 _initialUnivY; + uint8 _playerPointX; + uint8 _playerPointY; + int *_ladders; + UnivAt() {} + UnivAt(uint8 iX, uint8 iY, uint8 pX, uint8 pY, int l[]) { + _initialUnivX = iX; + _initialUnivY = iY; + _playerPointX = pX; + _playerPointY = pY; + _ladders = l; + } +}; + +struct SObj { + uint8 _x; + uint8 _y; + ObjType _type; + ObjFlag _flags; + uint8 _tmp; +SpriteFrame _frame; + SObj() {} + SObj(uint8 x, uint8 y, ObjType t, ObjFlag f, uint8 tmp, SpriteFrame s) { + _x = x; + _y = y; + _type = t; + _flags = f; + _tmp = tmp; + _frame = s; + } +}; + +struct SMonster { + uint8 _x; + uint8 _y; + uint8 _hits; + uint8 _madAt; + IsA _isA; + Program _program; + SpriteName _sprite; +MonsterFlag _flags; + SMonster() {} + SMonster(uint8 x, uint8 y, uint8 h, uint8 m, IsA i, Program p, SpriteName s, MonsterFlag mf) { + _x = x; + _y = y; + _hits = h; + _madAt = m; + _isA = i; + _program = p; + _sprite = s; + _flags = mf; + } +}; + +struct Story { + int _levelNum; + int _partNum; + UnivAt _UnivAt; + SRoom *_rooms; + SDoor *_doors; + SFlame **_flames; + SObj **_objects; +SMonster **_monsters; +}; + } // namespace immortal -#endif \ No newline at end of file +#endif + + + + + + + + + + + From 35d8b166fe0f5d3631dee0c115b83f5da1a4d122 Mon Sep 17 00:00:00 2001 From: Quote58 Date: Mon, 8 Aug 2022 05:55:49 -0400 Subject: [PATCH 320/412] IMMORTAL: Level 0 of story.cpp completed, story.h filled out, and related level.cpp revised --- engines/immortal/cycle.cpp | 28 +++-- engines/immortal/immortal.h | 4 + engines/immortal/level.cpp | 82 ++++++------- engines/immortal/sprite_list.h | 5 +- engines/immortal/story.cpp | 179 ++++++++++++++++++--------- engines/immortal/story.h | 214 ++++++++++++++++++++------------- 6 files changed, 322 insertions(+), 190 deletions(-) diff --git a/engines/immortal/cycle.cpp b/engines/immortal/cycle.cpp index c02570f93d60..e0a07d5cbde4 100644 --- a/engines/immortal/cycle.cpp +++ b/engines/immortal/cycle.cpp @@ -19,21 +19,27 @@ * */ -#include "immortal/immortal.h" +/* [Alternate Name: Sprite Animation Processing] + * --- What is a Cycle --- + */ + +//#include "immortal/room.h" namespace Immortal { -void ImmortalEngine::cycleNew() {} - int ImmortalEngine::getCycleChr() { +// Most of these functions can probably be removed eventually +/* +void Room::cycleNew() {} + int Room::getCycleChr() { return 0; } -void ImmortalEngine::cycleFreeAll() {} -void ImmortalEngine::cycleGetFile() {} -void ImmortalEngine::cycleGetNum() {} -void ImmortalEngine::cycleGetIndex() {} -void ImmortalEngine::cycleSetIndex() {} -void ImmortalEngine::cycleGetFrame() {} -void ImmortalEngine::cycleAdvance() {} - +void Room::cycleFreeAll() {} +void Room::cycleGetFile() {} +void Room::cycleGetNum() {} +void Room::cycleGetIndex() {} +void Room::cycleSetIndex() {} +void Room::cycleGetFrame() {} +void Room::cycleAdvance() {} +*/ } // namespace Immortal diff --git a/engines/immortal/immortal.h b/engines/immortal/immortal.h index 3296f741ea4f..856616dafae9 100644 --- a/engines/immortal/immortal.h +++ b/engines/immortal/immortal.h @@ -578,6 +578,7 @@ class ImmortalEngine : public Engine { // Init void levelInitAtStartOfGameOnly(); void levelInit(); + //void levelGetCount <-- lda count // Main void levelStory(int l); @@ -588,6 +589,9 @@ class ImmortalEngine : public Engine { bool levelIsShowRoom(int r); bool levelIsLoaded(int l); void univAtNew(int l); + //void getLastType <-- lda lastType + //void setLastType <-- sta lastType + //void getShowRoom <-- lda currentRoom /* diff --git a/engines/immortal/level.cpp b/engines/immortal/level.cpp index 1569990829dd..91c3aa43b2b4 100644 --- a/engines/immortal/level.cpp +++ b/engines/immortal/level.cpp @@ -64,60 +64,58 @@ void ImmortalEngine::levelStory(int l) { } void ImmortalEngine::levelLoadFile(int l) { - /* Originally, this searched through story.gs and ignored the data entries. - * However, we have the STR entries separate from the story entries, so - * we can just index the story files array directly. - * It also used a 16 byte buffer to read in a story entry, but again this - * is equivalent to the overhead of reading the array entry I think. + _dRoomNum = 0; + + /* This was originally a large branching tree that checked the identifier of each entry and + * Processed them all for the story. Once again, this would have been better as an indexed + * JSR instead of a set of comparisons and branches. Regardless, we instead use the information + * in the story struct to create the rooms and then populate them. */ - _dRoomNum = 0; - bool done = false; - int type = 0;//story[l]; - - // instead of switch statement, just make a room for each, because the rooms will have the relevant info - - // Once again, would be better as an indexed JSR instead of a set of comparisons and branches - while (done == false) { - switch (type & kOPMaskRecord) { - case kOPMaskRoom: -// roomNew(); - break; - case kOPMaskInRoom: -// inRoomNew(); - break; - case kOPMaskFlame: -// fsetNew(); - break; - case kOPMaskUnivAt: - univAtNew(l); - break; - case kOPMaskMonster: -// monstNew(); - break; - case kOPMaskDoor: -// doorNew(); - break; - case kOPMaskObject: -// objectNew(); - break; - default: - done = true; + // Create the rooms and doors, then populate the rooms with their objects and actors + for (int r = 0; r < _stories[l]._rooms.size(); r++) { + //roomNew(_stories[l]._rooms[i]); + //doorNew(_stories[l]._doors[i]); + debug("Room %d", r); + for (int f = 0; f < _stories[l]._flames.size(); f++) { + if (_stories[l]._flames[r].size() > 0) { + //fsetNew(_stories[l]._flames[r][f]); + debugN("F%d", f); + } + } + debug(""); + + for (int o = 0; o < _stories[l]._objects.size(); o++) { + if (_stories[l]._objects[r].size() > 0) { + //objNew(_stories[l]._objects[r][o]); + debugN("O%d", o); + } } + debug(""); + + for (int m = 0; m < _stories[l]._monsters.size(); m++) { + if (_stories[l]._monsters[r].size() > 0) { + //monstNew(_stories[l]._monsters[r][m]); + debugN("M%d", m); + } + } + debug(""); } + + // Set up the _initial variables for the engine scope + univAtNew(l); } void ImmortalEngine::univAtNew(int l) { _initialRoom = _dRoomNum; - _initialX = 0;//_stories[l]._initialX; - _initialY = 0;//_stories[l]._initialY; - _initialBX = 0;//_stories[l]._initialBX; - _initialBY = 0;//_stories[l]._initialBY; + _initialX = _stories[l]._initialUnivX; + _initialY = _stories[l]._initialUnivY; + _initialBX = _stories[l]._playerPointX; + _initialBY = _stories[l]._playerPointY; //doorToNextLevel(_stories[l]._doorToNextLevel, _initialBX, _initialBY); //doorSetLadders(_stories[l]._doorSetLadders); //roomSetHole(_stories[l]._setHole, _stories[l]._setHoleX, _stories[l]._setHoleY); //monstRepos(kPlayerID); - } void ImmortalEngine::levelDrawAll() { diff --git a/engines/immortal/sprite_list.h b/engines/immortal/sprite_list.h index b4e80963e624..a08293312500 100644 --- a/engines/immortal/sprite_list.h +++ b/engines/immortal/sprite_list.h @@ -25,8 +25,11 @@ namespace Immortal { enum SpriteFrame { + // Null + kNoFrame, + // Chest frames - kChest0Frame, + kChest0Frame = 0, kOpenChestFrame, kRingFrame, kKnifeFrame, diff --git a/engines/immortal/story.cpp b/engines/immortal/story.cpp index a32b149c3a98..f35d7b8f3b8e 100644 --- a/engines/immortal/story.cpp +++ b/engines/immortal/story.cpp @@ -27,79 +27,155 @@ * the torches, objects, monsters, etc. It also included the string * data in the source code, but technically it was writing those * strings to a separate string bank, so they weren't contiguous - * with the story files. These story files are read in when loading + * with the story files (sometimes?). These story files are read in when loading * a new level, and are used to construct the room object, the monster * objects, and everything in the rooms. */ +/* UNIVAT 1024,480, 1152, 464, \-1, -1, zip,level1Ladders, rooma, 704/64, 544/32\ + UNIVAT 304, 448, 472+32, 500+16, \-1, -1, zip,level12Ladders, -1, 0, 0\ + UNIVAT 600, 450, 560, 598, \-1, r2.b+(16*r2.a), zip,level3Ladders, r2.b, 640/64, 576/32\ + UNIVAT 120, 540, 188, 584, \-1, -1, zip,level4Ladders, -1, 0, 0\ + UNIVAT 64, 128, 128, 128+32, \-1, -1, zip,level5Ladders, -1, 1088/64, 928/32\ + UNIVAT 768, 224, 896, 288-16, \-1, -1, zip,level5Ladders, -1, 1088/64, 928/32\ + UNIVAT 896, 672+64, 960, 832-16, \-1, -1, zip,level6Ladders, -1, 0, 0\ + UNIVAT 688, 800, 912-64, 888-32, \-1, -1, zip,level7Ladders, -1, 1088/64, 928/32\ + UNIVAT 64, 704, 64+96, 704+64, \-1, -1, zip,level8Ladders, -1, 0, 0\ +*/ + #include "immortal/immortal.h" namespace Immortal { void ImmortalEngine::loadStoryFiles() { - /* The way I am doing this, there will be essentially duplicate data - * for the in-room objects. This is because the original also - * effectively duplicated data. There was less overhead of course, - * as these structs are considered classes by c++. However I think - * that logically speaking, this is what the original was doing. - * It's not ideal to do it this way, but my guess for why the source - * didn't just read directly (ex. door object data will never change, - * it is ROM) is that the story bank was too far from the general work - * memory used for the object data. Could be something else though. + /* There is one major difference between the source logic and this method. + * It doesn't change the game logic, but it does change the logic of storing + * the initial rom data. In the source, because there are no language based + * arrays available (the array/qarray have overhead and are not designed for this), + * the story entries are written out dynamically to ensure everything links together + * (in quite a clever way, but does require a lot of untangling to see). + * On the game end however, this means that to populate a level with it's objects, + * rooms, etc. It has to look at every single entry individually, and check the 'recordop'. + * This tells the game what kind of entry it is, and therefor which routine to call. + * But, the catch is that making sure the right entry goes with the right room is tricky. + * In certain cases, there are references to the rooms. In most however it relies on + * INROOM, which is a macro that basically sets the dynamic variable keeping track of what + * room the current entry is using for x/y coordinates. This doesn't serve any purpose + * for us though, because we can use real arrays and structs for the stories, which is what + * I believe the source would have used (though even the DOS version did it this way so + * who knows). All of this to say, instead of INROOM, the equivlent here is basically + * checking for nullptr within arrays that are always the size of the number of rooms. */ - // Level 0: Intro 1 + // *NOTE* the data types Trap and Program will be in the static Story area, and referenced by an enum + + const uint8 kZip = 5; - _stories[0]._levelNum = 0; // These aren't really needed anymore - _stories[0]._partNum = 1; - + /* + * ::: Level 0: Intro 1 ::: + */ + + /* Universe related properties + * including spawn point and entry/exit points + */ int univRoom = 4; // The room the player starts in when beginning this level uint8 univRoomX = 512; uint8 univRoomY = 416; - int byteArray[] = {-1, -1, kStoryNull, 2, 0, univRoom, (704 / 64),(544 / 32)}; - _stories[0]._UnivAt = UnivAt(1024 / 8, 480 / 8, (1152 - univRoomX) / 2, 464 - univRoomY, byteArray); - // All of the rooms for level 0 - SRoom rooms[8] = {SRoom(384, 256, kRoomFlag0), SRoom(512, 64, kRoomFlag0), SRoom(640, 160, kRoomFlag0), SRoom(768, 224, kRoomFlag0), - SRoom(univRoomX, univRoomY, kRoomFlag0), SRoom(960, 512, kRoomFlag0), SRoom(1024, 352, kRoomFlag0), SRoom(896, 64, kRoomFlag0)}; + _stories[0]._level = 0; + _stories[0]._part = 1; + _stories[0]._initialUnivX = 1024 / 8; + _stories[0]._initialUnivY = 480 / 8; + _stories[0]._playerPointX = (1152 - univRoomX) / 2; + _stories[0]._playerPointY = 464 - univRoomY; + + Common::Array ladders{-1, -1, kStoryNull, 2, 0, univRoom, (704 / 64),(544 / 32)}; + _stories[0]._ladders = ladders; + + /* All of the rooms + */ + Common::Array rooms{SRoom(384, 256, kRoomFlag0), SRoom(512, 64, kRoomFlag0), + SRoom(640, 160, kRoomFlag0), SRoom(768, 224, kRoomFlag0), + SRoom(univRoomX, univRoomY, kRoomFlag0), SRoom(960, 512, kRoomFlag0), + SRoom(1024, 352, kRoomFlag0), SRoom(896, 64, kRoomFlag0)}; _stories[0]._rooms = rooms; - // All of the doors for level 0 - SDoor doors[7] = {SDoor(kLeft, 704, 224, 0, 2, false), SDoor(kRight, 576, 352, 4, 0, true), - SDoor(kRight, 704,96, 2, 1, false), SDoor(kRight, 960,128, 7, 2, false), - SDoor(kRight, 1088,160, 3, 7, false), SDoor(kRight, 1088,320, 6, 3, false), - SDoor(kRight, 896,416, 4, 3, false)}; + /* All of the doors + */ + Common::Array doors{SDoor(kLeft, 704, 224, 0, 2, false), SDoor(kRight, 576, 352, 4, 0, true), + SDoor(kRight, 704,96, 2, 1, false), SDoor(kRight, 960,128, 7, 2, false), + SDoor(kRight, 1088,160, 3, 7, false), SDoor(kRight, 1088,320, 6, 3, false), + SDoor(kRight, 896,416, 4, 3, false)}; _stories[0]._doors = doors; - // All of the flames for level 0 - // Macro for flames is (x - roomx), (y - roomy), pattern number - SFlame f5[2] = {SFlame(512 - 384, (240 + 32) - 256, kFlameOff), SFlame(672 - 384, (240 + 32) - 256, kFlameOff)}; - SFlame f7[3] = {SFlame(576 - 384, (112 + 32) - 256, kFlameNormal), SFlame(576 - 384, (112 + 32) - 256, kFlameNormal), SFlame(928 - 384, (48 + 32) - 256, kFlameNormal)}; - SFlame f8[1] = {SFlame(800 - 640, (144 + 32) - 160, kFlameNormal)}; - SFlame f9[3] = {SFlame(768 - 768, (304 + 32) - 224, kFlameNormal), SFlame((928 - 768), (304 + 32) - 224, kFlameNormal), SFlame((1024 - 768), (240 + 32) - 224, kFlameNormal)}; - SFlame fA[3] = {SFlame(672 - 512, (400 + 32) - 416, kFlameNormal), SFlame((800 - 64) - 512, (496 - 32) - 416, kFlameNormal), SFlame(576 - 512, (528 + 32) - 416, kFlameNormal)}; - SFlame fD[1] = {SFlame(1024 - 960, (496 + 32) - 512, kFlameNormal)}; - SFlame fE[1] = {SFlame(1184 - 1024, 432 - 352, kFlameCandle)}; - SFlame fF[1] = {SFlame(1024 - 896, (144 + 32) - 64, kFlameNormal)}; - SFlame *flames[8] = {f5, f7, f8, f9, fA, fD, fE, fF}; + /* All of the flames + * Macro for flames is (x - roomx), (y - roomy), pattern number + */ + Common::Array f5{SFlame(512 - 384, (240 + 32) - 256, kFlameOff), SFlame(672 - 384, (240 + 32) - 256, kFlameOff)}; + Common::Array f7{SFlame(576 - 384, (112 + 32) - 256, kFlameNormal), SFlame(576 - 384, (112 + 32) - 256, kFlameNormal), + SFlame(928 - 384, (48 + 32) - 256, kFlameNormal)}; + Common::Array f8{SFlame(800 - 640, (144 + 32) - 160, kFlameNormal)}; + Common::Array f9{SFlame(768 - 768, (304 + 32) - 224, kFlameNormal), SFlame((928 - 768), (304 + 32) - 224, kFlameNormal), + SFlame(1024 - 768, (240 + 32) - 224, kFlameNormal)}; + Common::Array fA{SFlame(672 - 512, (400 + 32) - 416, kFlameNormal), SFlame((800 - 64) - 512, (496 - 32) - 416, kFlameNormal), + SFlame(576 - 512, (528 + 32) - 416, kFlameNormal)}; + Common::Array fD{SFlame(1024 - 960, (496 + 32) - 512, kFlameNormal)}; + Common::Array fE{SFlame(1184 - 1024, 432 - 352, kFlameCandle)}; + Common::Array fF{SFlame(1024 - 896, (144 + 32) - 64, kFlameNormal)}; + CArray2D flames{f5, f7, f8, f9, fA, fD, fE, fF}; _stories[0]._flames = flames; - // All of the objects for level 0 - SObj o5[3]; - SObj o7[1]; - SObj o8[1]; - SObj o9[9]; - SObj oE[4]; - SObj *objects[8] = {o5, o7, o8, o9, nullptr, nullptr, oE, nullptr}; + /* All of the objects + * Macro for traps is arrowType,freq,#sinkTraps,#1(going toward 5),#3,#5,#7,#trapdoors + */ + Common::Array noTraps{}; + Common::Array o5Traps{0,0x80,0,0,0,0,0,5}; + Common::Array o7Traps{0,0x80,15,5,3,0,0,0}; + Common::Array o8Traps{0,0x80,0,0,0,0,0,3}; + + Common::Array noObj{}; + Common::Array o5{SObj(kZip, kZip, kTypeTrap, kNoFrame, kObjIsRunning + kObjIsInvisible, o5Traps), + SObj(459, 379, kTypeCoin, kRingFrame, kObjNone, noTraps), + SObj(446, 327, kTypeWowCharm, kScrollFrame, kObjNone, noTraps)}; + Common::Array o7{SObj(145, 138, kTypeTrap, kNoFrame, kObjIsRunning + kObjIsInvisible, o7Traps)}; + Common::Array o8{SObj(kZip, kZip, kTypeTrap, kNoFrame, kObjIsRunning + kObjIsInvisible, o8Traps)}; + Common::Array o9{SObj(1052, 309, kTypeDead, kDeadGoblinFrame, kObjIsChest + kObjIsOnGround, noTraps), + SObj(kZip, kZip, kTypeFireBall, kScrollFrame, kObjUsesFireButton, noTraps), + SObj(128, 464, kTypeDunRing, kRingFrame, 0, noTraps), + SObj(837, 421, kTypeChest, kChest0Frame, kObjIsChest, noTraps), + SObj(kZip, kZip, kTypeDeathMap, kScrollFrame, 0, noTraps), + SObj(597, 457, kTypeWater, kVaseFrame, 0, noTraps), + SObj(kZip, kZip, kTypeSpores, kSporesFrame, 0, noTraps), + SObj(kZip, kZip, kTypeWormFood, kNoFrame, 0, noTraps), + SObj(205, 158, kTypeChestKey, kKeyFrame, 0, noTraps)}; + Common::Array oE{SObj(1184, 426, kTypePhant, kAltarFrame, 0, noTraps), + SObj(145, 138, kTypeGold, kNoFrame, kObjIsRunning, noTraps), + SObj(671, 461, kTypeHay, kNoFrame, kObjIsRunning + kObjIsInvisible, noTraps), + SObj(780, 508, kTypeBeam, kNoFrame, kObjIsRunning + kObjIsInvisible, noTraps)}; + CArray2D objects{o5, o7, o8, o9, noObj, noObj, oE, noObj}; _stories[0]._objects = objects; - // All of the monsters for level 0 - SMonster m5[2]; - SMonster m9[3]; - SMonster mE[1]; - SMonster mF[1]; - SMonster *monsters[8] = {m5, nullptr, nullptr, m9, nullptr, nullptr, mE, mF}; + /* All of the monsters + * A 'Program' is just an array of pointers to 'Motives' + */ + Common::Array progShade{kMotiveRoomCombat, kMotiveShadeFind, kMotiveShadeLoose, kMotiveEngage, kMotiveUpdateGoal, kMotiveFollow, kMotiveShadeHesitate}; + Common::Array progEasy{kMotiveEasyRoomCombat, kMotiveFind8, kMotiveLoose4, kMotiveEngage, kMotiveUpdateGoal, kMotiveFollow}; + Common::Array progUlindor{kMotiveDefensiveCombat, kMotiveEngage, kMotiveUlinTalk, kMotiveGive, kMotiveUseUpMonster}; + Common::Array progGoblin5{kMotiveAliveRoomCombat, kMotiveFindAlways, kMotiveLoose4, kMotiveEngage, kMotiveUpdateGoal, kMotiveFollow}; + Common::Array progPlayer{kMotivePlayerCombat, kMotiveJoystick, kMotivePlayerDoor}; + Common::Array progWill2{kMotiveRoomCombat, kMotivewaittalk2, kMotiveFindAlways, kMotiveGetDisturbed, kMotiveLoose32, kMotiveUpdateGoal, kMotiveIfNot1Skip1, kMotiveFollow, kMotiveEngage}; + + Common::Array noMonst{}; + Common::Array m5{SMonster(448, 344, 12, kMonstPlayer, kMonstA + kMonstIsEngage + kMonstIsTough, progShade, kShadow), + SMonster(590, 381, 12, kMonstPlayer, kMonstA + kMonstIsEngage + kMonstIsTough, progShade, kShadow)}; + Common::Array m9{SMonster(1106, 258, 3, kMonstPlayer, kMonstA + kMonstIsEngage, progEasy, kGoblin0), + SMonster(832, 364, 10, kMonstA, kMonstB + kMonstIsPoss, progUlindor, kUlindor3), + SMonster(838, 370, 15, kMonstPlayer, kMonstA + kMonstIsEngage, progGoblin5, kGoblin7)}; + Common::Array mE{SMonster(1136, 464, 15, kMonstMonster, kMonstPlayer + kMonstIsEngage, progPlayer, kWizard0)}; + Common::Array mF{SMonster(1182, 116, 5, kMonstPlayer, kMonstA + kMonstIsEngage, progWill2, kGoblin5)}; + CArray2D monsters{m5, noMonst, noMonst, m9, noMonst, noMonst, mE, mF}; _stories[0]._monsters = monsters; + } } // namespace Immortal @@ -120,13 +196,6 @@ void ImmortalEngine::loadStoryFiles() { - - - - - - - diff --git a/engines/immortal/story.h b/engines/immortal/story.h index 3524a3c32700..332e93b990ea 100644 --- a/engines/immortal/story.h +++ b/engines/immortal/story.h @@ -24,26 +24,29 @@ namespace Immortal { +// We need a few two-dimentional vectors, and writing them out in full each time is tedious +template using CArray2D = Common::Array>; + enum DoorDir : bool { kLeft = false, kRight = true }; -enum RoomFlag : uint8 { +enum RoomFlag : uint8 { // Generic properties available to each room kRoomFlag0 = 0x1, kRoomFlag1 = 0x2, kRoomFlag2 = 0x4, kRoomFlag3 = 0x8 }; -enum FPattern { +enum FPattern : uint8 { // This defines which Cyc animation it uses kFlameNormal, kFlameCandle, kFlameOff, kFlameGusty }; -enum OPMask : uint8 { +enum OPMask : uint8 { // These are not actually needed anymore, they were for the original compiler method for making story.gs. Keeping it just in case for now kOPMaskRoom, kOPMaskInRoom, kOPMaskFlame, @@ -61,27 +64,62 @@ enum ObjFlag : uint8 { kObjIsChest = 0x08, kObjIsOnGround = 0x04, kObjIsF1 = 0x02, - kObjIsF2 = 0x01 + kObjIsF2 = 0x01, + kObjNone = 0x0 }; enum MonsterFlag : uint8 { + kMonstIsNone = 0x00, kMonstIsTough = 0x10, kMonstIsDead = 0x20, kMonstIsPoss = 0x40, kMonstIsBaby = 0x40, - kMonstIsEngage = 0x80 + kMonstIsEngage = 0x80, + kMonstPlayer = 0x00, + kMonstMonster = 0x01, + kMonstAnybody = 0x02, + kMonstNobody = 0x03, + kMonstA = 0x04, + kMonstB = 0x05, + kMonstC = 0x06, + kMonstD = 0x07 }; enum IsA : uint8 { kIsAF1 = 0x20, - kIsAF2 = 0x40 + kIsAF2 = 0x40, + kIsANone = 0x0, }; -enum Program { // This will likely be moved to a monster ai specific file later +enum Motive { // This will likely be moved to a monster ai specific file later + kMotiveRoomCombat, + kMotiveShadeFind, + kMotiveShadeLoose, + kMotiveEngage, + kMotiveUpdateGoal, + kMotiveFollow, + kMotiveShadeHesitate, + kMotiveEasyRoomCombat, + kMotiveFind8, + kMotiveLoose4, + kMotiveDefensiveCombat, + kMotiveUlinTalk, + kMotiveGive, + kMotiveUseUpMonster, + kMotiveAliveRoomCombat, + kMotiveFindAlways, + kMotivePlayerCombat, + kMotiveJoystick, + kMotivePlayerDoor, + kMotivewaittalk2, + kMotiveGetDisturbed, + kMotiveLoose32, + kMotiveIfNot1Skip1, }; enum Str { - kStrOldGame, + kStrNoDesc, + kStrOldGame = 0, kStrEnterCertificate, kStrBadCertificate, kStrCertificate, @@ -93,6 +131,33 @@ enum Str { kStrGameOver, }; +enum SObjType { + kTypeTrap, + kTypeCoin, + kTypeWowCharm, + kTypeDead, + kTypeFireBall, + kTypeDunRing, + kTypeChest, + kTypeDeathMap, + kTypeWater, + kTypeSpores, + kTypeWormFood, + kTypeChestKey, + kTypePhant, + kTypeGold, + kTypeHay, + kTypeBeam +}; + +enum SObjPickup { + +}; + +enum SObjUse { + +}; + struct Pickup { //pointer to function int _param; @@ -104,25 +169,24 @@ struct Use { }; struct ObjType { - Str _str; - Str _desc; - int _size; + Str _str = kStrNoDesc; + Str _desc = kStrNoDesc; + int _size = 0; Pickup _pickup; Use _use; Use _run; }; - /* Strictly speaking, many of these structs (which were rom data written dynamically * with compiler macros) combine multiple properties into single bytes (ex. room uses * bits 0-2 of X to also hold the roomOP, and bits 0-2 of Y to hold flags). However * for the moment there's no need to replicate this particular bit of space saving. */ struct SRoom { - uint8 _x; - uint8 _y; - RoomFlag _flags; - SRoom() {} + uint8 _x = 0; + uint8 _y = 0; + RoomFlag _flags = kRoomFlag0; + SRoom(uint8 x, uint8 y, RoomFlag f) { _x = x; _y = y; @@ -131,100 +195,88 @@ struct SRoom { }; struct SDoor { - DoorDir _dir; - uint8 _x; - uint8 _y; - uint8 _fromRoom; - uint8 _toRoom; - bool _isLocked; - SDoor() {} +DoorDir _dir = kLeft; + uint8 _x = 0; + uint8 _y = 0; + uint8 _fromRoom = 0; + uint8 _toRoom = 0; + bool _isLocked = false; + SDoor(DoorDir d, uint8 x, uint8 y, uint8 f, uint8 t, bool l) { - _dir = d; - _x = x; - _y = y; - _fromRoom = f; - _toRoom = t; - _isLocked = l; + _dir = d; + _x = x; + _y = y; + _fromRoom = f; + _toRoom = t; + _isLocked = l; } }; struct SFlame { - uint8 _x; - uint8 _y; - FPattern _pattern; - SFlame() {} + uint8 _x = 0; + uint8 _y = 0; +FPattern _pattern = kFlameOff; + SFlame(uint8 x, uint8 y, FPattern p) { _x = x; _y = y; - _pattern = p; + _pattern = p; } }; -struct UnivAt { - uint8 _initialUnivX; - uint8 _initialUnivY; - uint8 _playerPointX; - uint8 _playerPointY; - int *_ladders; - UnivAt() {} - UnivAt(uint8 iX, uint8 iY, uint8 pX, uint8 pY, int l[]) { - _initialUnivX = iX; - _initialUnivY = iY; - _playerPointX = pX; - _playerPointY = pY; - _ladders = l; - } -}; - struct SObj { - uint8 _x; - uint8 _y; - ObjType _type; - ObjFlag _flags; - uint8 _tmp; -SpriteFrame _frame; - SObj() {} - SObj(uint8 x, uint8 y, ObjType t, ObjFlag f, uint8 tmp, SpriteFrame s) { + uint8 _x = 0; + uint8 _y = 0; + SObjType _type = kTypeTrap; + uint8 _flags = 0; +SpriteFrame _frame = kNoFrame; +Common::Array _traps; + + SObj(uint8 x, uint8 y, SObjType t, SpriteFrame s, uint8 f, Common::Array traps) { _x = x; _y = y; _type = t; _flags = f; - _tmp = tmp; + _traps = traps; _frame = s; } }; struct SMonster { - uint8 _x; - uint8 _y; - uint8 _hits; - uint8 _madAt; - IsA _isA; - Program _program; - SpriteName _sprite; -MonsterFlag _flags; - SMonster() {} - SMonster(uint8 x, uint8 y, uint8 h, uint8 m, IsA i, Program p, SpriteName s, MonsterFlag mf) { - _x = x; - _y = y; + uint8 _x = 0; + uint8 _y = 0; + uint8 _hits = 0; +MonsterFlag _madAt = kMonstIsNone; + uint8 _flags = 0; + SpriteName _sprite = kCandle; +Common::Array _program; + + SMonster(uint8 x, uint8 y, uint8 h, MonsterFlag m, uint8 f, Common::Array p, SpriteName s) { + _x = x; + _y = y; _hits = h; _madAt = m; - _isA = i; + _flags = f; _program = p; _sprite = s; - _flags = mf; } }; struct Story { - int _levelNum; - int _partNum; - UnivAt _UnivAt; - SRoom *_rooms; - SDoor *_doors; - SFlame **_flames; - SObj **_objects; -SMonster **_monsters; + int _level = 0; + int _part = 1; + + uint8 _initialUnivX = 0; + uint8 _initialUnivY = 0; + uint8 _playerPointX = 0; + uint8 _playerPointY = 0; + + Common::Array _ladders; +Common::Array _rooms; +Common::Array _doors; + CArray2D _flames; + CArray2D _objects; + CArray2D _monsters; }; } // namespace immortal From bb56b8cdab463dfa5b1df402dea95dd27ad68e80 Mon Sep 17 00:00:00 2001 From: Quote58 Date: Wed, 10 Aug 2022 06:22:25 -0400 Subject: [PATCH 321/412] IMMORTAL: Add skeleton of Room Object --- engines/immortal/immortal.h | 50 +++++++------- engines/immortal/level.cpp | 12 ++-- engines/immortal/module.mk | 4 +- engines/immortal/room.cpp | 94 ++++++++++++++++++++++++++ engines/immortal/room.h | 130 ++++++++++++++++++++++++++++++++++++ engines/immortal/story.h | 2 + 6 files changed, 261 insertions(+), 31 deletions(-) create mode 100644 engines/immortal/room.cpp create mode 100644 engines/immortal/room.h diff --git a/engines/immortal/immortal.h b/engines/immortal/immortal.h index 856616dafae9..cfb0ffe64f19 100644 --- a/engines/immortal/immortal.h +++ b/engines/immortal/immortal.h @@ -49,7 +49,6 @@ #include "immortal/detection.h" #include "immortal/disk.h" -#include "immortal/sprite_list.h" // This is an enum of all available sprites #include "immortal/story.h" namespace Immortal { @@ -217,8 +216,8 @@ class ImmortalEngine : public Engine { */ // Misc constants - const int kNumLengths = 21; - const int kNiceTime = 36; + const int kNumLengths = 21; + const int kNiceTime = 36; const int kMaxCertificate = 16; // Max strings = 250 @@ -232,27 +231,27 @@ class ImmortalEngine : public Engine { "Enter certificate:&-=", "Game Over&&Play again?@"}; // Screen constants - const int kResH = 320; - const int kResV = 200; - const int kScreenW__ = 128; // ??? labeled in source as SCREENWIDTH - const int kScreenH__ = 128; // ??? - const int kViewPortW = 256; - const int kViewPortH = 128; - const int kScreenSize = (kResH * kResV) * 2; // The size of the screen buffer is 320x200 - const int kScreenLeft = 32; - const int kScreenTop = 20; - const int kTextLeft = 8; - const int kTextTop = 4; - const int kGaugeX = 0; - const int kGaugeY = -13; // ??? - const int kScreenBMW = 160; // Literally no idea yet - const uint16 kChrW = 64; - const uint16 kChrH = 32; - const uint16 kChrH2 = kChrH * 2; - const uint16 kChrH3 = kChrH * 3; - const int kChrLen = (kChrW / 2) * kChrH; - const int kChrBMW = kChrW / 2; - const int kLCutaway = 4; + const int kResH = 320; + const int kResV = 200; + const int kScreenW__ = 128; // ??? labeled in source as SCREENWIDTH + const int kScreenH__ = 128; // ??? + const int kViewPortW = 256; + const int kViewPortH = 128; + const int kScreenSize = (kResH * kResV) * 2; // The size of the screen buffer is 320x200 + const int kScreenLeft = 32; + const int kScreenTop = 20; + const int kTextLeft = 8; + const int kTextTop = 4; + const int kGaugeX = 0; + const int kGaugeY = -13; // ??? + const int kScreenBMW = 160; // Literally no idea yet + const uint16 kChrW = 64; + const uint16 kChrH = 32; + const uint16 kChrH2 = kChrH * 2; + const uint16 kChrH3 = kChrH * 3; + const int kChrLen = (kChrW / 2) * kChrH; + const int kChrBMW = kChrW / 2; + const int kLCutaway = 4; const uint16 kChrDy[19] = {kChr0, kChrH, kChrH2, kChrH, kChrH2, kChrH2, kChrH, kChrH2, kChrH2, kChr0, @@ -273,7 +272,7 @@ class ImmortalEngine : public Engine { 0, 0, 0, 0, 0, 0}; // Disk offsets - const int kPaletteOffset = 21205; // This is the byte position of the palette data in the disk + const int kPaletteOffset = 21205; // This is the byte position of the palette data in the disk // Sprite constants const int kMaxSpriteAbove = 48; // Maximum sprite extents from center @@ -574,6 +573,7 @@ class ImmortalEngine : public Engine { /* * [Level.cpp] Functions from level.GS + * < All functions implemented (in some capacity)! > */ // Init void levelInitAtStartOfGameOnly(); diff --git a/engines/immortal/level.cpp b/engines/immortal/level.cpp index 91c3aa43b2b4..0a18afd44f6b 100644 --- a/engines/immortal/level.cpp +++ b/engines/immortal/level.cpp @@ -19,10 +19,13 @@ * */ +#include "immortal/room.h" #include "immortal/immortal.h" namespace Immortal { +struct Flame; + void ImmortalEngine::levelInitAtStartOfGameOnly() { loadStoryFiles(); _lastLevelLoaded = -1; @@ -38,7 +41,7 @@ void ImmortalEngine::levelNew(int l) { clearScreen(); /* commented out in the source for some reason? */ for (int i = 0; i < kMaxRooms; i++) { - //_rooms[i].delete(); + delete _rooms[i]; } levelStory(l); @@ -64,7 +67,7 @@ void ImmortalEngine::levelStory(int l) { } void ImmortalEngine::levelLoadFile(int l) { - _dRoomNum = 0; +// _dRoomNum = 0; /* This was originally a large branching tree that checked the identifier of each entry and * Processed them all for the story. Once again, this would have been better as an indexed @@ -74,12 +77,13 @@ void ImmortalEngine::levelLoadFile(int l) { // Create the rooms and doors, then populate the rooms with their objects and actors for (int r = 0; r < _stories[l]._rooms.size(); r++) { - //roomNew(_stories[l]._rooms[i]); + _rooms[r] = new Room(_stories[l]._rooms[r]._x, _stories[l]._rooms[r]._y, _stories[l]._rooms[r]._flags); //doorNew(_stories[l]._doors[i]); debug("Room %d", r); for (int f = 0; f < _stories[l]._flames.size(); f++) { if (_stories[l]._flames[r].size() > 0) { - //fsetNew(_stories[l]._flames[r][f]); + //Flame flame; + //_rooms[r]->_flames.push_back(flame); debugN("F%d", f); } } diff --git a/engines/immortal/module.mk b/engines/immortal/module.mk index 6c460cff60a8..ac6c8f3bed01 100644 --- a/engines/immortal/module.mk +++ b/engines/immortal/module.mk @@ -12,10 +12,10 @@ MODULE_OBJS = \ cycle.o \ drawChr.o \ level.o \ - story.o + story.o \ + room.o # universe.o \ -# room.o \ # object.o \ # door.o \ # flameset.o \ diff --git a/engines/immortal/room.cpp b/engines/immortal/room.cpp new file mode 100644 index 000000000000..dc6f49db2adc --- /dev/null +++ b/engines/immortal/room.cpp @@ -0,0 +1,94 @@ +/* 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 "immortal/room.h" + +namespace Immortal { + +Room::Room(uint8 x, uint8 y, RoomFlag f) { + _xPos = x; + _yPos = y; + _flags = f; +} + +void Room::addMonster() { + //_monsters->push_back(new Monster()); +} + +void Room::removeMonster() { + //_monsters->pop_back(); +} + +void Room::addObject() { + //_objects->push_back(new Object()); +} + +void Room::removeObject() { + //_objects->pop_back(); +} + +Common::Array Room::getMonsterList() { + return _monsters; +} + +Common::Array Room::getObjectList() { + return _objects; +} + +void Room::getXY(uint16 &x, uint16 &y) { + x <<= 2; + y <<= 2; +} + +void Room::getCell(uint16 &x, uint16 &y) { + x >>= 3; + y >>= 3; +} + +void Room::setHole() {} +void Room::drawContents() {} + +bool Room::getWideWallNormal(uint8 x, uint8 y, uint8 xPrev, uint8 yPrev, int id, int spacing) { + return true; +} + +bool Room::getWallNormal(uint8 x, uint8 y, uint8 xPrev, uint8 yPrev, int id) { + return true; +} + +} // namespace immortal + + + + + + + + + + + + + + + + + diff --git a/engines/immortal/room.h b/engines/immortal/room.h new file mode 100644 index 000000000000..8c07a7f01614 --- /dev/null +++ b/engines/immortal/room.h @@ -0,0 +1,130 @@ +/* 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 . + * + */ + +/* --- What is a Room --- + * + */ + +#include "common/file.h" +#include "common/memstream.h" +#include "common/debug.h" +#include "common/error.h" +#include "immortal/story.h" + +#ifndef IMMORTAL_ROOM_H +#define IMMORTAL_ROOM_H + +namespace Immortal { + +enum Tile : uint8 { + kTileFloor, + kTileUpper5, + kTileUpper3, + kTileCeiling, + kTileTop1, + kTileTop7, + kTileWallFace, + kTileTopLower13, + kTileTopLower75, + kTileLower3, + kTileLower5, + kTileCeilingTile = 2 +}; + +struct Flame { +}; + +// Temp +struct Object { +}; + +// Temp +struct Monster { +}; + +struct Spark { +}; + +struct Chest { +}; + +struct Bullet { +}; + +class Room { +private: + +public: + Room(uint8 x, uint8 y, RoomFlag f); + ~Room() {} + +Common::Array _fset; +Common::Array _monsters; +Common::Array _objects; + + RoomFlag _flags; + uint8 _xPos; + uint8 _yPos; + uint8 _holeRoom; + uint8 _holeCellX; + uint8 _holeCellY; + + //void init(); + //void inRoomNew(); + //void getTilePair(uint8 x, uint8 y); // Modifies a struct of the tile number, aboveTile number, and the cell coordinates of the tile + + void setHole(); + void drawContents(); + bool getTilePair(uint8 x, uint8 y, int id); + bool getWideWallNormal(uint8 x, uint8 y, uint8 xPrev, uint8 yPrev, int id, int spacing); + bool getWallNormal(uint8 x, uint8 y, uint8 xPrev, uint8 yPrev, int id); + void addMonster(); + void addObject(); + void removeObject(); + void removeMonster(); + +Common::Array getMonsterList(); +Common::Array getObjectList(); + + void getXY(uint16 &x, uint16 &y); + void getCell(uint16 &x, uint16 &y); +}; + + + +} // namespace immortal + +#endif + + + + + + + + + + + + + + + diff --git a/engines/immortal/story.h b/engines/immortal/story.h index 332e93b990ea..472415a0c358 100644 --- a/engines/immortal/story.h +++ b/engines/immortal/story.h @@ -19,6 +19,8 @@ * */ +#include "immortal/sprite_list.h" // This is an enum of all available sprites + #ifndef IMMORTAL_STORY_H #define IMMORTAL_STORY_H From 204dda79b0a3aa26f1d44ac71b173e2a6eb96541 Mon Sep 17 00:00:00 2001 From: Quote58 Date: Sun, 14 Aug 2022 17:00:38 -0400 Subject: [PATCH 322/412] IMMORTAL: Add static story STR definitions --- engines/immortal/immortal.cpp | 1 + engines/immortal/immortal.h | 34 +++++---- engines/immortal/kernal.cpp | 119 +++++++++++++++++++++++++++++++ engines/immortal/level.cpp | 2 +- engines/immortal/logic.cpp | 6 +- engines/immortal/story.cpp | 2 +- engines/immortal/story.h | 127 ++++++++++++++++++++++++++++++++-- 7 files changed, 267 insertions(+), 24 deletions(-) diff --git a/engines/immortal/immortal.cpp b/engines/immortal/immortal.cpp index 623a5cdc3dc5..c75105de4133 100644 --- a/engines/immortal/immortal.cpp +++ b/engines/immortal/immortal.cpp @@ -156,6 +156,7 @@ Common::Error ImmortalEngine::run() { _usingNormal = 0; _draw = 1; + initStoryStatic(); // Init the arrays of static story elements (done at compile time in the source) loadPalette(); // We need to grab the palette from the disk first useNormal(); // The first palette will be the default loadFont(); // Load the font sprite diff --git a/engines/immortal/immortal.h b/engines/immortal/immortal.h index cfb0ffe64f19..eef656df82ed 100644 --- a/engines/immortal/immortal.h +++ b/engines/immortal/immortal.h @@ -154,6 +154,18 @@ enum GameFlags : uint8 { kSavedAna }; +struct Spark { +}; + +struct GenSprite { +}; + +struct Door { +}; + +struct Cycle { +}; + struct Frame { uint16 _deltaX; uint16 _deltaY; @@ -220,16 +232,6 @@ class ImmortalEngine : public Engine { const int kNiceTime = 36; const int kMaxCertificate = 16; - // Max strings = 250 - // This should really be a char array, but inserting frame values will be stupid so it's just a string instead - const Common::String stringPtrs[250] = {"New game?%", "Enter certificate:&-=", "Invalid certificate.@", - "End of level!&Here is your certificate:&&=", "&@", - " Electronic Arts presents&& The Immortal&&&&  1990 Will Harvey|]]]]]]]]]=", // Might need \ for something - " written by&& Will Harvey& Ian Gooding& Michael Marcantel& Brett G. Durrett& Douglas Fulton|]]]]]]]/=", - "#" + Common::String(kGoldBigFrame) + "$0 gold@", - "Congratulations!&&Play again?@", - "Enter certificate:&-=", - "Game Over&&Play again?@"}; // Screen constants const int kResH = 320; const int kResV = 200; @@ -307,7 +309,7 @@ class ImmortalEngine : public Engine { const int kMaxFilesPerLevel = 16; const int kMaxPartInstances = 4; const int kLevelToMaze[8] = {0,0,1,1,2,2,2,3}; - +//cantunlockdoor set badchestdesc /* * 'global' members */ @@ -371,6 +373,13 @@ class ImmortalEngine : public Engine { DataSprite _font; // The font sprite data is loaded separate from other sprite stuff Sprite _sprites[kMaxSprites]; // All the sprites shown on screen DataSprite _dataSprites[kFont + 1]; // All the sprite data, indexed by SpriteFile + Common::Array _strPtrs; // Str should really be a char array, but inserting frame values will be stupid so it's just a string instead + Common::Array _motivePtrs; + Common::Array _damagePtrs; + Common::Array _usePtrs; + Common::Array _pickupPtrs; + CArray2D _programPtrs; + Common::Array _objTypePtrs; // Screen members byte *_window; // Bitmap of the window around the game @@ -467,6 +476,7 @@ class ImmortalEngine : public Engine { // Assets Common::SeekableReadStream *loadIFF(Common::String fileName); // Loads a file and uncompresses if it is compressed + void initStoryStatic(); // Sets up all of the global static story elements //void loadMazeGraphics(); // Creates a universe with a maze void loadFont(); // Gets the font.spr file, and centers the sprite void clearSprites(); // Clears all sprites before drawing the current frame @@ -598,7 +608,7 @@ class ImmortalEngine : public Engine { * [Story.cpp] Functions from Story.cpp */ // Init - void loadStoryFiles(); + void initStoryDynamic(); /* * [Sprites.cpp] Functions from Sprites.GS and spriteList.GS diff --git a/engines/immortal/kernal.cpp b/engines/immortal/kernal.cpp index 50f9fa16cafd..cb2a03365c1a 100644 --- a/engines/immortal/kernal.cpp +++ b/engines/immortal/kernal.cpp @@ -364,6 +364,125 @@ void ImmortalEngine::printChr(char c) { * */ +void ImmortalEngine::initStoryStatic() { + Common::Array s{"#" + Common::String(kSwordBigFrame) + "sword@", + "You find an Elven sword of&agility. Take it?@", + "Search the bones?%", + "}The sword permanently endows you with Elven agility and quickness in combat.@", + "}You notice something that looks wet and green under the pile. Search further?%", + "#" + Common::String(kBagBigFrame) + " dust@" + "}You find a bag containing Dust of Complaisance.&@" + "}Drop the bait on the ground here?%" + "}To use this dust, you throw it in the air. Do that here?%" + "_}Don+t bother me, I+m cutting a gem. Yes, you need it. No, you can+t have it. I wouldn+t give it to anyone, least of all you. Go away. ]]]]=" + "_}Let me help you. Please take this gem. No, really, I insist. Take it and go with my blessings. Good luck. ]]]]=" + "#" + Common::String(kCarpetBigFrame) + "carpet@", + "#" + Common::String(kBombBigFrame) + " bomb@", + "A gas bomb that goblins&use to paralyze trolls.&@", + "Take it?<>@", + "%", + " other@", + "#" + Common::String(kKeyBigFrame) + " key@", + "#" + Common::String(kKeyBigFrame) + " key@", + "A key to a chest.&@", + "The chest is open. Examine&contents?%", + "Put it on?%", + "Drop it?%", + "It+s unlocked. Open it?%", + "It+s locked but you have&the key. Open it?%", + "It+s locked and you don+t&have the key.@", + "The lock, triggered by a&complicated set of latches,&is unfamiliar to you.@", + "#" + Common::String(kGoldBigFrame) + "$0 gold@", + "You find $0 gold pieces.&&^#" + Common::String(kPileFrame) + "@", + "@", + "You can+t plant them on&stone tiles.@", + "It+s locked but you are&able to unlock it with&the key.@", + "_}The king is not dead, but the poison is taking effect. When he sees you, he attempts to speak:[(Give me water... the fountain... I give you... information... peace...+[Give him water?%", + "_}You dont have any water to give him. He mumbles something. Then silence... You find a key on his body.]]]]=", + "_}He mumbles something. Then silence... You find a key on his body.]]]]=", + "_}I+ll tell you how to... next level... past slime... three jewels... slime... rock becomes... floor... right, left, center of the... [Then silence. His hand opens, releasing a key.]]]]=", + "You find a door key.&@", + "You find a note.&@", + "#" + Common::String(kNoteBigFrame) + "note@", + "He+s dead.&Look for possessions?%", + "You don+t have it. Check&your inventory.@", + "Game Over&&Play again?@", + "Congratulations!&&Play again?@", + "You find a bag of bait.&@", + "#" + Common::String(kBagBigFrame) + " bait@", + "You find a stone. @", + "#" + Common::String(kStoneBigFrame) + " stone@", + "You find a red gem.&@", + "#" + Common::String(kGemBigFrame) + " gem@", + "You find a scroll with&fireball spells.&@" + "#" + Common::String(kScrollBigFrame) + "$ shots@", + "You find a map warning&you about pit traps.&@" + "#" + Common::String(kMapBigFrame) + " map@", + "#" + Common::String(kVaseBigFrame) + " oil@", + "You apply the oil but notice&as you walk that the leather&is drying out quickly.@" + "}You discover a scroll with a charm spell to use on will o+ the wisps.&@" + "#" + Common::String(kScrollBigFrame) + " charm@", + "}This charms the will o+ the wisps to follow you. Read the spell again to turn them against your enemies.@" + "}It looks like water. Drink it?%", + "Drink it?%", + "}It works! You are much stronger.]]]=", + "}It looks like it has green stuff inside. Open it?%", + "Now this will take&effect when you press the&fire button.@", + "You find a potion,&Magic Muscle.&@", + "#" + Common::String(kVaseBigFrame) + " potion@", + "You find a bottle.&@", + "#" + Common::String(kVaseBigFrame) + " bottle@", + "#" + Common::String(kRingBigFrame) + "Protean@", + "You find a Protean Ring.&@", + "You find a troll ritual knife,&used to declare a fight to&the death. @", + "#" + Common::String(kKnifeBigFrame) + " knife@", + "_}It is a fine woman+s garment. Folded inside is a ring with the words,[`To Ana, so harm will never find you. -Your loving father, Dunric.+&@", + "You find a small, well&crafted ring. @", + "#" + Common::String(kRingBigFrame) + " gift@", + "#" + Common::String(kRingBigFrame) + " Ana+s@", + "_}She is hurt and upset when she finds you don+t have her ring or won+t give it to her. She scurries back into the hole. The hole is too small for you to follow.&@", + "_}`Sir, can you help me,+ the girl pleads. `I was kidnapped and dragged down here. All the man would say is `Mordamir+s orders.+[I escaped using a ring my father gave me, but now I+ve lost it. Did you find it?+%", + "_}We have met before, old man. Do you remember? Because you helped me, you may pass. But I warn you, we are at war with the trolls.[Over this ladder, across the spikes, is troll territory. Very dangerous.@", + "_}You are an impostor!]]]]=", + "_}Old man, do you remember me? I am king of the goblins. You didn+t give me the water. You left me to die after you took the key from me. Now you will pay.]]]]=", + "_}You quickly fall into a deep, healing sleep...[Vivid images of a beautiful enchanted city pass by. All the city people are young and glowing. Fountains fill the city, and the splash and sparkle of water is everywhere...[Suddenly the images go black. A face appears... Mordamir!]][He is different from how you remember him. His gentle features are now withered. His kind eyes, now cold and sunken, seem to look through you with a dark, penetrating stare. You wake rejuvenated, but disturbed.]]]]]=", + "_}Here, take this ring in return. [I don+t know if it will help, but I heard the unpleasant little dwarf say, (Clockwise, three rings around the triangle.+[Could that be a clue to his exit puzzle? I must go. Goodbye.]]]]=", + "#" + Common::String(kSackBigFrame) + " spores@", + "You find a sack of bad&smelling spores.&@", + "Please insert play disk.@", + "New game?%", + "Enter certificate:&-=", + "Invalid certificate.@", + "End of level!&Here is your certificate:&&=", + "&@", + " Electronic Arts presents&& The Immortal&&&&  1990 Will Harvey|]]]]]]]]]=", + " written by&& Will Harvey& Ian Gooding& Michael Marcantel& Brett G. Durrett& Douglas Fulton|]]]]]]]/=", + "_}Greetings, friend! Come, I+ve got something you need. These parts are plagued with slime.[You can+t venture safely without my slime oil for boots, a bargain at only 80 gold pieces.%", + "_}All right, 60 gold pieces for my oil. Rub it on your boots and slime won+t touch you. 60, friend.%", + "This room doesn+t resemble&any part of the map.@", + "This room resembles part&of the map.@"}; + _strPtrs = s; + + Common::Array m{}; + _motivePtrs = m; + + Common::Array d{}; + _damagePtrs = d; + + Common::Array u{}; + _usePtrs = u; + + Common::Array p{}; + _pickupPtrs = p; + + CArray2D pr{}; + _programPtrs = pr; + + Common::Array o{}; + _objTypePtrs = o; + +} + void ImmortalEngine::addSprite(uint16 x, uint16 y, SpriteName n, int frame, uint16 p) { if (_numSprites != kMaxSprites) { if (x >= (kResH + kMaxSpriteLeft)) { diff --git a/engines/immortal/level.cpp b/engines/immortal/level.cpp index 0a18afd44f6b..59ff8739c1f5 100644 --- a/engines/immortal/level.cpp +++ b/engines/immortal/level.cpp @@ -27,7 +27,7 @@ namespace Immortal { struct Flame; void ImmortalEngine::levelInitAtStartOfGameOnly() { - loadStoryFiles(); + initStoryDynamic(); _lastLevelLoaded = -1; _lastSongLoaded = -1; } diff --git a/engines/immortal/logic.cpp b/engines/immortal/logic.cpp index ebeea26369a1..6e04edbbb91d 100644 --- a/engines/immortal/logic.cpp +++ b/engines/immortal/logic.cpp @@ -504,7 +504,7 @@ void ImmortalEngine::calcCheckSum(int l, uint8 checksum[]) { } bool ImmortalEngine::getCertificate() { - textPrint(kStrCertificate); + textPrint(kStrCert); int certLen = 0; bool entered = false; int k = 0; @@ -596,11 +596,11 @@ void ImmortalEngine::printCertificate() { */ char toHex[] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}; - textBeginning(kStrCertificate); + textBeginning(kStrCert); for (int i = 0; i < _lastCertLen; i++) { printChr(toHex[_certificate[i]]); } - textEnd(kStrCertificate2); + textEnd(kStrCert2); } bool ImmortalEngine::isSavedKing() { diff --git a/engines/immortal/story.cpp b/engines/immortal/story.cpp index f35d7b8f3b8e..875b3f5857d0 100644 --- a/engines/immortal/story.cpp +++ b/engines/immortal/story.cpp @@ -47,7 +47,7 @@ namespace Immortal { -void ImmortalEngine::loadStoryFiles() { +void ImmortalEngine::initStoryDynamic() { /* There is one major difference between the source logic and this method. * It doesn't change the game logic, but it does change the logic of storing * the initial rom data. In the source, because there are no language based diff --git a/engines/immortal/story.h b/engines/immortal/story.h index 472415a0c358..70e8fd48e49e 100644 --- a/engines/immortal/story.h +++ b/engines/immortal/story.h @@ -67,7 +67,7 @@ enum ObjFlag : uint8 { kObjIsOnGround = 0x04, kObjIsF1 = 0x02, kObjIsF2 = 0x01, - kObjNone = 0x0 + kObjNone = 0x0 }; enum MonsterFlag : uint8 { @@ -121,16 +121,121 @@ enum Motive { // This will likely be moved to a monster ai specific file la enum Str { kStrNoDesc, - kStrOldGame = 0, + kStrSword, + kStrSwordDesc, + kStrBonesText1, + kStrBonesText2, + kStrBonesText3, + kStrComp, + kStrCompDesc, + kStrOpenBag, + kStrThrowComp, + kStrSmithText1, + kStrSmithText2, + kStrCarpet, + kStrBomb, + kStrBombDesc, + kStrPickItUp, + kStrYesNo, + kStrOther, + kStrChestKey, + kStrDoorKey, + kStrChestKeyDesc, + kStrOpenChestDesc, + kStrPutItOn, + kStrDropItThen, + kStrChestDesc, + kStrGoodChestDesc, + kStrBadChestDesc, + kStrComboLock, + kStrGold, + kStrFindGold, + kStrNull, + kStrNotHere, + kStrUnlockDoor, + kStrWeak1, + kStrDummyWater, + kStrBadWizard, + kStrDiesAnyway, + kStrDoorKeyDesc, + kStrNoteDesc, + kStrNote, + kStrLootBodyDesc, + kStrNotEnough, + kStrGameOver, + kStrYouWin, + kStrWormFoodDesc, + kStrWormFood, + kStrStoneDesc, + kStrStone, + kStrGemDesc, + kStrGem, + kStrFireBallDesc, + kStrFireBall, + kStrDeathMapDesc, + kStrDeathMap, + kStrBoots, + kStrUseBoots, + kStrWowCharmDesc, + kStrWowCharm, + kStrUseWowCharm, + kStrWaterOpen, + kStrDrinkIt, + kStrItWorks, + kStrSBOpen, + kStrUsesFire, + kStrMuscleDesc, + kStrMuscle, + kStrSBDesc, + kStrSB, + kStrFace, + kStrFaceDesc, + kStrTRNDesc, + kStrTRN, + kStrInvisDesc, + kStrGoodLuckDesc, + kStrAnaRing, + kStrInvis, + kStrGoesAway, + kStrGiveHerRing, + kStrGive2, + kStrMadKingText, + kStrMadKing3Text, + kStrMadKing2Text, + kStrDream1, + kStrDream1P2, + kStrDream1P3, + kStrHowToGetOut, + kStrSpore, + kStrSporeDesc, + kStrRequestPlayDisc, + kStrOldGame, kStrEnterCertificate, kStrBadCertificate, - kStrCertificate, - kStrCertificate2, + kStrCert, + kStrCert2, kStrTitle0, kStrTitle4, - kStrGold, - kStrYouWin, - kStrGameOver, + kStrMDesc, + kStrM3Desc, + kStrMapText1, + kStrMapText2, + + // Level 0 str + + // Level 1 str + + // Level 2 str + + // Level 3 str + + // Level 4 str + + // Level 5 str + + // Level 6 str + + // Level 7 str }; enum SObjType { @@ -160,6 +265,14 @@ enum SObjUse { }; +enum SDamage { + +}; + +struct Damage { + +}; + struct Pickup { //pointer to function int _param; From 9410617da4c0c024515d668bbf9f7bf910f00a1e Mon Sep 17 00:00:00 2001 From: Quote58 Date: Tue, 16 Aug 2022 21:39:53 -0400 Subject: [PATCH 323/412] IMMORTAL: Add util.h and util.cpp, move several misc functions to util.cpp --- engines/immortal/immortal.h | 218 ++++++++++++++++++++++-------------- engines/immortal/kernal.cpp | 8 +- engines/immortal/misc.cpp | 16 --- engines/immortal/util.cpp | 49 ++++++++ engines/immortal/util.h | 41 +++++++ 5 files changed, 227 insertions(+), 105 deletions(-) create mode 100644 engines/immortal/util.cpp create mode 100644 engines/immortal/util.h diff --git a/engines/immortal/immortal.h b/engines/immortal/immortal.h index eef656df82ed..3287f2a0b69e 100644 --- a/engines/immortal/immortal.h +++ b/engines/immortal/immortal.h @@ -22,8 +22,25 @@ #ifndef IMMORTAL_IMMORTAL_H #define IMMORTAL_IMMORTAL_H +// Audio is only handled in kernal, therefore it is only needed here #include "audio/mixer.h" +// Immortal.h is the engine, so it needs the engine headers +#include "engines/engine.h" +#include "engines/savestate.h" + +// Theorectically, all graphics should be handled through driver, which is part of kernal, which is in immortal.h +#include "graphics/screen.h" +#include "graphics/palette.h" +#include "graphics/surface.h" + +// Detection is only needed by the main engine +#include "immortal/detection.h" + +// Disk is only used by immortal.cpp +#include "immortal/disk.h" + +// Common is needed by immortal.h, room.h, and monster.h #include "common/debug.h" #include "common/debug-channels.h" #include "common/events.h" @@ -39,52 +56,17 @@ #include "common/util.h" #include "common/platform.h" -#include "engines/engine.h" -#include "engines/savestate.h" +// There is a lot of bit masking that needs to happen, so this header includes several enums for immortal.h, room.h, and monster.h +#include "immortal/bitmask.h" -#include "graphics/screen.h" -#include "graphics/palette.h" -#include "graphics/surface.h" - -#include "immortal/detection.h" -#include "immortal/disk.h" +#include "immortal/util.h" +// Story is needed by both immortal.h and room.h #include "immortal/story.h" namespace Immortal { -// There is a lot of bit masking that needs to happen, so this enum makes it a little easier to read -enum BitMask16 : uint16 { - kMaskLow = 0x00FF, - kMaskHigh = 0xFF00, - kMaskLast = 0xF000, - kMaskFirst = 0x000F, - kMaskHLow = 0x0F00, - kMaskLHigh = 0x00F0, - kMaskNeg = 0x8000, - kMask12Bit = 0x0F9F // Compression code (pos, 00, len) is stored in lower 12 bits of word -}; - -enum BitMask8 : uint8 { - kMaskASCII = 0x7F, // The non-extended ASCII table uses 7 bits, this makes a couple of things easier - kMask8High = 0xF0, - kMask8Low = 0x0F -}; - -enum ColourBitMask : uint16 { - kMaskRed = 0x0F00, - kMaskGreen = 0x00F0, - kMaskBlue = 0x000F -}; - -enum ChrMask : uint16 { - kChr0 = 0x0000, - kChrL = 0x0001, - kChrR = 0xFFFF, - kChrLD = 0x0002, - kChrRD = 0xFFFE -}; - +// Needed by kernal for drawing enum Screen { // These are constants that are used for defining screen related arrays kMaxSprites = 32, // Number of sprites allowed at once kViewPortCW = 256 / 64, @@ -92,16 +74,7 @@ enum Screen { // These are constants that are used for defining screen kMaxDrawItems = kViewPortCH + 1 + kMaxSprites }; -enum StoryMaxes { - kMaxRooms = 16, - kMaxDoors = 10, - kMaxFlames = 32, - kMaxFlamesInRoom = 5, - kMaxObjects = 42, - kMaxMonsters = 20, - kMaxGenSprites = 6 -}; - +// Needed by kernal for input enum InputAction { kActionNothing, kActionKey, @@ -119,17 +92,21 @@ enum InputDirection { kDirectionRight }; -enum MonsterID { - kPlayerID +// Needed by kernal for music +enum Song { + kSongNothing, + kSongMaze, + kSongCombat, + kSongText }; -enum LevelType { - kRoomType, - kMonsterType, - kObjectType +// Needed by logic for various things +enum MonsterID { + kPlayerID }; -enum CertIndex : uint8 { +// Needed by logic for certificate processing +enum CertificateIndex : uint8 { kCertHits, kCertLevel, kCertLoGameFlags, @@ -141,31 +118,40 @@ enum CertIndex : uint8 { kCertGoldHi }; -enum Song { - kSongNothing, - kSongMaze, - kSongCombat, - kSongText -}; - +// Needed by logic for various things enum GameFlags : uint8 { kSavedNone, kSavedKing, kSavedAna }; +// Needed by level (maybe?) +enum LevelType { + kRoomType, + kMonsterType, + kObjectType +}; + +// Basically the equivalent of the explosion from a projectile in other games I think struct Spark { }; -struct GenSprite { +// Generic sprites can be used anywhere, just sort of misc sprites +struct GenericSprite { }; +// Doors are a property of the level, not the room, they defined the connections between rooms struct Door { + uint8 _x = 0; + uint8 _y = 0; + uint8 _from = 0; + uint8 _to = 0; + uint8 _busyOnRight = 0; + uint8 _on = 0; }; -struct Cycle { -}; +// Sprites are handled by driver in Kernal struct Frame { uint16 _deltaX; uint16 _deltaY; @@ -192,7 +178,7 @@ DataSprite *_dSprite; struct ImmortalGameDescription; -// Forward declaration because we will need the Disk class +// Forward declaration because we will need the Disk and Room classes class ProDosDisk; class Room; @@ -309,7 +295,7 @@ class ImmortalEngine : public Engine { const int kMaxFilesPerLevel = 16; const int kMaxPartInstances = 4; const int kLevelToMaze[8] = {0,0,1,1,2,2,2,3}; -//cantunlockdoor set badchestdesc + /* * 'global' members */ @@ -317,7 +303,7 @@ class ImmortalEngine : public Engine { // Misc Common::ErrorCode _err; // If this is not kNoError at any point, the engine will stop uint8 _certificate[16]; // The certificate (password) is basically the inventory/equipment array - uint8 _lastCertLen = 0; + uint8 _lastCertLen = 0; bool _draw = 0; // Whether the screen should draw this frame int _zero = 0; // No idea what this is yet bool _gameOverFlag = false; @@ -353,6 +339,19 @@ class ImmortalEngine : public Engine { int _roomCellX; int _roomCellY; Room *_rooms[kMaxRooms]; // Rooms within the level + Common::Array _allFlames[kMaxRooms]; // The level needs it's own set of flames so that the flames can be turned on/off permenantly. This is technically more like a hashmap in the source, but it could also be seen as a 2d array, just hashed together in the source + + // Door members + uint8 _numDoors = 0; + uint8 _doorRoom = 0; + uint8 _doorToNextLevel = 0; + uint8 _doorCameInFrom = 0; + uint8 _ladders = 0; + uint8 _numLadders = 0; + uint8 _ladderInUse = 0; + uint8 _secretLadder = 0; + uint8 _secretCount = 0; + uint8 _secretDelta = 0; // Debug members bool _singleStep; // Flag for _singleStep mode @@ -374,12 +373,12 @@ class ImmortalEngine : public Engine { Sprite _sprites[kMaxSprites]; // All the sprites shown on screen DataSprite _dataSprites[kFont + 1]; // All the sprite data, indexed by SpriteFile Common::Array _strPtrs; // Str should really be a char array, but inserting frame values will be stupid so it's just a string instead - Common::Array _motivePtrs; - Common::Array _damagePtrs; - Common::Array _usePtrs; - Common::Array _pickupPtrs; - CArray2D _programPtrs; - Common::Array _objTypePtrs; + Common::Array _motivePtrs; + Common::Array _damagePtrs; + Common::Array _usePtrs; + Common::Array _pickupPtrs; + CArray2D _programPtrs; + Common::Array _objTypePtrs; // Screen members byte *_window; // Bitmap of the window around the game @@ -403,6 +402,8 @@ class ImmortalEngine : public Engine { uint16 _myUnivPointY; int _num2DrawItems = 0; Graphics::Surface *_mainSurface; + Cyc _cycles[32]; +GenericSprite _genSprites[6]; // Palette members int _dontResetColors = 0; // Not sure yet @@ -556,9 +557,6 @@ class ImmortalEngine : public Engine { */ // Misc - void delay(int j); // Delay engine by j jiffies (from driver originally, but makes more sense grouped with misc) - void delay4(int j); // || /4 - void delay8(int j); // || /8 void miscInit(); void setRandomSeed(); void getRandom(); @@ -576,10 +574,6 @@ class ImmortalEngine : public Engine { void buttonPressed(); void firePressed(); - // Screen related - void inside(int p, int p2, int a); - void insideRect(int p, int r); - /* * [Level.cpp] Functions from level.GS @@ -605,8 +599,31 @@ class ImmortalEngine : public Engine { /* - * [Story.cpp] Functions from Story.cpp + * [Cycle.cpp] Functions from Cyc */ + + // Misc + void cycleNew(); // Adds a cycle to the current list + int getCycleChr(); + void cycleFreeAll(); // Delete all cycles + void cycleGetFile(); + void cycleGetNum(); + void cycleGetIndex(); + void cycleSetIndex(); + void cycleGetFrame(); + void cycleAdvance(); + + /* Unneccessary cycle functions + void cycleInit(); + void cycleFree(); + void cycleGetNumFrames(); + void cycleGetList();*/ + + + /* + * [Story.cpp] Functions related to Story.GS + */ + // Init void initStoryDynamic(); @@ -636,11 +653,42 @@ class ImmortalEngine : public Engine { /* - * [Music.cpp] Functions from Music.cpp + * [door.cpp] Functions from Door.GS + */ + + void roomTransfer(int r, int x, int y); // Transfers the player from the current room to a new room at x,y + void doorOpenSecret(); + void doorCloseSecret(); + //void doorToNextLevel(); + void doorInit(); + void doorClrLock(); + void doorNew(); + void doorDrawAll(); + void doorOnDoorMat(); + //void doorEnter(); // <-- this is actually a method of Player Monster, should probably move it there later + int findDoorTop(int x, int y); + int findDoor(int x, int y); + bool doLockStuff(int d, MonsterID m, int top); + bool inDoorTop(int x, int y, MonsterID m); + bool inDoor(int x, int y, MonsterID m); + int doorDoStep(MonsterID m, int d, int index); + int doorSetOn(int d); + int doorComeOut(MonsterID m); + void doorSetLadders(MonsterID m); + + + /* + * [Music.cpp] Functions from music.GS and sound.GS */ // Misc + + /* + * [Univ.cpp] Functions from Univ.GS + */ + + /* * --- ScummVM general engine Functions --- * diff --git a/engines/immortal/kernal.cpp b/engines/immortal/kernal.cpp index cb2a03365c1a..778248aa4b99 100644 --- a/engines/immortal/kernal.cpp +++ b/engines/immortal/kernal.cpp @@ -750,13 +750,13 @@ void ImmortalEngine::pump() { // Flashes the screen (except the frame thankfully) white, black, white, black, then clears the screen and goes back to normal useWhite(); g_system->updateScreen(); - delay(2); + Immortal::Util::delay(2); useBlack(); g_system->updateScreen(); - delay(2); + Immortal::Util::delay(2); useWhite(); g_system->updateScreen(); - delay(2); + Immortal::Util::delay(2); useBlack(); g_system->updateScreen(); clearScreen(); @@ -818,7 +818,7 @@ void ImmortalEngine::fade(uint16 pal[], int dir, int delay) { while ((count >= 0) && (count <= 256)) { fadePal(pal, count, target); - delay8(delay); + Immortal::Util::delay8(delay); setColors(target); // Same as above, it was originally a branch, this does the same thing diff --git a/engines/immortal/misc.cpp b/engines/immortal/misc.cpp index 379e2571c1c1..79e77585dd9f 100644 --- a/engines/immortal/misc.cpp +++ b/engines/immortal/misc.cpp @@ -31,18 +31,6 @@ namespace Immortal { * */ -void ImmortalEngine::delay(int j) { // Delay is measured in jiffies, which are 56.17ms - g_system->delayMillis(j * 56); -} - -void ImmortalEngine::delay4(int j) { // Named in source quarterClock for some reason, 1/4 jiffies are 14.04ms - g_system->delayMillis(j * 14); -} - -void ImmortalEngine::delay8(int j) { // 1/8 jiffies are 7.02ms - g_system->delayMillis(j * 7); -} - void ImmortalEngine::miscInit() { // In the source, this is where the seed for the rng is set, but we don't need to do that as we used _randomSource _lastGauge = 0; @@ -91,10 +79,6 @@ void ImmortalEngine::firePressed() {} * */ -void ImmortalEngine::inside(int p, int p2, int a) {} -void ImmortalEngine::insideRect(int p, int r) {} - - } // namespace Immortal diff --git a/engines/immortal/util.cpp b/engines/immortal/util.cpp new file mode 100644 index 000000000000..0b6bc866edee --- /dev/null +++ b/engines/immortal/util.cpp @@ -0,0 +1,49 @@ +/* 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 "immortal/util.h" + +namespace Immortal { + +namespace Util { + +void Util::delay(int j) { // Delay is measured in jiffies, which are 56.17ms + g_system->delayMillis(j * 56); +} + +void Util::delay4(int j) { // Named in source quarterClock for some reason, 1/4 jiffies are 14.04ms + g_system->delayMillis(j * 14); +} + +void Util::delay8(int j) { // 1/8 jiffies are 7.02ms + g_system->delayMillis(j * 7); +} + +bool Util::inside(int x1, int y1, int a, int x2, int y2) { + return false; +} +bool Util::insideRect(int x, int y, int r) { + return false; +} + +}; // namespace Util + +}; // namespace Immortal \ No newline at end of file diff --git a/engines/immortal/util.h b/engines/immortal/util.h new file mode 100644 index 000000000000..ba7ef1df514a --- /dev/null +++ b/engines/immortal/util.h @@ -0,0 +1,41 @@ +/* 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 . + * + */ + +#ifndef IMMORTAL_UTIL_H +#define IMMORTAL_UTIL_H + +#include "common/system.h" + +namespace Immortal { + +namespace Util { + +void delay(int j); // Delay engine by j jiffies (from driver originally, but makes more sense grouped with misc) +void delay4(int j); // || /4 +void delay8(int j); // || /8 +bool inside(int x1, int y1, int a, int x2, int y2); +bool insideRect(int x, int y, int r); + +}; // namespace Util + +}; // namespace Immortal + +#endif \ No newline at end of file From af28dec2e9d808e8f08a1bd71a0de32e22341de5 Mon Sep 17 00:00:00 2001 From: Quote58 Date: Tue, 16 Aug 2022 21:41:51 -0400 Subject: [PATCH 324/412] IMMORTAL: Add bitmask.h and move bitmask enums from immortal.h to bitmask.h --- engines/immortal/bitmask.h | 60 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 engines/immortal/bitmask.h diff --git a/engines/immortal/bitmask.h b/engines/immortal/bitmask.h new file mode 100644 index 000000000000..e1b7f6a49822 --- /dev/null +++ b/engines/immortal/bitmask.h @@ -0,0 +1,60 @@ +/* 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 . + * + */ + +#ifndef IMMORTAL_BITMASK_H +#define IMMORTAL_BITMASK_H + +namespace Immortal { + +enum BitMask16 : uint16 { + kMaskLow = 0x00FF, + kMaskHigh = 0xFF00, + kMaskLast = 0xF000, + kMaskFirst = 0x000F, + kMaskHLow = 0x0F00, + kMaskLHigh = 0x00F0, + kMaskNeg = 0x8000, + kMask12Bit = 0x0F9F // Compression code (pos, 00, len) is stored in lower 12 bits of word +}; + +enum BitMask8 : uint8 { + kMaskASCII = 0x7F, // The non-extended ASCII table uses 7 bits, this makes a couple of things easier + kMask8High = 0xF0, + kMask8Low = 0x0F +}; + +enum ColourBitMask : uint16 { + kMaskRed = 0x0F00, + kMaskGreen = 0x00F0, + kMaskBlue = 0x000F +}; + +enum ChrMask : uint16 { + kChr0 = 0x0000, + kChrL = 0x0001, + kChrR = 0xFFFF, + kChrLD = 0x0002, + kChrRD = 0xFFFE +}; + +} // namespace immortal + +#endif \ No newline at end of file From b761800cfb0562ecbb45ef3a778556dd0f76ac1a Mon Sep 17 00:00:00 2001 From: Quote58 Date: Tue, 16 Aug 2022 21:43:40 -0400 Subject: [PATCH 325/412] IMMORTAL: Add definitions.h and move enums str, motives, and cyc from story.h to definitions.h --- engines/immortal/definitions.h | 200 +++++++++++++++++++++++ engines/immortal/story.h | 283 ++++++++------------------------- 2 files changed, 268 insertions(+), 215 deletions(-) create mode 100644 engines/immortal/definitions.h diff --git a/engines/immortal/definitions.h b/engines/immortal/definitions.h new file mode 100644 index 000000000000..73082333927d --- /dev/null +++ b/engines/immortal/definitions.h @@ -0,0 +1,200 @@ +/* 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 . + * + */ + +#ifndef IMMORTAL_DEFINITIONS_H +#define IMMORTAL_DEFINITIONS_H + +namespace Immortal { + +enum Cyc { + kCycNone +}; + +enum Motive { // This will likely be moved to a monster ai specific file later + kMotiveRoomCombat, + kMotiveShadeFind, + kMotiveShadeLoose, + kMotiveEngage, + kMotiveUpdateGoal, + kMotiveFollow, + kMotiveShadeHesitate, + kMotiveEasyRoomCombat, + kMotiveFind8, + kMotiveLoose4, + kMotiveDefensiveCombat, + kMotiveUlinTalk, + kMotiveGive, + kMotiveUseUpMonster, + kMotiveAliveRoomCombat, + kMotiveFindAlways, + kMotivePlayerCombat, + kMotiveJoystick, + kMotivePlayerDoor, + kMotivewaittalk2, + kMotiveGetDisturbed, + kMotiveLoose32, + kMotiveIfNot1Skip1, +}; + +enum Str { + kStrNoDesc, + kStrSword, + kStrSwordDesc, + kStrBonesText1, + kStrBonesText2, + kStrBonesText3, + kStrComp, + kStrCompDesc, + kStrOpenBag, + kStrThrowComp, + kStrSmithText1, + kStrSmithText2, + kStrCarpet, + kStrBomb, + kStrBombDesc, + kStrPickItUp, + kStrYesNo, + kStrOther, + kStrChestKey, + kStrDoorKey, + kStrChestKeyDesc, + kStrOpenChestDesc, + kStrPutItOn, + kStrDropItThen, + kStrChestDesc, + kStrGoodChestDesc, + kStrBadChestDesc, + kStrComboLock, + kStrGold, + kStrFindGold, + kStrNull, + kStrNotHere, + kStrUnlockDoor, + kStrWeak1, + kStrDummyWater, + kStrBadWizard, + kStrDiesAnyway, + kStrDoorKeyDesc, + kStrNoteDesc, + kStrNote, + kStrLootBodyDesc, + kStrNotEnough, + kStrGameOver, + kStrYouWin, + kStrWormFoodDesc, + kStrWormFood, + kStrStoneDesc, + kStrStone, + kStrGemDesc, + kStrGem, + kStrFireBallDesc, + kStrFireBall, + kStrDeathMapDesc, + kStrDeathMap, + kStrBoots, + kStrUseBoots, + kStrWowCharmDesc, + kStrWowCharm, + kStrUseWowCharm, + kStrWaterOpen, + kStrDrinkIt, + kStrItWorks, + kStrSBOpen, + kStrUsesFire, + kStrMuscleDesc, + kStrMuscle, + kStrSBDesc, + kStrSB, + kStrFace, + kStrFaceDesc, + kStrTRNDesc, + kStrTRN, + kStrInvisDesc, + kStrGoodLuckDesc, + kStrAnaRing, + kStrInvis, + kStrGoesAway, + kStrGiveHerRing, + kStrGive2, + kStrMadKingText, + kStrMadKing3Text, + kStrMadKing2Text, + kStrDream1, + kStrDream1P2, + kStrDream1P3, + kStrHowToGetOut, + kStrSpore, + kStrSporeDesc, + kStrRequestPlayDisc, + kStrOldGame, + kStrEnterCertificate, + kStrBadCertificate, + kStrCert, + kStrCert2, + kStrTitle0, + kStrTitle4, + kStrMDesc, + kStrM3Desc, + kStrMapText1, + kStrMapText2, + + // Level 0 str + + // Level 1 str + + // Level 2 str + + // Level 3 str + + // Level 4 str + + // Level 5 str + + // Level 6 str + + // Level 7 str + + kCantUnlockDoor = kStrBadChestDesc +}; + +enum SObjType { + kTypeTrap, + kTypeCoin, + kTypeWowCharm, + kTypeDead, + kTypeFireBall, + kTypeDunRing, + kTypeChest, + kTypeDeathMap, + kTypeWater, + kTypeSpores, + kTypeWormFood, + kTypeChestKey, + kTypePhant, + kTypeGold, + kTypeHay, + kTypeBeam +}; + + +} // namespace immortal + +#endif \ No newline at end of file diff --git a/engines/immortal/story.h b/engines/immortal/story.h index 70e8fd48e49e..8787bf3ecdfd 100644 --- a/engines/immortal/story.h +++ b/engines/immortal/story.h @@ -19,47 +19,45 @@ * */ -#include "immortal/sprite_list.h" // This is an enum of all available sprites +// Definitions are the enum for the set of global definitions in Story.GS +#include "immortal/definitions.h" + +// Sprite List is a list of all sprite definitions (could be included in definitions.h, but sprite_list.gs was a separate source file and is sprite specific) +#include "immortal/sprite_list.h" #ifndef IMMORTAL_STORY_H #define IMMORTAL_STORY_H namespace Immortal { +struct Frame; +struct DataSprite; +struct Sprite; + // We need a few two-dimentional vectors, and writing them out in full each time is tedious template using CArray2D = Common::Array>; -enum DoorDir : bool { - kLeft = false, - kRight = true +// These maximum numbers aren't really needed, because most of these are vectors and have .size() +enum StoryMaxes { + kMaxRooms = 16, + kMaxDoors = 10, + kMaxFlames = 32, + kMaxFlamesInRoom = 5, + kMaxObjects = 42, + kMaxMonsters = 20, + kMaxGenSprites = 6, + kMaxCycles = 32 }; +// These are flags that are relevant to their specific story data structures enum RoomFlag : uint8 { // Generic properties available to each room - kRoomFlag0 = 0x1, - kRoomFlag1 = 0x2, - kRoomFlag2 = 0x4, - kRoomFlag3 = 0x8 -}; - -enum FPattern : uint8 { // This defines which Cyc animation it uses - kFlameNormal, - kFlameCandle, - kFlameOff, - kFlameGusty + kRoomFlag0 = 0x01, + kRoomFlag1 = 0x02, + kRoomFlag2 = 0x04, + kRoomFlag3 = 0x08 }; -enum OPMask : uint8 { // These are not actually needed anymore, they were for the original compiler method for making story.gs. Keeping it just in case for now - kOPMaskRoom, - kOPMaskInRoom, - kOPMaskFlame, - kOPMaskUnivAt, - kOPMaskMonster, - kOPMaskDoor, - kOPMaskObject, - kOPMaskRecord -}; - -enum ObjFlag : uint8 { +enum ObjFlag : uint8 { // Properties of the object essentially kObjUsesFireButton = 0x40, kObjIsInvisible = 0x20, kObjIsRunning = 0x10, @@ -67,10 +65,16 @@ enum ObjFlag : uint8 { kObjIsOnGround = 0x04, kObjIsF1 = 0x02, kObjIsF2 = 0x01, - kObjNone = 0x0 + kObjNone = 0x0 +}; + +enum IsA : uint8 { // To be completely honest, I'm not really sure what this is. It seems to be more object flags, but they act a little strangely + kIsAF1 = 0x20, + kIsAF2 = 0x40, + kIsANone = 0x0, }; -enum MonsterFlag : uint8 { +enum MonsterFlag : uint8 { // Mostly properties of the AI for a given monster, *including the player* kMonstIsNone = 0x00, kMonstIsTough = 0x10, kMonstIsDead = 0x20, @@ -87,195 +91,44 @@ enum MonsterFlag : uint8 { kMonstD = 0x07 }; -enum IsA : uint8 { - kIsAF1 = 0x20, - kIsAF2 = 0x40, - kIsANone = 0x0, -}; - -enum Motive { // This will likely be moved to a monster ai specific file later - kMotiveRoomCombat, - kMotiveShadeFind, - kMotiveShadeLoose, - kMotiveEngage, - kMotiveUpdateGoal, - kMotiveFollow, - kMotiveShadeHesitate, - kMotiveEasyRoomCombat, - kMotiveFind8, - kMotiveLoose4, - kMotiveDefensiveCombat, - kMotiveUlinTalk, - kMotiveGive, - kMotiveUseUpMonster, - kMotiveAliveRoomCombat, - kMotiveFindAlways, - kMotivePlayerCombat, - kMotiveJoystick, - kMotivePlayerDoor, - kMotivewaittalk2, - kMotiveGetDisturbed, - kMotiveLoose32, - kMotiveIfNot1Skip1, +// Flame pattern is used by the story data, in-room data, *and* the level based total flame data. So it needs to be in story.h to be used by immortal.h and room.h +enum FPattern : uint8 { // This defines which Cyc animation it uses + kFlameNormal, + kFlameCandle, + kFlameOff, + kFlameGusty }; -enum Str { - kStrNoDesc, - kStrSword, - kStrSwordDesc, - kStrBonesText1, - kStrBonesText2, - kStrBonesText3, - kStrComp, - kStrCompDesc, - kStrOpenBag, - kStrThrowComp, - kStrSmithText1, - kStrSmithText2, - kStrCarpet, - kStrBomb, - kStrBombDesc, - kStrPickItUp, - kStrYesNo, - kStrOther, - kStrChestKey, - kStrDoorKey, - kStrChestKeyDesc, - kStrOpenChestDesc, - kStrPutItOn, - kStrDropItThen, - kStrChestDesc, - kStrGoodChestDesc, - kStrBadChestDesc, - kStrComboLock, - kStrGold, - kStrFindGold, - kStrNull, - kStrNotHere, - kStrUnlockDoor, - kStrWeak1, - kStrDummyWater, - kStrBadWizard, - kStrDiesAnyway, - kStrDoorKeyDesc, - kStrNoteDesc, - kStrNote, - kStrLootBodyDesc, - kStrNotEnough, - kStrGameOver, - kStrYouWin, - kStrWormFoodDesc, - kStrWormFood, - kStrStoneDesc, - kStrStone, - kStrGemDesc, - kStrGem, - kStrFireBallDesc, - kStrFireBall, - kStrDeathMapDesc, - kStrDeathMap, - kStrBoots, - kStrUseBoots, - kStrWowCharmDesc, - kStrWowCharm, - kStrUseWowCharm, - kStrWaterOpen, - kStrDrinkIt, - kStrItWorks, - kStrSBOpen, - kStrUsesFire, - kStrMuscleDesc, - kStrMuscle, - kStrSBDesc, - kStrSB, - kStrFace, - kStrFaceDesc, - kStrTRNDesc, - kStrTRN, - kStrInvisDesc, - kStrGoodLuckDesc, - kStrAnaRing, - kStrInvis, - kStrGoesAway, - kStrGiveHerRing, - kStrGive2, - kStrMadKingText, - kStrMadKing3Text, - kStrMadKing2Text, - kStrDream1, - kStrDream1P2, - kStrDream1P3, - kStrHowToGetOut, - kStrSpore, - kStrSporeDesc, - kStrRequestPlayDisc, - kStrOldGame, - kStrEnterCertificate, - kStrBadCertificate, - kStrCert, - kStrCert2, - kStrTitle0, - kStrTitle4, - kStrMDesc, - kStrM3Desc, - kStrMapText1, - kStrMapText2, - - // Level 0 str - - // Level 1 str - - // Level 2 str - - // Level 3 str - - // Level 4 str - - // Level 5 str - - // Level 6 str - - // Level 7 str +enum DoorDir : bool { + kLeft = false, + kRight = true }; -enum SObjType { - kTypeTrap, - kTypeCoin, - kTypeWowCharm, - kTypeDead, - kTypeFireBall, - kTypeDunRing, - kTypeChest, - kTypeDeathMap, - kTypeWater, - kTypeSpores, - kTypeWormFood, - kTypeChestKey, - kTypePhant, - kTypeGold, - kTypeHay, - kTypeBeam +// Cycles define the animation of sprites within a level. There is a fixed total of cycles available, and they are not room dependant +struct Cycle { +DataSprite *_dSprite; + int _numCycles; + int *_frames; }; +// Object Pickup defines how an object can be picked up by the player, with different functions enum SObjPickup { - }; -enum SObjUse { - +struct Pickup { + //pointer to function + int _param; }; +// Iirc damage is used by object types as well as enemy types enum SDamage { - }; struct Damage { - }; -struct Pickup { - //pointer to function - int _param; +// Use is self explanitory, it defines the function and parameters for using an object +enum SObjUse { }; struct Use { @@ -301,7 +154,7 @@ struct SRoom { uint8 _x = 0; uint8 _y = 0; RoomFlag _flags = kRoomFlag0; - + SRoom() {} SRoom(uint8 x, uint8 y, RoomFlag f) { _x = x; _y = y; @@ -316,7 +169,7 @@ DoorDir _dir = kLeft; uint8 _fromRoom = 0; uint8 _toRoom = 0; bool _isLocked = false; - + SDoor() {} SDoor(DoorDir d, uint8 x, uint8 y, uint8 f, uint8 t, bool l) { _dir = d; _x = x; @@ -330,12 +183,12 @@ DoorDir _dir = kLeft; struct SFlame { uint8 _x = 0; uint8 _y = 0; -FPattern _pattern = kFlameOff; - +FPattern _p = kFlameOff; + SFlame() {} SFlame(uint8 x, uint8 y, FPattern p) { - _x = x; - _y = y; - _pattern = p; + _x = x; + _y = y; + _p = p; } }; @@ -346,7 +199,7 @@ struct SObj { uint8 _flags = 0; SpriteFrame _frame = kNoFrame; Common::Array _traps; - + SObj() {} SObj(uint8 x, uint8 y, SObjType t, SpriteFrame s, uint8 f, Common::Array traps) { _x = x; _y = y; @@ -365,15 +218,15 @@ MonsterFlag _madAt = kMonstIsNone; uint8 _flags = 0; SpriteName _sprite = kCandle; Common::Array _program; - + SMonster() {} SMonster(uint8 x, uint8 y, uint8 h, MonsterFlag m, uint8 f, Common::Array p, SpriteName s) { _x = x; _y = y; - _hits = h; - _madAt = m; - _flags = f; - _program = p; - _sprite = s; + _hits = h; + _madAt = m; + _flags = f; + _program = p; + _sprite = s; } }; From 63a6fe2851adf3c3b948a073cdb29db1e65849ed Mon Sep 17 00:00:00 2001 From: Quote58 Date: Tue, 16 Aug 2022 21:47:45 -0400 Subject: [PATCH 326/412] IMMORTAL: Update room skeleton, add flameSet, Univ, Door, and Bullet --- engines/immortal/bullet.cpp | 32 ++++++++++ engines/immortal/cycle.cpp | 23 ++++---- engines/immortal/door.cpp | 86 +++++++++++++++++++++++++++ engines/immortal/flameSet.cpp | 108 ++++++++++++++++++++++++++++++++++ engines/immortal/level.cpp | 33 ++++++----- engines/immortal/module.mk | 11 ++-- engines/immortal/room.cpp | 1 + engines/immortal/room.h | 105 ++++++++++++++++++++++++++++----- engines/immortal/univ.cpp | 27 +++++++++ 9 files changed, 379 insertions(+), 47 deletions(-) create mode 100644 engines/immortal/bullet.cpp create mode 100644 engines/immortal/door.cpp create mode 100644 engines/immortal/flameSet.cpp create mode 100644 engines/immortal/univ.cpp diff --git a/engines/immortal/bullet.cpp b/engines/immortal/bullet.cpp new file mode 100644 index 000000000000..e8770ec881e7 --- /dev/null +++ b/engines/immortal/bullet.cpp @@ -0,0 +1,32 @@ +/* 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 . + * + */ + +/* [Alternate Name: Projectile Proccessing] + * --- What is a Bullet --- + */ + +#include "immortal/room.h" + +namespace Immortal { + + + +} // namespace immortal \ No newline at end of file diff --git a/engines/immortal/cycle.cpp b/engines/immortal/cycle.cpp index e0a07d5cbde4..eeac61882085 100644 --- a/engines/immortal/cycle.cpp +++ b/engines/immortal/cycle.cpp @@ -23,23 +23,20 @@ * --- What is a Cycle --- */ -//#include "immortal/room.h" +#include "immortal/immortal.h" namespace Immortal { -// Most of these functions can probably be removed eventually -/* -void Room::cycleNew() {} - int Room::getCycleChr() { +void ImmortalEngine::cycleNew() {} + int ImmortalEngine::getCycleChr() { return 0; } -void Room::cycleFreeAll() {} -void Room::cycleGetFile() {} -void Room::cycleGetNum() {} -void Room::cycleGetIndex() {} -void Room::cycleSetIndex() {} -void Room::cycleGetFrame() {} -void Room::cycleAdvance() {} -*/ +void ImmortalEngine::cycleFreeAll() {} +void ImmortalEngine::cycleGetFile() {} +void ImmortalEngine::cycleGetNum() {} +void ImmortalEngine::cycleGetIndex() {} +void ImmortalEngine::cycleSetIndex() {} +void ImmortalEngine::cycleGetFrame() {} +void ImmortalEngine::cycleAdvance() {} } // namespace Immortal diff --git a/engines/immortal/door.cpp b/engines/immortal/door.cpp new file mode 100644 index 000000000000..1e93da60e601 --- /dev/null +++ b/engines/immortal/door.cpp @@ -0,0 +1,86 @@ +/* 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 . + * + */ + +/* [Alternate Name: Door Processing] + * --- What is a Door --- + */ + +#include "immortal/immortal.h" + +namespace Immortal { + +enum DoorMask { + kDoorXMask = 0x1f, + kDoorYMask = 0x1f, + kDoorFullMask = 0x40, + kDoorOnMask = 0x60 +}; + +enum DoorIs { + kDoorIsRight = 0x80, + kDoorIsBusy = 0x40, + kDoorIsLocked = 0x20 +}; + +enum DoorSide { + kDoorTopPriority = 64, + kDoorPriority = 85 - kDoorTopPriority, + kDoorLeftTop = 24, // To left of this enters door + kDoorRightTop = 8, // To right of this enters door + kDoorLeftBottom = 10, + kDoorRightBottom = 22, + kDoorTopBottom = 20 +}; + +void ImmortalEngine::doorOpenSecret() {} +void ImmortalEngine::doorCloseSecret() {} +void ImmortalEngine::doorInit() {} +void ImmortalEngine::doorClrLock() {} +void ImmortalEngine::doorNew() {} +void ImmortalEngine::doorDrawAll() {} +void ImmortalEngine::doorOnDoorMat() {} + int ImmortalEngine::findDoorTop(int x, int y) { + return 0; + } + int ImmortalEngine::findDoor(int x, int y) { + return 0; + } +bool ImmortalEngine::doLockStuff(int d, MonsterID m, int top) { + return true; +} +bool ImmortalEngine::inDoorTop(int x, int y, MonsterID m) { + return true; +} +bool ImmortalEngine::inDoor(int x, int y, MonsterID m) { + return true; +} + int ImmortalEngine::doorDoStep(MonsterID m, int d, int index) { + return 0; + } + int ImmortalEngine::doorSetOn(int d) { + return 0; + } + int ImmortalEngine::doorComeOut(MonsterID m) { + return 0; + } +void ImmortalEngine::doorSetLadders(MonsterID m) {} + +} // namespace immortal \ No newline at end of file diff --git a/engines/immortal/flameSet.cpp b/engines/immortal/flameSet.cpp new file mode 100644 index 000000000000..70169845ce51 --- /dev/null +++ b/engines/immortal/flameSet.cpp @@ -0,0 +1,108 @@ +/* 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 . + * + */ + +/* [Alternate Name: Torch Processing] + * --- What is a FlameSet --- + * A FlameSet is a list of torches in a given room. + * The level has X amount of flames total, and each + * room has N amount of torches, making up a FlameSet. + * There are 3 instances of torches in the game. + * First is in the story record, second is in the level torches, + * and lastly is the in-room torch. This is done so that + * the in-room torch can be lit up by a fireball and then + * stay permanantly lit for the next time the player enters the room. + */ + +#include "immortal/room.h" + +namespace Immortal { + +void Room::flameSetRoom(Common::Array allFlames) { + for (int i = 0; i < allFlames.size(); i++) { + Flame f; + f._p = allFlames[i]._p; + f._x = allFlames[i]._x; + f._y = allFlames[i]._y; + f._c = flameGetCyc(0 | _candleTmp); + _candleTmp = 1; + _fset.push_back(f); + } +} + +void Room::flameDrawAll() { + +} + +bool Room::roomLighted() { + // Very simple, just checks every torch and if any of them are lit, we say the room is lit + for (int i = 0; i < _fset.size(); i++) { + if (_fset[i]._p != kFlameOff) { + return true; + } + } + return false; +} + +void Room::lightTorch(int x, int y) { + /* Checks every torch to see if it is: + * pattern == off, and inside the point x,y + * which is the fireball position. This is a + * little bit clever, because it saves cycles + * over checking x,y first, since you need to + * check both x,y and flame pattern. Neato. + */ + + for (int i = 0; i < _fset.size(); i++) { + if (_fset[i]._p == kFlameOff) { + if (Immortal::Util::inside(x, y, kLightTorchX, _fset[i]._x + 16, _fset[i]._y + 8)) { + _fset[i]._p = kFlameNormal; + + } + } + } +} + +Cyc Room::flameGetCyc(int first) { + return kCycNone; +} + +} // namespace immortal + + + + + + + + + + + + + + + + + + + + + diff --git a/engines/immortal/level.cpp b/engines/immortal/level.cpp index 59ff8739c1f5..35139a967ea4 100644 --- a/engines/immortal/level.cpp +++ b/engines/immortal/level.cpp @@ -39,10 +39,6 @@ void ImmortalEngine::levelInit() { void ImmortalEngine::levelNew(int l) { stopMusic(); clearScreen(); - /* commented out in the source for some reason? */ - for (int i = 0; i < kMaxRooms; i++) { - delete _rooms[i]; - } levelStory(l); if (kLevelToMaze[l] != _lastLevelLoaded) { @@ -67,7 +63,7 @@ void ImmortalEngine::levelStory(int l) { } void ImmortalEngine::levelLoadFile(int l) { -// _dRoomNum = 0; + // _dRoomNum = 0; /* This was originally a large branching tree that checked the identifier of each entry and * Processed them all for the story. Once again, this would have been better as an indexed @@ -76,34 +72,42 @@ void ImmortalEngine::levelLoadFile(int l) { */ // Create the rooms and doors, then populate the rooms with their objects and actors + debug("loading level file..."); for (int r = 0; r < _stories[l]._rooms.size(); r++) { _rooms[r] = new Room(_stories[l]._rooms[r]._x, _stories[l]._rooms[r]._y, _stories[l]._rooms[r]._flags); - //doorNew(_stories[l]._doors[i]); + //doorNew(_stories[l]._doors[r]); debug("Room %d", r); - for (int f = 0; f < _stories[l]._flames.size(); f++) { - if (_stories[l]._flames[r].size() > 0) { - //Flame flame; - //_rooms[r]->_flames.push_back(flame); + + Common::Array allFlames(_stories[l]._flames[r].size()); + if (_stories[l]._flames[r].size() > 0) { + for (int f = 0; f < _stories[l]._flames[r].size(); f++) { + SFlame sf; + sf._p = _stories[l]._flames[r][f]._p; + sf._x = _stories[l]._flames[r][f]._x; + sf._y = _stories[l]._flames[r][f]._y; + allFlames[f] = sf; debugN("F%d", f); } } + _allFlames[r] = allFlames; debug(""); - for (int o = 0; o < _stories[l]._objects.size(); o++) { - if (_stories[l]._objects[r].size() > 0) { + if (_stories[l]._objects[r].size() > 0) { + for (int o = 0; o < _stories[l]._objects[r].size(); o++) { //objNew(_stories[l]._objects[r][o]); debugN("O%d", o); } } debug(""); - for (int m = 0; m < _stories[l]._monsters.size(); m++) { - if (_stories[l]._monsters[r].size() > 0) { + if (_stories[l]._monsters[r].size() > 0) { + for (int m = 0; m < _stories[l]._monsters[r].size(); m++) { //monstNew(_stories[l]._monsters[r][m]); debugN("M%d", m); } } debug(""); + } // Set up the _initial variables for the engine scope @@ -131,6 +135,7 @@ void ImmortalEngine::levelDrawAll() { void ImmortalEngine::levelShowRoom(int r, int bX, int bY) { _currentRoom = r; + _rooms[r]->flameSetRoom(_allFlames[r]); //univSetRoom(r, bX, bY); //fset, spark, bullet, and door get set to the current room //roomGetCell(r, bX, bY); diff --git a/engines/immortal/module.mk b/engines/immortal/module.mk index ac6c8f3bed01..16713fcb9353 100644 --- a/engines/immortal/module.mk +++ b/engines/immortal/module.mk @@ -2,6 +2,7 @@ MODULE := engines/immortal MODULE_OBJS = \ metaengine.o \ + util.o \ disk.o \ immortal.o \ kernal.o \ @@ -13,13 +14,13 @@ MODULE_OBJS = \ drawChr.o \ level.o \ story.o \ - room.o + room.o \ + flameSet.o \ + univ.o \ + door.o \ + bullet.o -# universe.o \ # object.o \ -# door.o \ -# flameset.o \ -# bullet.o \ # monster.o \ # motives.o diff --git a/engines/immortal/room.cpp b/engines/immortal/room.cpp index dc6f49db2adc..320624f16955 100644 --- a/engines/immortal/room.cpp +++ b/engines/immortal/room.cpp @@ -27,6 +27,7 @@ Room::Room(uint8 x, uint8 y, RoomFlag f) { _xPos = x; _yPos = y; _flags = f; + _candleTmp = 0; } void Room::addMonster() { diff --git a/engines/immortal/room.h b/engines/immortal/room.h index 8c07a7f01614..7b7fb8463823 100644 --- a/engines/immortal/room.h +++ b/engines/immortal/room.h @@ -23,10 +23,28 @@ * */ -#include "common/file.h" -#include "common/memstream.h" +// Common is needed by immortal.h, room.h, and monster.h #include "common/debug.h" +#include "common/debug-channels.h" +#include "common/events.h" +#include "common/scummsys.h" +#include "common/system.h" #include "common/error.h" +#include "common/fs.h" +#include "common/file.h" +#include "common/memstream.h" +#include "common/hash-str.h" +#include "common/random.h" +#include "common/serializer.h" +#include "common/util.h" +#include "common/platform.h" + +// There is a lot of bit masking that needs to happen, so this header includes several enums for immortal.h, room.h, and monster.h +#include "immortal/bitmask.h" + +#include "immortal/util.h" + +// Story is needed by both immortal.h and room.h #include "immortal/story.h" #ifndef IMMORTAL_ROOM_H @@ -49,8 +67,19 @@ enum Tile : uint8 { kTileCeilingTile = 2 }; -struct Flame { -}; +/* Quick note: + * This looks entirely redundant and silly, I agree. However + * this is because the source does more or less the same thing. + * At compile time, it creates and stores in memory what are the + * equivalent of structs (or maybe tuples), and then at run time + * when creating a room, it makes room specific versions that can + * be changed. So essentially it creates two RAM structs and then + * treats the first as ROM. As such, that's what I'm doing here. + * The 'Story' structs are ROM, the 'Room' structs are RAM. There + * are also slight differences, like how the room Flame has a reference + * to the Cyc it is using. Although again the Story ones are ram + * and could do this too. + */ // Temp struct Object { @@ -60,7 +89,11 @@ struct Object { struct Monster { }; -struct Spark { +struct Flame { +FPattern _p; + uint8 _x; + uint8 _y; + Cyc _c; }; struct Chest { @@ -76,16 +109,35 @@ class Room { Room(uint8 x, uint8 y, RoomFlag f); ~Room() {} + /* + * --- Data --- + * + */ + + // Constants + const uint8 kLightTorchX = 10; + Common::Array _fset; Common::Array _monsters; Common::Array _objects; - RoomFlag _flags; - uint8 _xPos; - uint8 _yPos; - uint8 _holeRoom; - uint8 _holeCellX; - uint8 _holeCellY; + RoomFlag _flags; + uint8 _xPos; + uint8 _yPos; + uint8 _holeRoom; + uint8 _holeCellX; + uint8 _holeCellY; + uint8 _candleTmp; // Special case for candle in maze 0 + + + /* + * --- Methods --- + * + */ + + /* + * [room.cpp] Functions from Room.GS + */ //void init(); //void inRoomNew(); @@ -100,12 +152,35 @@ Common::Array _objects; void addObject(); void removeObject(); void removeMonster(); - -Common::Array getMonsterList(); -Common::Array getObjectList(); - + Common::Array getMonsterList(); + Common::Array getObjectList(); void getXY(uint16 &x, uint16 &y); void getCell(uint16 &x, uint16 &y); + + + /* + * [flameSet.cpp] Functions from flameSet.GS + */ + + void flameSetRoom(Common::Array); + void flameDrawAll(); + bool roomLighted(); + void lightTorch(int x, int y); + Cyc flameGetCyc(int first); + //void flameFreeAll(); + //void flameSetRoom(); + + /* + * [bullet.cpp] Functions from Bullet.GS + */ + + + + /* + * [object.cpp] Functions from Object.GS + */ + + }; diff --git a/engines/immortal/univ.cpp b/engines/immortal/univ.cpp new file mode 100644 index 000000000000..7349cdbff8a1 --- /dev/null +++ b/engines/immortal/univ.cpp @@ -0,0 +1,27 @@ +/* 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 "immortal/immortal.h" + +namespace Immortal { + + +} // namespace immortal \ No newline at end of file From fe6ef5d0d681b7032cc5a2af94adaeb6a2db193e Mon Sep 17 00:00:00 2001 From: Quote58 Date: Tue, 16 Aug 2022 21:55:02 -0400 Subject: [PATCH 327/412] IMMORTAL: Spaces -> Tabs --- engines/immortal/bitmask.h | 38 ++-- engines/immortal/definitions.h | 316 ++++++++++++++++----------------- engines/immortal/door.cpp | 44 ++--- engines/immortal/flameSet.cpp | 66 +++---- engines/immortal/misc.cpp | 4 +- 5 files changed, 234 insertions(+), 234 deletions(-) diff --git a/engines/immortal/bitmask.h b/engines/immortal/bitmask.h index e1b7f6a49822..d9b5ba1509ae 100644 --- a/engines/immortal/bitmask.h +++ b/engines/immortal/bitmask.h @@ -25,34 +25,34 @@ namespace Immortal { enum BitMask16 : uint16 { - kMaskLow = 0x00FF, - kMaskHigh = 0xFF00, - kMaskLast = 0xF000, - kMaskFirst = 0x000F, - kMaskHLow = 0x0F00, - kMaskLHigh = 0x00F0, - kMaskNeg = 0x8000, - kMask12Bit = 0x0F9F // Compression code (pos, 00, len) is stored in lower 12 bits of word + kMaskLow = 0x00FF, + kMaskHigh = 0xFF00, + kMaskLast = 0xF000, + kMaskFirst = 0x000F, + kMaskHLow = 0x0F00, + kMaskLHigh = 0x00F0, + kMaskNeg = 0x8000, + kMask12Bit = 0x0F9F // Compression code (pos, 00, len) is stored in lower 12 bits of word }; enum BitMask8 : uint8 { - kMaskASCII = 0x7F, // The non-extended ASCII table uses 7 bits, this makes a couple of things easier - kMask8High = 0xF0, - kMask8Low = 0x0F + kMaskASCII = 0x7F, // The non-extended ASCII table uses 7 bits, this makes a couple of things easier + kMask8High = 0xF0, + kMask8Low = 0x0F }; enum ColourBitMask : uint16 { - kMaskRed = 0x0F00, - kMaskGreen = 0x00F0, - kMaskBlue = 0x000F + kMaskRed = 0x0F00, + kMaskGreen = 0x00F0, + kMaskBlue = 0x000F }; enum ChrMask : uint16 { - kChr0 = 0x0000, - kChrL = 0x0001, - kChrR = 0xFFFF, - kChrLD = 0x0002, - kChrRD = 0xFFFE + kChr0 = 0x0000, + kChrL = 0x0001, + kChrR = 0xFFFF, + kChrLD = 0x0002, + kChrRD = 0xFFFE }; } // namespace immortal diff --git a/engines/immortal/definitions.h b/engines/immortal/definitions.h index 73082333927d..1991d790c36a 100644 --- a/engines/immortal/definitions.h +++ b/engines/immortal/definitions.h @@ -25,173 +25,173 @@ namespace Immortal { enum Cyc { - kCycNone + kCycNone }; enum Motive { // This will likely be moved to a monster ai specific file later - kMotiveRoomCombat, - kMotiveShadeFind, - kMotiveShadeLoose, - kMotiveEngage, - kMotiveUpdateGoal, - kMotiveFollow, - kMotiveShadeHesitate, - kMotiveEasyRoomCombat, - kMotiveFind8, - kMotiveLoose4, - kMotiveDefensiveCombat, - kMotiveUlinTalk, - kMotiveGive, - kMotiveUseUpMonster, - kMotiveAliveRoomCombat, - kMotiveFindAlways, - kMotivePlayerCombat, - kMotiveJoystick, - kMotivePlayerDoor, - kMotivewaittalk2, - kMotiveGetDisturbed, - kMotiveLoose32, - kMotiveIfNot1Skip1, + kMotiveRoomCombat, + kMotiveShadeFind, + kMotiveShadeLoose, + kMotiveEngage, + kMotiveUpdateGoal, + kMotiveFollow, + kMotiveShadeHesitate, + kMotiveEasyRoomCombat, + kMotiveFind8, + kMotiveLoose4, + kMotiveDefensiveCombat, + kMotiveUlinTalk, + kMotiveGive, + kMotiveUseUpMonster, + kMotiveAliveRoomCombat, + kMotiveFindAlways, + kMotivePlayerCombat, + kMotiveJoystick, + kMotivePlayerDoor, + kMotivewaittalk2, + kMotiveGetDisturbed, + kMotiveLoose32, + kMotiveIfNot1Skip1, }; enum Str { - kStrNoDesc, - kStrSword, - kStrSwordDesc, - kStrBonesText1, - kStrBonesText2, - kStrBonesText3, - kStrComp, - kStrCompDesc, - kStrOpenBag, - kStrThrowComp, - kStrSmithText1, - kStrSmithText2, - kStrCarpet, - kStrBomb, - kStrBombDesc, - kStrPickItUp, - kStrYesNo, - kStrOther, - kStrChestKey, - kStrDoorKey, - kStrChestKeyDesc, - kStrOpenChestDesc, - kStrPutItOn, - kStrDropItThen, - kStrChestDesc, - kStrGoodChestDesc, - kStrBadChestDesc, - kStrComboLock, - kStrGold, - kStrFindGold, - kStrNull, - kStrNotHere, - kStrUnlockDoor, - kStrWeak1, - kStrDummyWater, - kStrBadWizard, - kStrDiesAnyway, - kStrDoorKeyDesc, - kStrNoteDesc, - kStrNote, - kStrLootBodyDesc, - kStrNotEnough, - kStrGameOver, - kStrYouWin, - kStrWormFoodDesc, - kStrWormFood, - kStrStoneDesc, - kStrStone, - kStrGemDesc, - kStrGem, - kStrFireBallDesc, - kStrFireBall, - kStrDeathMapDesc, - kStrDeathMap, - kStrBoots, - kStrUseBoots, - kStrWowCharmDesc, - kStrWowCharm, - kStrUseWowCharm, - kStrWaterOpen, - kStrDrinkIt, - kStrItWorks, - kStrSBOpen, - kStrUsesFire, - kStrMuscleDesc, - kStrMuscle, - kStrSBDesc, - kStrSB, - kStrFace, - kStrFaceDesc, - kStrTRNDesc, - kStrTRN, - kStrInvisDesc, - kStrGoodLuckDesc, - kStrAnaRing, - kStrInvis, - kStrGoesAway, - kStrGiveHerRing, - kStrGive2, - kStrMadKingText, - kStrMadKing3Text, - kStrMadKing2Text, - kStrDream1, - kStrDream1P2, - kStrDream1P3, - kStrHowToGetOut, - kStrSpore, - kStrSporeDesc, - kStrRequestPlayDisc, - kStrOldGame, - kStrEnterCertificate, - kStrBadCertificate, - kStrCert, - kStrCert2, - kStrTitle0, - kStrTitle4, - kStrMDesc, - kStrM3Desc, - kStrMapText1, - kStrMapText2, - - // Level 0 str - - // Level 1 str - - // Level 2 str - - // Level 3 str - - // Level 4 str - - // Level 5 str - - // Level 6 str - - // Level 7 str - - kCantUnlockDoor = kStrBadChestDesc + kStrNoDesc, + kStrSword, + kStrSwordDesc, + kStrBonesText1, + kStrBonesText2, + kStrBonesText3, + kStrComp, + kStrCompDesc, + kStrOpenBag, + kStrThrowComp, + kStrSmithText1, + kStrSmithText2, + kStrCarpet, + kStrBomb, + kStrBombDesc, + kStrPickItUp, + kStrYesNo, + kStrOther, + kStrChestKey, + kStrDoorKey, + kStrChestKeyDesc, + kStrOpenChestDesc, + kStrPutItOn, + kStrDropItThen, + kStrChestDesc, + kStrGoodChestDesc, + kStrBadChestDesc, + kStrComboLock, + kStrGold, + kStrFindGold, + kStrNull, + kStrNotHere, + kStrUnlockDoor, + kStrWeak1, + kStrDummyWater, + kStrBadWizard, + kStrDiesAnyway, + kStrDoorKeyDesc, + kStrNoteDesc, + kStrNote, + kStrLootBodyDesc, + kStrNotEnough, + kStrGameOver, + kStrYouWin, + kStrWormFoodDesc, + kStrWormFood, + kStrStoneDesc, + kStrStone, + kStrGemDesc, + kStrGem, + kStrFireBallDesc, + kStrFireBall, + kStrDeathMapDesc, + kStrDeathMap, + kStrBoots, + kStrUseBoots, + kStrWowCharmDesc, + kStrWowCharm, + kStrUseWowCharm, + kStrWaterOpen, + kStrDrinkIt, + kStrItWorks, + kStrSBOpen, + kStrUsesFire, + kStrMuscleDesc, + kStrMuscle, + kStrSBDesc, + kStrSB, + kStrFace, + kStrFaceDesc, + kStrTRNDesc, + kStrTRN, + kStrInvisDesc, + kStrGoodLuckDesc, + kStrAnaRing, + kStrInvis, + kStrGoesAway, + kStrGiveHerRing, + kStrGive2, + kStrMadKingText, + kStrMadKing3Text, + kStrMadKing2Text, + kStrDream1, + kStrDream1P2, + kStrDream1P3, + kStrHowToGetOut, + kStrSpore, + kStrSporeDesc, + kStrRequestPlayDisc, + kStrOldGame, + kStrEnterCertificate, + kStrBadCertificate, + kStrCert, + kStrCert2, + kStrTitle0, + kStrTitle4, + kStrMDesc, + kStrM3Desc, + kStrMapText1, + kStrMapText2, + + // Level 0 str + + // Level 1 str + + // Level 2 str + + // Level 3 str + + // Level 4 str + + // Level 5 str + + // Level 6 str + + // Level 7 str + + kCantUnlockDoor = kStrBadChestDesc }; enum SObjType { - kTypeTrap, - kTypeCoin, - kTypeWowCharm, - kTypeDead, - kTypeFireBall, - kTypeDunRing, - kTypeChest, - kTypeDeathMap, - kTypeWater, - kTypeSpores, - kTypeWormFood, - kTypeChestKey, - kTypePhant, - kTypeGold, - kTypeHay, - kTypeBeam + kTypeTrap, + kTypeCoin, + kTypeWowCharm, + kTypeDead, + kTypeFireBall, + kTypeDunRing, + kTypeChest, + kTypeDeathMap, + kTypeWater, + kTypeSpores, + kTypeWormFood, + kTypeChestKey, + kTypePhant, + kTypeGold, + kTypeHay, + kTypeBeam }; diff --git a/engines/immortal/door.cpp b/engines/immortal/door.cpp index 1e93da60e601..b31a7d5fd4f5 100644 --- a/engines/immortal/door.cpp +++ b/engines/immortal/door.cpp @@ -28,26 +28,26 @@ namespace Immortal { enum DoorMask { - kDoorXMask = 0x1f, - kDoorYMask = 0x1f, - kDoorFullMask = 0x40, - kDoorOnMask = 0x60 + kDoorXMask = 0x1f, + kDoorYMask = 0x1f, + kDoorFullMask = 0x40, + kDoorOnMask = 0x60 }; enum DoorIs { - kDoorIsRight = 0x80, - kDoorIsBusy = 0x40, - kDoorIsLocked = 0x20 + kDoorIsRight = 0x80, + kDoorIsBusy = 0x40, + kDoorIsLocked = 0x20 }; enum DoorSide { - kDoorTopPriority = 64, - kDoorPriority = 85 - kDoorTopPriority, - kDoorLeftTop = 24, // To left of this enters door - kDoorRightTop = 8, // To right of this enters door - kDoorLeftBottom = 10, - kDoorRightBottom = 22, - kDoorTopBottom = 20 + kDoorTopPriority = 64, + kDoorPriority = 85 - kDoorTopPriority, + kDoorLeftTop = 24, // To left of this enters door + kDoorRightTop = 8, // To right of this enters door + kDoorLeftBottom = 10, + kDoorRightBottom = 22, + kDoorTopBottom = 20 }; void ImmortalEngine::doorOpenSecret() {} @@ -58,28 +58,28 @@ void ImmortalEngine::doorNew() {} void ImmortalEngine::doorDrawAll() {} void ImmortalEngine::doorOnDoorMat() {} int ImmortalEngine::findDoorTop(int x, int y) { - return 0; + return 0; } int ImmortalEngine::findDoor(int x, int y) { - return 0; + return 0; } bool ImmortalEngine::doLockStuff(int d, MonsterID m, int top) { - return true; + return true; } bool ImmortalEngine::inDoorTop(int x, int y, MonsterID m) { - return true; + return true; } bool ImmortalEngine::inDoor(int x, int y, MonsterID m) { - return true; + return true; } int ImmortalEngine::doorDoStep(MonsterID m, int d, int index) { - return 0; + return 0; } int ImmortalEngine::doorSetOn(int d) { - return 0; + return 0; } int ImmortalEngine::doorComeOut(MonsterID m) { - return 0; + return 0; } void ImmortalEngine::doorSetLadders(MonsterID m) {} diff --git a/engines/immortal/flameSet.cpp b/engines/immortal/flameSet.cpp index 70169845ce51..fe335010cf40 100644 --- a/engines/immortal/flameSet.cpp +++ b/engines/immortal/flameSet.cpp @@ -36,15 +36,15 @@ namespace Immortal { void Room::flameSetRoom(Common::Array allFlames) { - for (int i = 0; i < allFlames.size(); i++) { - Flame f; - f._p = allFlames[i]._p; - f._x = allFlames[i]._x; - f._y = allFlames[i]._y; - f._c = flameGetCyc(0 | _candleTmp); - _candleTmp = 1; - _fset.push_back(f); - } + for (int i = 0; i < allFlames.size(); i++) { + Flame f; + f._p = allFlames[i]._p; + f._x = allFlames[i]._x; + f._y = allFlames[i]._y; + f._c = flameGetCyc(0 | _candleTmp); + _candleTmp = 1; + _fset.push_back(f); + } } void Room::flameDrawAll() { @@ -52,36 +52,36 @@ void Room::flameDrawAll() { } bool Room::roomLighted() { - // Very simple, just checks every torch and if any of them are lit, we say the room is lit - for (int i = 0; i < _fset.size(); i++) { - if (_fset[i]._p != kFlameOff) { - return true; - } - } - return false; + // Very simple, just checks every torch and if any of them are lit, we say the room is lit + for (int i = 0; i < _fset.size(); i++) { + if (_fset[i]._p != kFlameOff) { + return true; + } + } + return false; } void Room::lightTorch(int x, int y) { - /* Checks every torch to see if it is: - * pattern == off, and inside the point x,y - * which is the fireball position. This is a - * little bit clever, because it saves cycles - * over checking x,y first, since you need to - * check both x,y and flame pattern. Neato. - */ - - for (int i = 0; i < _fset.size(); i++) { - if (_fset[i]._p == kFlameOff) { - if (Immortal::Util::inside(x, y, kLightTorchX, _fset[i]._x + 16, _fset[i]._y + 8)) { - _fset[i]._p = kFlameNormal; - - } - } - } + /* Checks every torch to see if it is: + * pattern == off, and inside the point x,y + * which is the fireball position. This is a + * little bit clever, because it saves cycles + * over checking x,y first, since you need to + * check both x,y and flame pattern. Neato. + */ + + for (int i = 0; i < _fset.size(); i++) { + if (_fset[i]._p == kFlameOff) { + if (Immortal::Util::inside(x, y, kLightTorchX, _fset[i]._x + 16, _fset[i]._y + 8)) { + _fset[i]._p = kFlameNormal; + + } + } + } } Cyc Room::flameGetCyc(int first) { - return kCycNone; + return kCycNone; } } // namespace immortal diff --git a/engines/immortal/misc.cpp b/engines/immortal/misc.cpp index 79e77585dd9f..2eb393c2265b 100644 --- a/engines/immortal/misc.cpp +++ b/engines/immortal/misc.cpp @@ -32,8 +32,8 @@ namespace Immortal { */ void ImmortalEngine::miscInit() { - // In the source, this is where the seed for the rng is set, but we don't need to do that as we used _randomSource - _lastGauge = 0; + // In the source, this is where the seed for the rng is set, but we don't need to do that as we used _randomSource + _lastGauge = 0; } void ImmortalEngine::setRandomSeed() {} From 22a3535e34d4789d8e19edbda7ed7c805f94fcc8 Mon Sep 17 00:00:00 2001 From: Quote58 Date: Wed, 17 Aug 2022 00:18:04 -0400 Subject: [PATCH 328/412] IMMORTAL: levelLoadFile initializes level doors --- engines/immortal/door.cpp | 14 ++++++++++++-- engines/immortal/immortal.h | 12 ++++++------ engines/immortal/level.cpp | 11 +++++++---- engines/immortal/story.cpp | 8 ++++---- engines/immortal/story.h | 15 +++++---------- 5 files changed, 34 insertions(+), 26 deletions(-) diff --git a/engines/immortal/door.cpp b/engines/immortal/door.cpp index b31a7d5fd4f5..a97820658bcc 100644 --- a/engines/immortal/door.cpp +++ b/engines/immortal/door.cpp @@ -28,7 +28,7 @@ namespace Immortal { enum DoorMask { - kDoorXMask = 0x1f, + kDoorXMask = 0x1f, // Only relevant for extracting the data from the compressed bytes in the story record kDoorYMask = 0x1f, kDoorFullMask = 0x40, kDoorOnMask = 0x60 @@ -54,7 +54,17 @@ void ImmortalEngine::doorOpenSecret() {} void ImmortalEngine::doorCloseSecret() {} void ImmortalEngine::doorInit() {} void ImmortalEngine::doorClrLock() {} -void ImmortalEngine::doorNew() {} +void ImmortalEngine::doorNew(SDoor door) { + Door d; + d._x = door._x; + d._y = door._y; + d._fromRoom = door._fromRoom; + d._toRoom = door._toRoom; + d._busyOnRight = door._dir | door._x; + d._on = door._y & kDoorYMask; + _doors.push_back(d); +} + void ImmortalEngine::doorDrawAll() {} void ImmortalEngine::doorOnDoorMat() {} int ImmortalEngine::findDoorTop(int x, int y) { diff --git a/engines/immortal/immortal.h b/engines/immortal/immortal.h index 3287f2a0b69e..927ad250d1e4 100644 --- a/engines/immortal/immortal.h +++ b/engines/immortal/immortal.h @@ -144,13 +144,12 @@ struct GenericSprite { struct Door { uint8 _x = 0; uint8 _y = 0; - uint8 _from = 0; - uint8 _to = 0; + uint8 _fromRoom = 0; + uint8 _toRoom = 0; uint8 _busyOnRight = 0; uint8 _on = 0; }; - // Sprites are handled by driver in Kernal struct Frame { uint16 _deltaX; @@ -333,8 +332,8 @@ class ImmortalEngine : public Engine { int _initialBX; int _initialBY; int _dRoomNum; - int _initialRoom; - int _currentRoom; + int _initialRoom = 0; + int _currentRoom = 0; int _lastType; int _roomCellX; int _roomCellY; @@ -342,6 +341,7 @@ class ImmortalEngine : public Engine { Common::Array _allFlames[kMaxRooms]; // The level needs it's own set of flames so that the flames can be turned on/off permenantly. This is technically more like a hashmap in the source, but it could also be seen as a 2d array, just hashed together in the source // Door members + Common::Array _doors; uint8 _numDoors = 0; uint8 _doorRoom = 0; uint8 _doorToNextLevel = 0; @@ -662,7 +662,7 @@ GenericSprite _genSprites[6]; //void doorToNextLevel(); void doorInit(); void doorClrLock(); - void doorNew(); + void doorNew(SDoor door); void doorDrawAll(); void doorOnDoorMat(); //void doorEnter(); // <-- this is actually a method of Player Monster, should probably move it there later diff --git a/engines/immortal/level.cpp b/engines/immortal/level.cpp index 35139a967ea4..b125d6ed6b3d 100644 --- a/engines/immortal/level.cpp +++ b/engines/immortal/level.cpp @@ -63,8 +63,6 @@ void ImmortalEngine::levelStory(int l) { } void ImmortalEngine::levelLoadFile(int l) { - // _dRoomNum = 0; - /* This was originally a large branching tree that checked the identifier of each entry and * Processed them all for the story. Once again, this would have been better as an indexed * JSR instead of a set of comparisons and branches. Regardless, we instead use the information @@ -73,9 +71,14 @@ void ImmortalEngine::levelLoadFile(int l) { // Create the rooms and doors, then populate the rooms with their objects and actors debug("loading level file..."); + + for (int d = 0; d < _stories[l]._doors.size(); d++) { + doorNew(_stories[l]._doors[d]); + debug("door %d", d); + } + for (int r = 0; r < _stories[l]._rooms.size(); r++) { _rooms[r] = new Room(_stories[l]._rooms[r]._x, _stories[l]._rooms[r]._y, _stories[l]._rooms[r]._flags); - //doorNew(_stories[l]._doors[r]); debug("Room %d", r); Common::Array allFlames(_stories[l]._flames[r].size()); @@ -130,7 +133,7 @@ void ImmortalEngine::levelDrawAll() { _count++; //univAutoCenter(); clearSprites(); - //rooms[_currentRoom].drawContents(); + _rooms[_currentRoom]->drawContents(); } void ImmortalEngine::levelShowRoom(int r, int bX, int bY) { diff --git a/engines/immortal/story.cpp b/engines/immortal/story.cpp index 875b3f5857d0..e7c1424e45a4 100644 --- a/engines/immortal/story.cpp +++ b/engines/immortal/story.cpp @@ -102,10 +102,10 @@ void ImmortalEngine::initStoryDynamic() { /* All of the doors */ - Common::Array doors{SDoor(kLeft, 704, 224, 0, 2, false), SDoor(kRight, 576, 352, 4, 0, true), - SDoor(kRight, 704,96, 2, 1, false), SDoor(kRight, 960,128, 7, 2, false), - SDoor(kRight, 1088,160, 3, 7, false), SDoor(kRight, 1088,320, 6, 3, false), - SDoor(kRight, 896,416, 4, 3, false)}; + Common::Array doors{SDoor(0, 704, 224, 0, 2, false), SDoor(1, 576, 352, 4, 0, true), + SDoor(1, 704, 96, 2, 1, false), SDoor(1, 960, 128, 7, 2, false), + SDoor(1, 1088,160, 3, 7, false), SDoor(1, 1088,320, 6, 3, false), + SDoor(1, 896, 416, 4, 3, false)}; _stories[0]._doors = doors; /* All of the flames diff --git a/engines/immortal/story.h b/engines/immortal/story.h index 8787bf3ecdfd..bcb20a001c5d 100644 --- a/engines/immortal/story.h +++ b/engines/immortal/story.h @@ -99,11 +99,6 @@ enum FPattern : uint8 { // This defines which Cyc animation it uses kFlameGusty }; -enum DoorDir : bool { - kLeft = false, - kRight = true -}; - // Cycles define the animation of sprites within a level. There is a fixed total of cycles available, and they are not room dependant struct Cycle { DataSprite *_dSprite; @@ -163,14 +158,14 @@ struct SRoom { }; struct SDoor { -DoorDir _dir = kLeft; - uint8 _x = 0; - uint8 _y = 0; + uint8 _dir = 0; + uint8 _x = 0; + uint8 _y = 0; uint8 _fromRoom = 0; - uint8 _toRoom = 0; + uint8 _toRoom = 0; bool _isLocked = false; SDoor() {} - SDoor(DoorDir d, uint8 x, uint8 y, uint8 f, uint8 t, bool l) { + SDoor(uint8 d, uint8 x, uint8 y, uint8 f, uint8 t, bool l) { _dir = d; _x = x; _y = y; From 3d696d0e01618c609b9308e6dd8f9a489b6cb797 Mon Sep 17 00:00:00 2001 From: Quote58 Date: Fri, 19 Aug 2022 03:51:03 -0400 Subject: [PATCH 329/412] IMMORTAL: Frame -> Image, and Image/DataSprite/Cycle moved to sprite_list.h --- engines/immortal/immortal.h | 43 +++++++++++----------------------- engines/immortal/sprite_list.h | 23 ++++++++++++++++++ engines/immortal/sprites.cpp | 30 ++++++++++++------------ engines/immortal/story.h | 11 --------- 4 files changed, 52 insertions(+), 55 deletions(-) diff --git a/engines/immortal/immortal.h b/engines/immortal/immortal.h index 927ad250d1e4..a063b7a67b74 100644 --- a/engines/immortal/immortal.h +++ b/engines/immortal/immortal.h @@ -151,23 +151,8 @@ struct Door { }; // Sprites are handled by driver in Kernal -struct Frame { - uint16 _deltaX; - uint16 _deltaY; - uint16 _rectX; - uint16 _rectY; - byte *_bitmap; -}; - -struct DataSprite { - uint16 _cenX; // These are the base center positions - uint16 _cenY; - uint16 _numFrames; -Common::Array _frames; -}; - struct Sprite { - int _frame; // Index of _dSprite._frames[] + int _image; // Index of _dSprite._frames[] uint16 _X; uint16 _Y; uint16 _on; // 1 = active @@ -369,9 +354,9 @@ class ImmortalEngine : public Engine { // Asset members int _numSprites = 0; // This is more accurately actually the index within the sprite array, so _numSprites + 1 is the current number of sprites - DataSprite _font; // The font sprite data is loaded separate from other sprite stuff - Sprite _sprites[kMaxSprites]; // All the sprites shown on screen DataSprite _dataSprites[kFont + 1]; // All the sprite data, indexed by SpriteFile + Sprite _sprites[kMaxSprites]; // All the sprites shown on screen + Cycle _cycles[kMaxCycles]; Common::Array _strPtrs; // Str should really be a char array, but inserting frame values will be stupid so it's just a string instead Common::Array _motivePtrs; Common::Array _damagePtrs; @@ -402,7 +387,6 @@ class ImmortalEngine : public Engine { uint16 _myUnivPointY; int _num2DrawItems = 0; Graphics::Surface *_mainSurface; - Cyc _cycles[32]; GenericSprite _genSprites[6]; // Palette members @@ -482,7 +466,7 @@ GenericSprite _genSprites[6]; void loadFont(); // Gets the font.spr file, and centers the sprite void clearSprites(); // Clears all sprites before drawing the current frame void loadSprites(); // Loads all the sprite files and centers their sprites (in spritelist, but called from kernal) - void addSprite(uint16 x, uint16 y, SpriteName n, int frame, uint16 p); + void addSprite(uint16 x, uint16 y, SpriteName n, int img, uint16 p); // Input void userIO(); // Get input @@ -603,15 +587,16 @@ GenericSprite _genSprites[6]; */ // Misc - void cycleNew(); // Adds a cycle to the current list - int getCycleChr(); + CycID cycleNew(CycID id); // Adds a cycle to the current list void cycleFreeAll(); // Delete all cycles - void cycleGetFile(); - void cycleGetNum(); - void cycleGetIndex(); - void cycleSetIndex(); - void cycleGetFrame(); - void cycleAdvance(); + void cycleFree(CycID id); +DataSprite *cycleGetDataSprite(CycID id); // This takes the place of getFile + getNum + int cycleGetIndex(CycID id); + void cycleSetIndex(CycID id, int f); + int cycleGetFrame(CycID id); + int cycleGetNumFrames(CycID id); + bool cycleAdvance(CycID id); + Cycle *getCycList(CycID id); /* Unneccessary cycle functions void cycleInit(); @@ -635,7 +620,7 @@ GenericSprite _genSprites[6]; void initDataSprite(Common::SeekableReadStream *f, DataSprite *d, int index, uint16 cenX, uint16 cenY); // Initializes the data sprite // Main - void superSprite(int s, uint16 x, uint16 y, Frame f, int bmw, byte *dst, int sT, int sB); + void superSprite(int s, uint16 x, uint16 y, Image img, int bmw, byte *dst, int sT, int sB); /* diff --git a/engines/immortal/sprite_list.h b/engines/immortal/sprite_list.h index a08293312500..345f31d5e3d9 100644 --- a/engines/immortal/sprite_list.h +++ b/engines/immortal/sprite_list.h @@ -24,6 +24,29 @@ namespace Immortal { +struct Image { + uint16 _deltaX; + uint16 _deltaY; + uint16 _rectX; + uint16 _rectY; + byte *_bitmap; +}; + +struct DataSprite { + uint16 _cenX; // These are the base center positions + uint16 _cenY; + uint16 _numImages; +Common::Array _images; +}; + +// Cycles define the animation of sprites within a level. There is a fixed total of cycles available, and they are not room dependant +struct Cycle { +DataSprite *_dSprite; + bool _repeat; + int _index; // In source this is actually the position within the *instruction list*, but since cycle's are structs, it's just the index of frames now + int *_frames; +}; + enum SpriteFrame { // Null kNoFrame, diff --git a/engines/immortal/sprites.cpp b/engines/immortal/sprites.cpp index ae93b2f4258e..83bec3c409ef 100644 --- a/engines/immortal/sprites.cpp +++ b/engines/immortal/sprites.cpp @@ -43,37 +43,37 @@ void ImmortalEngine::initDataSprite(Common::SeekableReadStream *f, DataSprite *d f->seek(index); index = f->readUint16LE(); - uint16 numFrames = f->readUint16LE(); + uint16 numImages = f->readUint16LE(); - d->_numFrames = numFrames; - debug("Number of Frames: %d", numFrames); + d->_numImages = numImages; + //debug("Number of Frames: %d", numFrames); // Only here for dragon, but just in case, it's a high number so it should catch others - if (numFrames >= 0x0200) { - debug("** Crazy large value, this isn't a frame number **"); + if (numImages >= 0x0200) { + //debug("** Crazy large value, this isn't a frame number **"); return; } - Common::Array frames; + Common::Array images; - for (int i = 0; i < numFrames; i++) { - Frame newFrame; + for (int i = 0; i < numImages; i++) { + Image newImage; f->seek(index + (i*2)); int ptrFrame = f->readUint16LE(); f->seek(ptrFrame); - newFrame._deltaX = f->readUint16LE() << 1; // the ASL might not be required, depending on how I translate the sprite drawing - newFrame._deltaY = f->readUint16LE(); - newFrame._rectX = f->readUint16LE(); - newFrame._rectY = f->readUint16LE(); - frames.push_back(newFrame); + newImage._deltaX = f->readUint16LE() << 1; // the ASL might not be required, depending on how I translate the sprite drawing + newImage._deltaY = f->readUint16LE(); + newImage._rectX = f->readUint16LE(); + newImage._rectY = f->readUint16LE(); + images.push_back(newImage); // This is probably where we will get the bitmap when I know how to get it } - d->_frames = frames; + d->_images = images; } -void ImmortalEngine::superSprite(int s, uint16 x, uint16 y, Frame f, int bmw, byte *dst, int sT, int sB) {} +void ImmortalEngine::superSprite(int s, uint16 x, uint16 y, Image img, int bmw, byte *dst, int sT, int sB) {} } // namespace Immortal diff --git a/engines/immortal/story.h b/engines/immortal/story.h index bcb20a001c5d..aa86734c7e98 100644 --- a/engines/immortal/story.h +++ b/engines/immortal/story.h @@ -30,10 +30,6 @@ namespace Immortal { -struct Frame; -struct DataSprite; -struct Sprite; - // We need a few two-dimentional vectors, and writing them out in full each time is tedious template using CArray2D = Common::Array>; @@ -99,13 +95,6 @@ enum FPattern : uint8 { // This defines which Cyc animation it uses kFlameGusty }; -// Cycles define the animation of sprites within a level. There is a fixed total of cycles available, and they are not room dependant -struct Cycle { -DataSprite *_dSprite; - int _numCycles; - int *_frames; -}; - // Object Pickup defines how an object can be picked up by the player, with different functions enum SObjPickup { }; From 435727b52112d72a7626af4280c9377307ce7df1 Mon Sep 17 00:00:00 2001 From: Quote58 Date: Fri, 19 Aug 2022 03:53:25 -0400 Subject: [PATCH 330/412] IMMORTAL: Util::X -> Immortal::Util::X --- engines/immortal/util.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/engines/immortal/util.cpp b/engines/immortal/util.cpp index 0b6bc866edee..0bc671a6fbd2 100644 --- a/engines/immortal/util.cpp +++ b/engines/immortal/util.cpp @@ -25,23 +25,23 @@ namespace Immortal { namespace Util { -void Util::delay(int j) { // Delay is measured in jiffies, which are 56.17ms - g_system->delayMillis(j * 56); +void Immortal::Util::delay(int j) { // Delay is measured in jiffies, which are 56.17ms + g_system->delayMillis(j * 56); } -void Util::delay4(int j) { // Named in source quarterClock for some reason, 1/4 jiffies are 14.04ms - g_system->delayMillis(j * 14); +void Immortal::Util::delay4(int j) { // Named in source quarterClock for some reason, 1/4 jiffies are 14.04ms + g_system->delayMillis(j * 14); } -void Util::delay8(int j) { // 1/8 jiffies are 7.02ms - g_system->delayMillis(j * 7); +void Immortal::Util::delay8(int j) { // 1/8 jiffies are 7.02ms + g_system->delayMillis(j * 7); } -bool Util::inside(int x1, int y1, int a, int x2, int y2) { - return false; +bool Immortal::Util::inside(int x1, int y1, int a, int x2, int y2) { + return false; } -bool Util::insideRect(int x, int y, int r) { - return false; +bool Immortal::Util::insideRect(int x, int y, int r) { + return false; } }; // namespace Util From 8b5b74fc848834040ccba9bf53b3f8fb32fee60a Mon Sep 17 00:00:00 2001 From: Quote58 Date: Fri, 19 Aug 2022 03:56:10 -0400 Subject: [PATCH 331/412] IMMORTAL: Move CycID to definitions.h --- engines/immortal/definitions.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/engines/immortal/definitions.h b/engines/immortal/definitions.h index 1991d790c36a..db0a40c8112c 100644 --- a/engines/immortal/definitions.h +++ b/engines/immortal/definitions.h @@ -24,8 +24,8 @@ namespace Immortal { -enum Cyc { - kCycNone +enum CycID { + kCycNone = 0 }; enum Motive { // This will likely be moved to a monster ai specific file later From 55be069f923191e9030d4e4d88d52bd8a240f698 Mon Sep 17 00:00:00 2001 From: Quote58 Date: Fri, 19 Aug 2022 03:57:35 -0400 Subject: [PATCH 332/412] IMMORTAL: Implement Cycles from Cyc.GS --- engines/immortal/cycle.cpp | 112 ++++++++++++++++++++++++++++++++---- engines/immortal/kernal.cpp | 18 +++--- engines/immortal/logic.cpp | 19 +++--- engines/immortal/room.h | 11 ++-- 4 files changed, 124 insertions(+), 36 deletions(-) diff --git a/engines/immortal/cycle.cpp b/engines/immortal/cycle.cpp index eeac61882085..bd11ee480c08 100644 --- a/engines/immortal/cycle.cpp +++ b/engines/immortal/cycle.cpp @@ -21,22 +21,114 @@ /* [Alternate Name: Sprite Animation Processing] * --- What is a Cycle --- + * Strictly speaking, a Cycle is an instruction list, but it gets a little confusing. + * A 'Cyc' is defined through Story as a static ROM entry of the format: + * file, num, numcycles, cycles[] + * However file + num = datasprite, and numcycles is actually a boolean for repeat animation. + * So really it's data, repeat, cycles[] + * This ROM entry is pointed to by a list of pointers, indexed by a byte pointer, which is + * referenced lexigraphically through the dynamic story compilation system. This pointer is then + * turned into a 'cycList' pointer, and stored in the RAM Cyc, which is of the format: + * index, cycList + * Where index is the index into the *instruction list*, not the frame array. However it's + * Usually used as an index into the frame array by subtracting the frame enum first. + * Here's the movement of data from ROM to RAM: + * list of Cycles on heap (cyc) + * | + * list of word pointers in wram to Cycles (cycPtrs) + * | + * list of lexical pointers as byte indexes into word pointers (cycID -> cyclist) */ #include "immortal/immortal.h" namespace Immortal { -void ImmortalEngine::cycleNew() {} - int ImmortalEngine::getCycleChr() { - return 0; +CycID ImmortalEngine::cycleNew(CycID id) { + // An 'available' cyc is identified by the index being -1 + for (int i = 0; i < kMaxCycles; i++) { + if (_cycles[i]._index == -1) { + _cycles[i]._index = 0; + return (CycID) i; + } + } + debug("Null Cyc, can not be created"); + return (CycID) (kMaxCycles - 1); +} + +void ImmortalEngine::cycleFree(CycID id) { + _cycles[id]._index = -1; +} + +void ImmortalEngine::cycleFreeAll() { + for (int i = 0; i < kMaxCycles; i++) { + _cycles[i]._index = -1; + } +} + +bool ImmortalEngine::cycleAdvance(CycID id) { + /* If we have reached the end, check if repeat == true, and set back to 0 if so + * Otherwise, set to the last used index */ + _cycles[id]._index++; + if (_cycles[id]._frames[_cycles[id]._index] == -1) { + if (_cycles[id]._repeat == true) { + _cycles[id]._index = 0; + } else { + _cycles[id]._index--; + return true; + } + } + return false; +} + +int ImmortalEngine::cycleGetFrame(CycID id) { + // This originally did some shenanigans in Kernal to get the number, but really it's just this + return _cycles[id]._frames[_cycles[id]._index]; } -void ImmortalEngine::cycleFreeAll() {} -void ImmortalEngine::cycleGetFile() {} -void ImmortalEngine::cycleGetNum() {} -void ImmortalEngine::cycleGetIndex() {} -void ImmortalEngine::cycleSetIndex() {} -void ImmortalEngine::cycleGetFrame() {} -void ImmortalEngine::cycleAdvance() {} + +int ImmortalEngine::cycleGetNumFrames(CycID id) { + // Why in the world is this not kept as a property of the cycle? We have to calculate the size of the array each time + int index = 0; + while (_cycles[id]._frames[index] != -1) { + index++; + } + return index; +} + +DataSprite *ImmortalEngine::cycleGetDataSprite(CycID id) { + return _cycles[id]._dSprite; +} + +Cycle *ImmortalEngine::getCycList(CycID id) { + return &_cycles[id]; +} + +int ImmortalEngine::cycleGetIndex(CycID id) { + return _cycles[id]._index; +} + +void ImmortalEngine::cycleSetIndex(CycID id, int f) { + _cycles[id]._index = f; +} + } // namespace Immortal + + + + + + + + + + + + + + + + + + + diff --git a/engines/immortal/kernal.cpp b/engines/immortal/kernal.cpp index 778248aa4b99..fa8e0ea56974 100644 --- a/engines/immortal/kernal.cpp +++ b/engines/immortal/kernal.cpp @@ -136,15 +136,15 @@ void ImmortalEngine::addSprites() { } DataSprite *tempD = _sprites[i]._dSprite; - Frame *tempF = &(_sprites[i]._dSprite->_frames[_sprites[i]._frame]); - int sx = ((_sprites[i]._X + tempF->_deltaX) - tempD->_cenX) - _myViewPortX; - int sy = ((_sprites[i]._Y + tempF->_deltaY) - tempD->_cenY) - _myViewPortY; + Image *tempImg = &(_sprites[i]._dSprite->_images[_sprites[i]._image]); + int sx = ((_sprites[i]._X + tempImg->_deltaX) - tempD->_cenX) - _myViewPortX; + int sy = ((_sprites[i]._Y + tempImg->_deltaY) - tempD->_cenY) - _myViewPortY; if (sx >= 0 ) { if (sx >= kViewPortW) { continue; } - } else if ((sx + tempF->_rectX) <= 0) { + } else if ((sx + tempImg->_rectX) <= 0) { continue; } @@ -152,7 +152,7 @@ void ImmortalEngine::addSprites() { if (sy >= kViewPortH) { continue; } - } else if ((sy + tempF->_rectY) <= 0) { + } else if ((sy + tempImg->_rectY) <= 0) { continue; } @@ -285,7 +285,7 @@ void ImmortalEngine::drawItems() { // If positive, it's a sprite uint16 x = (_sprites[index]._X - _myViewPortX) + kVSX; uint16 y = (_sprites[index]._Y - _myViewPortY) + kVSY; - superSprite(index, x, y, _sprites[index]._dSprite->_frames[_sprites[index]._frame], kVSBMW, _screenBuff, kMySuperTop, kMySuperBottom); + superSprite(index, x, y, _sprites[index]._dSprite->_images[_sprites[index]._image], kVSBMW, _screenBuff, kMySuperTop, kMySuperBottom); } n++; } while (n != _num2DrawItems); @@ -348,7 +348,7 @@ void ImmortalEngine::printChr(char c) { return; } - superSprite(0, x, y, _dataSprites[kFont]._frames[(int) c], kScreenBMW, _screenBuff, kSuperTop, kSuperBottom); + superSprite(0, x, y, _dataSprites[kFont]._images[(int) c], kScreenBMW, _screenBuff, kSuperTop, kSuperBottom); if ((c == 0x27) || (c == 'T')) { _penX -= 2; // Why is this done twice?? } @@ -483,7 +483,7 @@ void ImmortalEngine::initStoryStatic() { } -void ImmortalEngine::addSprite(uint16 x, uint16 y, SpriteName n, int frame, uint16 p) { +void ImmortalEngine::addSprite(uint16 x, uint16 y, SpriteName n, int img, uint16 p) { if (_numSprites != kMaxSprites) { if (x >= (kResH + kMaxSpriteLeft)) { x |= kMaskHigh; // Make it negative @@ -500,7 +500,7 @@ void ImmortalEngine::addSprite(uint16 x, uint16 y, SpriteName n, int frame, uint } _sprites[_numSprites]._priority = ((p + y) ^ 0xFFFF) + 1; - _sprites[_numSprites]._frame = frame; + _sprites[_numSprites]._image = img; _sprites[_numSprites]._dSprite = &_dataSprites[n]; _sprites[_numSprites]._on = 1; _numSprites += 1; diff --git a/engines/immortal/logic.cpp b/engines/immortal/logic.cpp index 6e04edbbb91d..2379914705e9 100644 --- a/engines/immortal/logic.cpp +++ b/engines/immortal/logic.cpp @@ -19,6 +19,7 @@ * */ +#include "immortal/room.h" #include "immortal/immortal.h" namespace Immortal { @@ -45,9 +46,7 @@ void ImmortalEngine::restartLogic() { // Here's where the majority of the game actually gets initialized miscInit(); - //qarrayInit(); - //cycInit(); <-- room.initCycles() - //fsetInit(); <-- room.initTorches() + cycleFreeAll(); levelInit(); //roomInit(); <-- will be run in constructor of room //monstInit(); <-- room.initMonsters() \ @@ -58,15 +57,13 @@ void ImmortalEngine::restartLogic() { //objectInit(); <-- again? Odd... //genericSpriteInit(); <-- room.initGenSprites() - // Probably will be written as: - // qarrayInit(); <-- will probably just be like, _qarray = new Common::Array(); - // levelInit(); - if (fromOldGame() == false) { _level = 0; levelNew(_level); } + _rooms[_currentRoom]->flameInit(); + if (_level != 7) { _themePaused = true; // and #-1-2 = set both flags for themePaused } @@ -121,18 +118,16 @@ void ImmortalEngine::logic() { levelDrawAll(); updateHitGauge(); - // What the heck? Check if we are in level 0: room 0, with no lit torches, and no projectiles - // If so, dim the screen _dim = 0; - if ((_level == 0) && (/*_currentLevel.getShowRoom()*/0 == 0) && (/*roomLighted()*/false == false) && (/*getNumBullets()*/ 0 == 0)) { - //_dim += 1; + if ((_level == 0) && (/*_currentLevel.getShowRoom()*/0 == 0) && (_rooms[_currentRoom]->roomLighted() == false) && (/*getNumBullets()*/ 0 == 0)) { + _dim += 1; } if (_level == 7) { doGroan(); } - if (/*monstIsCombat(kPlayerID)*/true == true) { + if (/*monstIsCombat(kPlayerID)*/false == true) { if (getPlaying() != kSongCombat) { playCombatSong(); } diff --git a/engines/immortal/room.h b/engines/immortal/room.h index 7b7fb8463823..58f893182b88 100644 --- a/engines/immortal/room.h +++ b/engines/immortal/room.h @@ -93,7 +93,7 @@ struct Flame { FPattern _p; uint8 _x; uint8 _y; - Cyc _c; + CycID _c; }; struct Chest { @@ -128,7 +128,8 @@ Common::Array _objects; uint8 _holeCellX; uint8 _holeCellY; uint8 _candleTmp; // Special case for candle in maze 0 - + uint8 _numFlames; + uint8 _numInRoom; /* * --- Methods --- @@ -162,13 +163,13 @@ Common::Array _objects; * [flameSet.cpp] Functions from flameSet.GS */ + void flameInit(); void flameSetRoom(Common::Array); void flameDrawAll(); bool roomLighted(); void lightTorch(int x, int y); - Cyc flameGetCyc(int first); - //void flameFreeAll(); - //void flameSetRoom(); + CycID flameGetCyc(int first); + void flameFreeAll(); /* * [bullet.cpp] Functions from Bullet.GS From 6ba6e0fa2cddab1c0d7b558aae74db4946b2eaa9 Mon Sep 17 00:00:00 2001 From: Quote58 Date: Sat, 20 Aug 2022 01:33:34 -0400 Subject: [PATCH 333/412] IMMORTAL: Translation of Cycle is more accurate with addition of cycPtrs --- engines/immortal/cycle.cpp | 47 +++++++++++++++++----------------- engines/immortal/immortal.h | 29 +++++++++++---------- engines/immortal/sprite_list.h | 6 ++--- engines/immortal/story.h | 12 +++++++++ 4 files changed, 53 insertions(+), 41 deletions(-) diff --git a/engines/immortal/cycle.cpp b/engines/immortal/cycle.cpp index bd11ee480c08..4a43b28be709 100644 --- a/engines/immortal/cycle.cpp +++ b/engines/immortal/cycle.cpp @@ -44,20 +44,21 @@ namespace Immortal { -CycID ImmortalEngine::cycleNew(CycID id) { +int ImmortalEngine::cycleNew(CycID id) { // An 'available' cyc is identified by the index being -1 for (int i = 0; i < kMaxCycles; i++) { if (_cycles[i]._index == -1) { _cycles[i]._index = 0; - return (CycID) i; + _cycles[i]._cycList = id; + return i; } } debug("Null Cyc, can not be created"); - return (CycID) (kMaxCycles - 1); + return kMaxCycles - 1; } -void ImmortalEngine::cycleFree(CycID id) { - _cycles[id]._index = -1; +void ImmortalEngine::cycleFree(int c) { + _cycles[c]._index = -1; } void ImmortalEngine::cycleFreeAll() { @@ -66,49 +67,49 @@ void ImmortalEngine::cycleFreeAll() { } } -bool ImmortalEngine::cycleAdvance(CycID id) { +bool ImmortalEngine::cycleAdvance(int c) { /* If we have reached the end, check if repeat == true, and set back to 0 if so * Otherwise, set to the last used index */ - _cycles[id]._index++; - if (_cycles[id]._frames[_cycles[id]._index] == -1) { - if (_cycles[id]._repeat == true) { - _cycles[id]._index = 0; + _cycles[c]._index++; + if (_cycPtrs[_cycles[c]._index]._frames[_cycles[c]._index] == -1) { + if (_cycPtrs[_cycles[c]._index]._repeat == true) { + _cycles[c]._index = 0; } else { - _cycles[id]._index--; + _cycles[c]._index--; return true; } } return false; } -int ImmortalEngine::cycleGetFrame(CycID id) { +int ImmortalEngine::cycleGetFrame(int c) { // This originally did some shenanigans in Kernal to get the number, but really it's just this - return _cycles[id]._frames[_cycles[id]._index]; + return _cycPtrs[_cycles[c]._cycList]._frames[_cycles[c]._index]; } -int ImmortalEngine::cycleGetNumFrames(CycID id) { +int ImmortalEngine::cycleGetNumFrames(int c) { // Why in the world is this not kept as a property of the cycle? We have to calculate the size of the array each time int index = 0; - while (_cycles[id]._frames[index] != -1) { + while (_cycPtrs[_cycles[c]._cycList]._frames[index] != -1) { index++; } return index; } -DataSprite *ImmortalEngine::cycleGetDataSprite(CycID id) { - return _cycles[id]._dSprite; +DataSprite *ImmortalEngine::cycleGetDataSprite(int c) { + return _cycPtrs[_cycles[c]._cycList]._dSprite; } -Cycle *ImmortalEngine::getCycList(CycID id) { - return &_cycles[id]; +CycID ImmortalEngine::getCycList(int c) { + return _cycles[c]._cycList; } -int ImmortalEngine::cycleGetIndex(CycID id) { - return _cycles[id]._index; +int ImmortalEngine::cycleGetIndex(int c) { + return _cycles[c]._index; } -void ImmortalEngine::cycleSetIndex(CycID id, int f) { - _cycles[id]._index = f; +void ImmortalEngine::cycleSetIndex(int c, int f) { + _cycles[c]._index = f; } diff --git a/engines/immortal/immortal.h b/engines/immortal/immortal.h index a063b7a67b74..994325e13543 100644 --- a/engines/immortal/immortal.h +++ b/engines/immortal/immortal.h @@ -353,15 +353,16 @@ class ImmortalEngine : public Engine { int _combatID = 0; // Asset members - int _numSprites = 0; // This is more accurately actually the index within the sprite array, so _numSprites + 1 is the current number of sprites - DataSprite _dataSprites[kFont + 1]; // All the sprite data, indexed by SpriteFile - Sprite _sprites[kMaxSprites]; // All the sprites shown on screen - Cycle _cycles[kMaxCycles]; + int _numSprites = 0; // This is more accurately actually the index within the sprite array, so _numSprites + 1 is the current number of sprites + DataSprite _dataSprites[kFont + 1]; // All the sprite data, indexed by SpriteFile + Sprite _sprites[kMaxSprites]; // All the sprites shown on screen + Cycle _cycles[kMaxCycles]; Common::Array _strPtrs; // Str should really be a char array, but inserting frame values will be stupid so it's just a string instead Common::Array _motivePtrs; Common::Array _damagePtrs; Common::Array _usePtrs; Common::Array _pickupPtrs; + Common::Array _cycPtrs; CArray2D _programPtrs; Common::Array _objTypePtrs; @@ -587,16 +588,16 @@ GenericSprite _genSprites[6]; */ // Misc - CycID cycleNew(CycID id); // Adds a cycle to the current list - void cycleFreeAll(); // Delete all cycles - void cycleFree(CycID id); -DataSprite *cycleGetDataSprite(CycID id); // This takes the place of getFile + getNum - int cycleGetIndex(CycID id); - void cycleSetIndex(CycID id, int f); - int cycleGetFrame(CycID id); - int cycleGetNumFrames(CycID id); - bool cycleAdvance(CycID id); - Cycle *getCycList(CycID id); + int cycleNew(CycID id); // Adds a cycle to the current list + void cycleFreeAll(); // Delete all cycles + void cycleFree(int c); +DataSprite *cycleGetDataSprite(int c); // This takes the place of getFile + getNum + int cycleGetIndex(int c); + void cycleSetIndex(int c, int f); + int cycleGetFrame(int c); + int cycleGetNumFrames(int c); + bool cycleAdvance(int c); + CycID getCycList(int c); /* Unneccessary cycle functions void cycleInit(); diff --git a/engines/immortal/sprite_list.h b/engines/immortal/sprite_list.h index 345f31d5e3d9..7633becd4b7d 100644 --- a/engines/immortal/sprite_list.h +++ b/engines/immortal/sprite_list.h @@ -41,10 +41,8 @@ Common::Array _images; // Cycles define the animation of sprites within a level. There is a fixed total of cycles available, and they are not room dependant struct Cycle { -DataSprite *_dSprite; - bool _repeat; - int _index; // In source this is actually the position within the *instruction list*, but since cycle's are structs, it's just the index of frames now - int *_frames; + int _index; // In source this is actually the position within the *instruction list*, but since cycle's are structs, it's just the index of frames now + CycID _cycList; }; enum SpriteFrame { diff --git a/engines/immortal/story.h b/engines/immortal/story.h index aa86734c7e98..759bcb9e8a6b 100644 --- a/engines/immortal/story.h +++ b/engines/immortal/story.h @@ -134,6 +134,18 @@ struct ObjType { * bits 0-2 of X to also hold the roomOP, and bits 0-2 of Y to hold flags). However * for the moment there's no need to replicate this particular bit of space saving. */ +struct SCycle { +DataSprite *_dSprite; + bool _repeat; + int *_frames; + SCycle() {} + SCycle(DataSprite *d, bool r, int *f) { + _dSprite = d; + _repeat = r; + _frames = f; + } +}; + struct SRoom { uint8 _x = 0; uint8 _y = 0; From c0c1d2e781dc6332d1f628fcdf82e69148a0fc1e Mon Sep 17 00:00:00 2001 From: Quote58 Date: Sun, 21 Aug 2022 20:00:19 -0400 Subject: [PATCH 334/412] IMMORTAL: All engine members initialized to values now --- engines/immortal/immortal.h | 105 ++++++++++++++---------------------- 1 file changed, 39 insertions(+), 66 deletions(-) diff --git a/engines/immortal/immortal.h b/engines/immortal/immortal.h index 994325e13543..4f71404eee5e 100644 --- a/engines/immortal/immortal.h +++ b/engines/immortal/immortal.h @@ -66,14 +66,6 @@ namespace Immortal { -// Needed by kernal for drawing -enum Screen { // These are constants that are used for defining screen related arrays - kMaxSprites = 32, // Number of sprites allowed at once - kViewPortCW = 256 / 64, - kViewPortCH = 128 / kMaxSprites, - kMaxDrawItems = kViewPortCH + 1 + kMaxSprites -}; - // Needed by kernal for input enum InputAction { kActionNothing, @@ -150,16 +142,6 @@ struct Door { uint8 _on = 0; }; -// Sprites are handled by driver in Kernal -struct Sprite { - int _image; // Index of _dSprite._frames[] - uint16 _X; - uint16 _Y; - uint16 _on; // 1 = active - uint16 _priority; -DataSprite *_dSprite; -}; - struct ImmortalGameDescription; // Forward declaration because we will need the Disk and Room classes @@ -203,8 +185,6 @@ class ImmortalEngine : public Engine { const int kMaxCertificate = 16; // Screen constants - const int kResH = 320; - const int kResV = 200; const int kScreenW__ = 128; // ??? labeled in source as SCREENWIDTH const int kScreenH__ = 128; // ??? const int kViewPortW = 256; @@ -247,10 +227,6 @@ class ImmortalEngine : public Engine { const int kPaletteOffset = 21205; // This is the byte position of the palette data in the disk // Sprite constants - const int kMaxSpriteAbove = 48; // Maximum sprite extents from center - const int kMaxSpriteBelow = 16; - const int kMaxSpriteLeft = 16; - const int kMaxSpriteRight = 16; const int kMaxSpriteW = 64; const int kMaxSpriteH = 64; const int kSpriteDY = 32; @@ -291,8 +267,8 @@ class ImmortalEngine : public Engine { bool _draw = 0; // Whether the screen should draw this frame int _zero = 0; // No idea what this is yet bool _gameOverFlag = false; - uint8 _gameFlags; // Bitflag array of event flags, but only two were used (saving ana and saving the king) <-- why is gameOverFlag not in this? Lol - bool _themePaused; // In the source, this is actually considered a bit flag array of 2 bits (b0 and b1). However, it only ever checks for non-zero, so it's effectively only 1 bit. + uint8 _gameFlags = 0; // Bitflag array of event flags, but only two were used (saving ana and saving the king) <-- why is gameOverFlag not in this? Lol + bool _themePaused = false; // In the source, this is actually considered a bit flag array of 2 bits (b0 and b1). However, it only ever checks for non-zero, so it's effectively only 1 bit. int _titlesShown = 0; int _time = 0; int _promoting = 0; // I think promoting means the title stuff @@ -302,26 +278,26 @@ class ImmortalEngine : public Engine { Story _stories[8]; // Level members - int _maxLevels = 0; // This is determined when loading in story files - int _level = 0; - bool _levelOver = false; - int _count; - int _lastLevelLoaded; - int _lastSongLoaded; - int _storyLevel; - int _storyX; - int _loadA; - int _loadY; - uint16 _initialX; - uint16 _initialY; - int _initialBX; - int _initialBY; - int _dRoomNum; - int _initialRoom = 0; - int _currentRoom = 0; - int _lastType; - int _roomCellX; - int _roomCellY; + int _maxLevels = 0; // This is determined when loading in story files + int _level = 0; + bool _levelOver = false; + int _count = 0; + int _lastLevelLoaded = 0; + int _lastSongLoaded = 0; + int _storyLevel = 0; + int _storyX = 0; + int _loadA = 0; + int _loadY = 0; + uint16 _initialX = 0; + uint16 _initialY = 0; + int _initialBX = 0; + int _initialBY = 0; + int _dRoomNum = 0; + int _initialRoom = 0; + int _currentRoom = 0; + int _lastType = 0; + int _roomCellX = 0; + int _roomCellY = 0; Room *_rooms[kMaxRooms]; // Rooms within the level Common::Array _allFlames[kMaxRooms]; // The level needs it's own set of flames so that the flames can be turned on/off permenantly. This is technically more like a hashmap in the source, but it could also be seen as a 2d array, just hashed together in the source @@ -342,19 +318,19 @@ class ImmortalEngine : public Engine { bool _singleStep; // Flag for _singleStep mode // Input members - int _pressedAction; - int _heldAction; - int _pressedDirection; - int _heldDirection; + int _pressedAction = 0; + int _heldAction = 0; + int _pressedDirection = 0; + int _heldDirection = 0; // Music members Song _playing; // Currently playing song - int _themeID = 0; // Not sure yet tbh - int _combatID = 0; + int _themeID = 0; // Not sure yet tbh + int _combatID = 0; // Asset members int _numSprites = 0; // This is more accurately actually the index within the sprite array, so _numSprites + 1 is the current number of sprites - DataSprite _dataSprites[kFont + 1]; // All the sprite data, indexed by SpriteFile + DataSprite _dataSprites[kFont + 1]; // All the sprite data, indexed by SpriteName Sprite _sprites[kMaxSprites]; // All the sprites shown on screen Cycle _cycles[kMaxCycles]; Common::Array _strPtrs; // Str should really be a char array, but inserting frame values will be stupid so it's just a string instead @@ -362,7 +338,7 @@ class ImmortalEngine : public Engine { Common::Array _damagePtrs; Common::Array _usePtrs; Common::Array _pickupPtrs; - Common::Array _cycPtrs; + Common::Array _cycPtrs; // This is not actually a set of pointers, but it is serving the function of what was called cycPtrs in the source CArray2D _programPtrs; Common::Array _objTypePtrs; @@ -377,15 +353,15 @@ class ImmortalEngine : public Engine { uint16 _columnIndex[kViewPortCW + 1]; // Why the heck is this an entire array, when it's just an index that gets zeroed before it gets used anyway... uint16 _tIndex[kMaxDrawItems]; uint16 _tPriority[kMaxDrawItems]; - uint16 _viewPortX; - uint16 _viewPortY; - uint16 _myViewPortX; // Probably mirror of viewportX - uint16 _myViewPortY; + uint16 _viewPortX = 0; + uint16 _viewPortY = 0; + uint16 _myViewPortX = 0; // Probably mirror of viewportX + uint16 _myViewPortY = 0; int _lastGauge = 0; // Mirror for player health, used to update health gauge display uint16 _penX = 0; // Basically where in the screen we are currently drawing uint16 _penY = 0; - uint16 _myUnivPointX; - uint16 _myUnivPointY; + uint16 _myUnivPointX = 0; + uint16 _myUnivPointY = 0; int _num2DrawItems = 0; Graphics::Surface *_mainSurface; GenericSprite _genSprites[6]; @@ -406,6 +382,8 @@ GenericSprite _genSprites[6]; * */ + void setSprites(Sprite *s); + /* * [Kernal.cpp] Functions from Kernal.gs and Driver.gs */ @@ -467,7 +445,7 @@ GenericSprite _genSprites[6]; void loadFont(); // Gets the font.spr file, and centers the sprite void clearSprites(); // Clears all sprites before drawing the current frame void loadSprites(); // Loads all the sprite files and centers their sprites (in spritelist, but called from kernal) - void addSprite(uint16 x, uint16 y, SpriteName n, int img, uint16 p); + void kernalAddSprite(uint16 x, uint16 y, SpriteName n, int img, uint16 p); // Input void userIO(); // Get input @@ -670,11 +648,6 @@ DataSprite *cycleGetDataSprite(int c); // This takes the place of getFile + g // Misc - /* - * [Univ.cpp] Functions from Univ.GS - */ - - /* * --- ScummVM general engine Functions --- * From 1336c89bdffb36b092a3010c66623b504ff0cec3 Mon Sep 17 00:00:00 2001 From: Quote58 Date: Tue, 23 Aug 2022 16:58:06 -0400 Subject: [PATCH 335/412] IMMORTAL: Add non-level static Cycle defintions + enum --- engines/immortal/definitions.h | 43 ++++++++++++++- engines/immortal/kernal.cpp | 95 +++++++++++++++++++++++----------- 2 files changed, 107 insertions(+), 31 deletions(-) diff --git a/engines/immortal/definitions.h b/engines/immortal/definitions.h index db0a40c8112c..8de52483cc6c 100644 --- a/engines/immortal/definitions.h +++ b/engines/immortal/definitions.h @@ -25,7 +25,48 @@ namespace Immortal { enum CycID { - kCycNone = 0 + kCycNone, + kCycBubble1 = 0, + kCycBubble2, + kCycSparkLBlood, + kCycSparkRBlood, + kCycSparkLWizBlood, + kCycSparkRWizBlood, + kCycBurst, + kCycPipe0, + kCycPipe1, + kCycPipe2, + kCycPipe3, + kCycAnaDisappears, + kCycAnaGlimpse, + kCycKnife, + kCycFireball0, + kCycArrow, + kCycMiniBall, + kCycBigBurst, + kCycFFlicker0, + kCycFFlicker1, + kCycFFlicker2, + kCycFNormal0, + kCycFNormal1, + kCycFNormal2, + kCycFOff, + kCycFCandleFlicker, + kCycFCandleLeap, + kCycFCandleJump, + kCycFCandleSway, + kCycFCandleBurst, + kCycSink, + kCycNorDown + + // Level 0 + // Level 1 + // Level 2 + // Level 3 + // Level 4 + // Level 5 + // Level 6 + // Level 7 }; enum Motive { // This will likely be moved to a monster ai specific file later diff --git a/engines/immortal/kernal.cpp b/engines/immortal/kernal.cpp index fa8e0ea56974..044fde879b06 100644 --- a/engines/immortal/kernal.cpp +++ b/engines/immortal/kernal.cpp @@ -463,6 +463,58 @@ void ImmortalEngine::initStoryStatic() { "This room resembles part&of the map.@"}; _strPtrs = s; + // Scope, amirite? + Common::Array cyc0{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,-1}; + Common::Array cyc1{15,16,17,18,19,20,21,22,-1}; + Common::Array cyc2{0,1,2,-1}; + Common::Array cyc3{3,4,5,-1}; + Common::Array cyc4{6,7,8,9,10,-1}; + Common::Array cyc5{11,12,13,14,15,-1}; + Common::Array cyc6{16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,-1}; + Common::Array cyc7{0,1,2,3,4,-1}; + Common::Array cyc8{5,1+5,2+5,3+5,4+5,-1}; + Common::Array cyc9{10,1+10,2+10,3+10,4+10,-1}; + Common::Array cyc10{15,1+15,2+15,3+15,4+15,-1}; + Common::Array cyc11{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,-1}; + Common::Array cyc12{0,1,2,3,4,5,6,7,8,9,-1}; + Common::Array cyc13{0,1,2,3, 0,1,2,3, 0,1,2,3, 0,1,2,3, 0,1,2,3, 0,1,2,3, 0,1,2,3, 0,1,2,3, -1}; + Common::Array cyc14{31,32,33,32, 34,35,36,35, 37,38,39,38, 40,41,42,41, 43,44,45,44, 46,47,48,47, 49,50,51,50, 52,53,54,53, -1}; + Common::Array cyc15{55, -1}; + Common::Array cyc16{63,64,65,66, 63,64,65,66, 63,64,65,66, 63,64,65,66, 63,64,65,66, 63,64,65,66, 63,64,65,66, 63,64,65,66,-1}; + Common::Array cyc17{0,1,0,-1}; + Common::Array cyc18{0,1,2,4,5,6,7,8,9,10,11,12,2,1,-1}; + Common::Array cyc19{0,0,1,2,13,14,15,16,4,2,3,-1}; + Common::Array cyc20{0,1,2,3,20,21,22,23,24,25,26,27,5,4,3,-1}; + Common::Array cyc21{0,1,2,3,-1}; + Common::Array cyc22{0,17,18,19,3,-1}; + Common::Array cyc23{0,1,-1}; + Common::Array cyc24{28,28,28,28,-1}; + Common::Array cyc25{15,16,15,16,15,1+15,1+15,-1}; + Common::Array cyc26{10+15,11+15,12+15,13+15,14+15,15+15,16+15,-1}; + Common::Array cyc27{2+15,3+15,4+15,5+15,-1}; + Common::Array cyc28{6+15,7+15,8+15,9+15,-1}; + Common::Array cyc29{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,-1}; + Common::Array cyc30{0,1,2,3,3,3,3,4,5,6,-1}; + Common::Array cyc31{0,1,2,3,4,5,6,7,8,-1}; + + Common::Array c{SCycle(kBubble, false, cyc0), SCycle(kBubble, false, cyc1), + SCycle(kSpark, false, cyc2), SCycle(kSpark, false, cyc3), + SCycle(kSpark, false, cyc4), SCycle(kSpark, false, cyc5), SCycle(kSpark, false, cyc6), + SCycle(kPipe, false, cyc7), SCycle(kPipe, false, cyc8), + SCycle(kPipe, false, cyc9), SCycle(kPipe, false, cyc10), + SCycle(kAnaVanish, false, cyc11), SCycle(kAnaGlimpse, false, cyc12), + SCycle(kKnife, true, cyc13), + SCycle(kSpark, true, cyc14), SCycle(kSpark, true, cyc15), SCycle(kSpark, true, cyc16), + SCycle(kBigBurst, false, cyc17), + SCycle(kFlame, false, cyc18), SCycle(kFlame, false, cyc19), SCycle(kFlame, false, cyc20), + SCycle(kFlame, false, cyc21), SCycle(kFlame, false, cyc22), SCycle(kFlame, false, cyc23), + SCycle(kFlame, false, cyc24), + SCycle(kCandle, false, cyc25), SCycle(kCandle, false, cyc26), SCycle(kCandle, false, cyc27), + SCycle(kCandle, false, cyc28), SCycle(kCandle, false, cyc29), + SCycle(kSink, false, cyc30), + SCycle(kNorlacDown, false, cyc31)}; + _cycPtrs = c; + Common::Array m{}; _motivePtrs = m; @@ -483,32 +535,8 @@ void ImmortalEngine::initStoryStatic() { } -void ImmortalEngine::addSprite(uint16 x, uint16 y, SpriteName n, int img, uint16 p) { - if (_numSprites != kMaxSprites) { - if (x >= (kResH + kMaxSpriteLeft)) { - x |= kMaskHigh; // Make it negative - } - _sprites[_numSprites]._X = (x << 1) + _viewPortX; - - if (y >= (kMaxSpriteAbove + kResV)) { - y |= kMaskHigh; - } - _sprites[_numSprites]._Y = (y << 1) + _viewPortY; - - if (p >= 0x80) { - p |= kMaskHigh; - } - _sprites[_numSprites]._priority = ((p + y) ^ 0xFFFF) + 1; - - _sprites[_numSprites]._image = img; - _sprites[_numSprites]._dSprite = &_dataSprites[n]; - _sprites[_numSprites]._on = 1; - _numSprites += 1; - - } else { - debug("Max sprites reached beeeeeep!!"); - } - +void ImmortalEngine::kernalAddSprite(uint16 x, uint16 y, SpriteName n, int img, uint16 p) { + Immortal::Utilities::addSprite(_sprites, _viewPortX, _viewPortY, _numSprites, &_dataSprites[n], img, x, y, p); } void ImmortalEngine::clearSprites() { @@ -518,6 +546,13 @@ void ImmortalEngine::clearSprites() { } } +void ImmortalEngine::cycleFreeAll() { + // Sets all cycle indexes to -1, indicating they are available + for (int i = 0; i < kMaxCycles; i++) { + _cycles[i]._index = -1; + } +} + void ImmortalEngine::loadSprites() { /* This is a bit weird, so I'll explain. * In the source, this routine loads the files onto the heap, and then @@ -750,13 +785,13 @@ void ImmortalEngine::pump() { // Flashes the screen (except the frame thankfully) white, black, white, black, then clears the screen and goes back to normal useWhite(); g_system->updateScreen(); - Immortal::Util::delay(2); + Immortal::Utilities::delay(2); useBlack(); g_system->updateScreen(); - Immortal::Util::delay(2); + Immortal::Utilities::delay(2); useWhite(); g_system->updateScreen(); - Immortal::Util::delay(2); + Immortal::Utilities::delay(2); useBlack(); g_system->updateScreen(); clearScreen(); @@ -818,7 +853,7 @@ void ImmortalEngine::fade(uint16 pal[], int dir, int delay) { while ((count >= 0) && (count <= 256)) { fadePal(pal, count, target); - Immortal::Util::delay8(delay); + Immortal::Utilities::delay8(delay); setColors(target); // Same as above, it was originally a branch, this does the same thing From ef711df128f889f1b425710216f54db5d2d6b0be Mon Sep 17 00:00:00 2001 From: Quote58 Date: Tue, 23 Aug 2022 17:00:43 -0400 Subject: [PATCH 336/412] IMMORTAL: Util -> Utilities, and addition of addSprite to utilities --- engines/immortal/bitmask.h | 60 ----------------------- engines/immortal/module.mk | 2 +- engines/immortal/util.cpp | 49 ------------------- engines/immortal/util.h | 41 ---------------- engines/immortal/utilities.cpp | 79 ++++++++++++++++++++++++++++++ engines/immortal/utilities.h | 89 ++++++++++++++++++++++++++++++++++ 6 files changed, 169 insertions(+), 151 deletions(-) delete mode 100644 engines/immortal/bitmask.h delete mode 100644 engines/immortal/util.cpp delete mode 100644 engines/immortal/util.h create mode 100644 engines/immortal/utilities.cpp create mode 100644 engines/immortal/utilities.h diff --git a/engines/immortal/bitmask.h b/engines/immortal/bitmask.h deleted file mode 100644 index d9b5ba1509ae..000000000000 --- a/engines/immortal/bitmask.h +++ /dev/null @@ -1,60 +0,0 @@ -/* 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 . - * - */ - -#ifndef IMMORTAL_BITMASK_H -#define IMMORTAL_BITMASK_H - -namespace Immortal { - -enum BitMask16 : uint16 { - kMaskLow = 0x00FF, - kMaskHigh = 0xFF00, - kMaskLast = 0xF000, - kMaskFirst = 0x000F, - kMaskHLow = 0x0F00, - kMaskLHigh = 0x00F0, - kMaskNeg = 0x8000, - kMask12Bit = 0x0F9F // Compression code (pos, 00, len) is stored in lower 12 bits of word -}; - -enum BitMask8 : uint8 { - kMaskASCII = 0x7F, // The non-extended ASCII table uses 7 bits, this makes a couple of things easier - kMask8High = 0xF0, - kMask8Low = 0x0F -}; - -enum ColourBitMask : uint16 { - kMaskRed = 0x0F00, - kMaskGreen = 0x00F0, - kMaskBlue = 0x000F -}; - -enum ChrMask : uint16 { - kChr0 = 0x0000, - kChrL = 0x0001, - kChrR = 0xFFFF, - kChrLD = 0x0002, - kChrRD = 0xFFFE -}; - -} // namespace immortal - -#endif \ No newline at end of file diff --git a/engines/immortal/module.mk b/engines/immortal/module.mk index 16713fcb9353..3812d27981ce 100644 --- a/engines/immortal/module.mk +++ b/engines/immortal/module.mk @@ -2,7 +2,7 @@ MODULE := engines/immortal MODULE_OBJS = \ metaengine.o \ - util.o \ + utilities.o \ disk.o \ immortal.o \ kernal.o \ diff --git a/engines/immortal/util.cpp b/engines/immortal/util.cpp deleted file mode 100644 index 0bc671a6fbd2..000000000000 --- a/engines/immortal/util.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/* 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 "immortal/util.h" - -namespace Immortal { - -namespace Util { - -void Immortal::Util::delay(int j) { // Delay is measured in jiffies, which are 56.17ms - g_system->delayMillis(j * 56); -} - -void Immortal::Util::delay4(int j) { // Named in source quarterClock for some reason, 1/4 jiffies are 14.04ms - g_system->delayMillis(j * 14); -} - -void Immortal::Util::delay8(int j) { // 1/8 jiffies are 7.02ms - g_system->delayMillis(j * 7); -} - -bool Immortal::Util::inside(int x1, int y1, int a, int x2, int y2) { - return false; -} -bool Immortal::Util::insideRect(int x, int y, int r) { - return false; -} - -}; // namespace Util - -}; // namespace Immortal \ No newline at end of file diff --git a/engines/immortal/util.h b/engines/immortal/util.h deleted file mode 100644 index ba7ef1df514a..000000000000 --- a/engines/immortal/util.h +++ /dev/null @@ -1,41 +0,0 @@ -/* 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 . - * - */ - -#ifndef IMMORTAL_UTIL_H -#define IMMORTAL_UTIL_H - -#include "common/system.h" - -namespace Immortal { - -namespace Util { - -void delay(int j); // Delay engine by j jiffies (from driver originally, but makes more sense grouped with misc) -void delay4(int j); // || /4 -void delay8(int j); // || /8 -bool inside(int x1, int y1, int a, int x2, int y2); -bool insideRect(int x, int y, int r); - -}; // namespace Util - -}; // namespace Immortal - -#endif \ No newline at end of file diff --git a/engines/immortal/utilities.cpp b/engines/immortal/utilities.cpp new file mode 100644 index 000000000000..84c71b78ed26 --- /dev/null +++ b/engines/immortal/utilities.cpp @@ -0,0 +1,79 @@ +/* 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 "immortal/utilities.h" + +namespace Immortal { + +namespace Utilities { + +void Immortal::Utilities::delay(int j) { // Delay is measured in jiffies, which are 56.17ms + g_system->delayMillis(j * 56); +} + +void Immortal::Utilities::delay4(int j) { // Named in source quarterClock for some reason, 1/4 jiffies are 14.04ms + g_system->delayMillis(j * 14); +} + +void Immortal::Utilities::delay8(int j) { // 1/8 jiffies are 7.02ms + g_system->delayMillis(j * 7); +} + +bool Immortal::Utilities::inside(int x1, int y1, int a, int x2, int y2) { + return false; +} +bool Immortal::Utilities::insideRect(int x, int y, int r) { + return false; +} + +void Immortal::Utilities::addSprite(Sprite *sprites, uint16 vpX, uint16 vpY, int num, DataSprite *d, int img, uint16 x, uint16 y, uint16 p) { + if (num != kMaxSprites) { + if (x >= (kResH + kMaxSpriteLeft)) { + x |= kMaskHigh; // Make it negative + } + + sprites[num]._X = (x << 1) + vpX; + + if (y >= (kMaxSpriteAbove + kResV)) { + y |= kMaskHigh; + } + + sprites[num]._Y = (y << 1) + vpY; + + if (p >= 0x80) { + p |= kMaskHigh; + } + + sprites[num]._priority = ((p + y) ^ 0xFFFF) + 1; + + sprites[num]._image = img; + sprites[num]._dSprite = d; + sprites[num]._on = 1; + num += 1; + + } else { + debug("Max sprites reached beeeeeep!!"); + } +} + +}; // namespace Utilities + +}; // namespace Immortal \ No newline at end of file diff --git a/engines/immortal/utilities.h b/engines/immortal/utilities.h new file mode 100644 index 000000000000..c41d1668b750 --- /dev/null +++ b/engines/immortal/utilities.h @@ -0,0 +1,89 @@ +/* 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 . + * + */ + +#ifndef IMMORTAL_UTIL_H +#define IMMORTAL_UTIL_H + +#include "common/debug.h" +#include "common/debug-channels.h" +#include "common/system.h" +#include "immortal/sprite_list.h" + +namespace Immortal { + +enum BitMask16 : uint16 { + kMaskLow = 0x00FF, + kMaskHigh = 0xFF00, + kMaskLast = 0xF000, + kMaskFirst = 0x000F, + kMaskHLow = 0x0F00, + kMaskLHigh = 0x00F0, + kMaskNeg = 0x8000, + kMask12Bit = 0x0F9F // Compression code (pos, 00, len) is stored in lower 12 bits of word +}; + +enum BitMask8 : uint8 { + kMaskASCII = 0x7F, // The non-extended ASCII table uses 7 bits, this makes a couple of things easier + kMask8High = 0xF0, + kMask8Low = 0x0F +}; + +enum ColourBitMask : uint16 { + kMaskRed = 0x0F00, + kMaskGreen = 0x00F0, + kMaskBlue = 0x000F +}; + +enum ChrMask : uint16 { + kChr0 = 0x0000, + kChrL = 0x0001, + kChrR = 0xFFFF, + kChrLD = 0x0002, + kChrRD = 0xFFFE +}; + +enum Screen { // These are constants that are used for defining screen related arrays + kResH = 320, + kResV = 200, + kMaxSprites = 32, // Number of sprites allowed at once + kViewPortCW = 256 / 64, + kViewPortCH = 128 / kMaxSprites, + kMaxDrawItems = kViewPortCH + 1 + kMaxSprites, + kMaxSpriteAbove = 48, // Maximum sprite extents from center + kMaxSpriteBelow = 16, + kMaxSpriteLeft = 16, + kMaxSpriteRight = 16 +}; + +namespace Utilities { + +void delay(int j); // Delay engine by j jiffies (from driver originally, but makes more sense grouped with misc) +void delay4(int j); // || /4 +void delay8(int j); // || /8 +bool inside(int x1, int y1, int a, int x2, int y2); +bool insideRect(int x, int y, int r); +void addSprite(Sprite *sprites, uint16 vpX, uint16 vpY, int num, DataSprite *d, int img, uint16 x, uint16 y, uint16 p); + +}; // namespace Util + +}; // namespace Immortal + +#endif \ No newline at end of file From 5940f2312c1340ae5e7bb152964cf9cfa496db18 Mon Sep 17 00:00:00 2001 From: Quote58 Date: Tue, 23 Aug 2022 17:01:47 -0400 Subject: [PATCH 337/412] IMMORTAL: Add univAddSprite to univ.cpp --- engines/immortal/room.h | 75 +++++++++++++++++++++++++++++++-------- engines/immortal/univ.cpp | 5 ++- 2 files changed, 64 insertions(+), 16 deletions(-) diff --git a/engines/immortal/room.h b/engines/immortal/room.h index 58f893182b88..910101f211f4 100644 --- a/engines/immortal/room.h +++ b/engines/immortal/room.h @@ -39,14 +39,14 @@ #include "common/util.h" #include "common/platform.h" -// There is a lot of bit masking that needs to happen, so this header includes several enums for immortal.h, room.h, and monster.h -#include "immortal/bitmask.h" - -#include "immortal/util.h" - // Story is needed by both immortal.h and room.h #include "immortal/story.h" +// Utilities.h contains many things used by all objects, not just immortal +#include "immortal/utilities.h" + +#include "immortal/immortal.h" + #ifndef IMMORTAL_ROOM_H #define IMMORTAL_ROOM_H @@ -90,10 +90,10 @@ struct Monster { }; struct Flame { -FPattern _p; - uint8 _x; - uint8 _y; - CycID _c; +FPattern _p = kFlameOff; + uint8 _x = 0; + uint8 _y = 0; + int _c = 0; }; struct Chest { @@ -104,9 +104,10 @@ struct Bullet { class Room { private: + Common::RandomSource _randomSource; public: - Room(uint8 x, uint8 y, RoomFlag f); + Room(uint8 x, uint8 y, RoomFlag f, Sprite *s, DataSprite *d, Cycle *c, Common::Array p); ~Room() {} /* @@ -115,8 +116,15 @@ class Room { */ // Constants - const uint8 kLightTorchX = 10; + const uint8 kLightTorchX = 10; + const uint8 kMaxFlameCycs = 16; + + // Other + Sprite *_sprites; + Cycle *_cycles; +DataSprite *_dataSprites; +Common::Array _cycPtrs; Common::Array _fset; Common::Array _monsters; Common::Array _objects; @@ -136,6 +144,10 @@ Common::Array _objects; * */ + uint32 getRandomNumber(uint maxNum) { + return _randomSource.getRandomNumber(maxNum); + } + /* * [room.cpp] Functions from Room.GS */ @@ -145,7 +157,7 @@ Common::Array _objects; //void getTilePair(uint8 x, uint8 y); // Modifies a struct of the tile number, aboveTile number, and the cell coordinates of the tile void setHole(); - void drawContents(); + void drawContents(uint16 vX, uint16 vY, int nS); bool getTilePair(uint8 x, uint8 y, int id); bool getWideWallNormal(uint8 x, uint8 y, uint8 xPrev, uint8 yPrev, int id, int spacing); bool getWallNormal(uint8 x, uint8 y, uint8 xPrev, uint8 yPrev, int id); @@ -159,17 +171,45 @@ Common::Array _objects; void getCell(uint16 &x, uint16 &y); + /* + * [Cycle.cpp] Functions from Cyc + */ + + // Init + int cycleNew(CycID id); // Adds a cycle to the current list + void cycleFree(int c); + + // Getters +DataSprite *cycleGetDataSprite(int c); // This takes the place of getFile + getNum + int cycleGetIndex(int c); + int cycleGetFrame(int c); + int cycleGetNumFrames(int c); + + // Setters + void cycleSetIndex(int c, int f); + + // Misc + bool cycleAdvance(int c); + CycID getCycList(int c); + + /* Unneccessary cycle functions + void cycleInit(); + void cycleFree(); + void cycleGetNumFrames(); + void cycleGetList();*/ + /* * [flameSet.cpp] Functions from flameSet.GS */ + //void flameNew() does not need to exist, because we create the duplicate SFlame in Level, and the array in immortal.h is not accessable from here void flameInit(); - void flameSetRoom(Common::Array); - void flameDrawAll(); + void flameDrawAll(uint16 vX, uint16 vY, int nS); bool roomLighted(); void lightTorch(int x, int y); - CycID flameGetCyc(int first); void flameFreeAll(); + void flameSetRoom(Common::Array); + int flameGetCyc(Flame *f, int first); /* * [bullet.cpp] Functions from Bullet.GS @@ -182,6 +222,11 @@ Common::Array _objects; */ + /* + * [Univ.cpp] Functions from Univ.GS + */ + + void univAddSprite(uint16 vX, uint16 vY, int nS, uint16 x, uint16 y, SpriteName n, int img, uint16 p); }; diff --git a/engines/immortal/univ.cpp b/engines/immortal/univ.cpp index 7349cdbff8a1..f52997c0b2f2 100644 --- a/engines/immortal/univ.cpp +++ b/engines/immortal/univ.cpp @@ -19,9 +19,12 @@ * */ -#include "immortal/immortal.h" +#include "immortal/room.h" namespace Immortal { +void Room::univAddSprite(uint16 vX, uint16 vY, int nS, uint16 x, uint16 y, SpriteName n, int img, uint16 p) { + //Immortal::Utilities::addSprite(_sprites, vX, vY, nS, &_dataSprites[n], img, x, y, p); +} } // namespace immortal \ No newline at end of file From 821a539b6a7e863971156f0f2ba8914c7ceeecef Mon Sep 17 00:00:00 2001 From: Quote58 Date: Tue, 23 Aug 2022 17:03:40 -0400 Subject: [PATCH 338/412] IMMORTAL: Implement Cycles more accurately, under Room instead of Immortal, except for cycleFreeAll() --- engines/immortal/cycle.cpp | 38 ++++----- engines/immortal/immortal.h | 150 +++++++++++++++------------------ engines/immortal/level.cpp | 18 ++-- engines/immortal/room.cpp | 26 ++++-- engines/immortal/sprite_list.h | 11 ++- engines/immortal/story.h | 14 ++- 6 files changed, 126 insertions(+), 131 deletions(-) diff --git a/engines/immortal/cycle.cpp b/engines/immortal/cycle.cpp index 4a43b28be709..12b339090ba9 100644 --- a/engines/immortal/cycle.cpp +++ b/engines/immortal/cycle.cpp @@ -21,7 +21,7 @@ /* [Alternate Name: Sprite Animation Processing] * --- What is a Cycle --- - * Strictly speaking, a Cycle is an instruction list, but it gets a little confusing. + * Strictly speaking, a Cycle is an instruction list, but more specifically: * A 'Cyc' is defined through Story as a static ROM entry of the format: * file, num, numcycles, cycles[] * However file + num = datasprite, and numcycles is actually a boolean for repeat animation. @@ -40,16 +40,17 @@ * list of lexical pointers as byte indexes into word pointers (cycID -> cyclist) */ -#include "immortal/immortal.h" +#include "immortal/room.h" namespace Immortal { -int ImmortalEngine::cycleNew(CycID id) { +int Room::cycleNew(CycID id) { // An 'available' cyc is identified by the index being -1 for (int i = 0; i < kMaxCycles; i++) { if (_cycles[i]._index == -1) { _cycles[i]._index = 0; _cycles[i]._cycList = id; + debug("made cyc, = %d", i); return i; } } @@ -57,22 +58,16 @@ int ImmortalEngine::cycleNew(CycID id) { return kMaxCycles - 1; } -void ImmortalEngine::cycleFree(int c) { +void Room::cycleFree(int c) { _cycles[c]._index = -1; } -void ImmortalEngine::cycleFreeAll() { - for (int i = 0; i < kMaxCycles; i++) { - _cycles[i]._index = -1; - } -} - -bool ImmortalEngine::cycleAdvance(int c) { +bool Room::cycleAdvance(int c) { /* If we have reached the end, check if repeat == true, and set back to 0 if so * Otherwise, set to the last used index */ _cycles[c]._index++; - if (_cycPtrs[_cycles[c]._index]._frames[_cycles[c]._index] == -1) { - if (_cycPtrs[_cycles[c]._index]._repeat == true) { + if (_cycPtrs[_cycles[c]._cycList]._frames[_cycles[c]._index] == -1) { + if (_cycPtrs[_cycles[c]._cycList]._repeat == true) { _cycles[c]._index = 0; } else { _cycles[c]._index--; @@ -82,12 +77,13 @@ bool ImmortalEngine::cycleAdvance(int c) { return false; } -int ImmortalEngine::cycleGetFrame(int c) { +int Room::cycleGetFrame(int c) { // This originally did some shenanigans in Kernal to get the number, but really it's just this - return _cycPtrs[_cycles[c]._cycList]._frames[_cycles[c]._index]; + debug("%d", _cycPtrs[_cycles[c]._cycList]._frames[_cycles[c]._index]); + return _cycPtrs[_cycles[c]._cycList]._frames[_cycles[c]._index]; } -int ImmortalEngine::cycleGetNumFrames(int c) { +int Room::cycleGetNumFrames(int c) { // Why in the world is this not kept as a property of the cycle? We have to calculate the size of the array each time int index = 0; while (_cycPtrs[_cycles[c]._cycList]._frames[index] != -1) { @@ -96,19 +92,19 @@ int ImmortalEngine::cycleGetNumFrames(int c) { return index; } -DataSprite *ImmortalEngine::cycleGetDataSprite(int c) { - return _cycPtrs[_cycles[c]._cycList]._dSprite; +DataSprite *Room::cycleGetDataSprite(int c) { + return &_dataSprites[_cycPtrs[_cycles[c]._cycList]._sName]; } -CycID ImmortalEngine::getCycList(int c) { +CycID Room::getCycList(int c) { return _cycles[c]._cycList; } -int ImmortalEngine::cycleGetIndex(int c) { +int Room::cycleGetIndex(int c) { return _cycles[c]._index; } -void ImmortalEngine::cycleSetIndex(int c, int f) { +void Room::cycleSetIndex(int c, int f) { _cycles[c]._index = f; } diff --git a/engines/immortal/immortal.h b/engines/immortal/immortal.h index 4f71404eee5e..0dcfe60b77a4 100644 --- a/engines/immortal/immortal.h +++ b/engines/immortal/immortal.h @@ -56,14 +56,14 @@ #include "common/util.h" #include "common/platform.h" -// There is a lot of bit masking that needs to happen, so this header includes several enums for immortal.h, room.h, and monster.h -#include "immortal/bitmask.h" - -#include "immortal/util.h" - // Story is needed by both immortal.h and room.h #include "immortal/story.h" +// Utilities.h contains many things used by all objects, not just immortal +#include "immortal/utilities.h" + +#include "immortal/room.h" + namespace Immortal { // Needed by kernal for input @@ -185,25 +185,25 @@ class ImmortalEngine : public Engine { const int kMaxCertificate = 16; // Screen constants - const int kScreenW__ = 128; // ??? labeled in source as SCREENWIDTH - const int kScreenH__ = 128; // ??? - const int kViewPortW = 256; - const int kViewPortH = 128; - const int kScreenSize = (kResH * kResV) * 2; // The size of the screen buffer is 320x200 - const int kScreenLeft = 32; - const int kScreenTop = 20; - const int kTextLeft = 8; - const int kTextTop = 4; - const int kGaugeX = 0; - const int kGaugeY = -13; // ??? - const int kScreenBMW = 160; // Literally no idea yet - const uint16 kChrW = 64; - const uint16 kChrH = 32; - const uint16 kChrH2 = kChrH * 2; - const uint16 kChrH3 = kChrH * 3; - const int kChrLen = (kChrW / 2) * kChrH; - const int kChrBMW = kChrW / 2; - const int kLCutaway = 4; + const int kScreenW__ = 128; // ??? labeled in source as SCREENWIDTH + const int kScreenH__ = 128; // ??? + const int kViewPortW = 256; + const int kViewPortH = 128; + const int kScreenSize = (kResH * kResV) * 2; // The size of the screen buffer is 320x200 + const int kScreenLeft = 32; + const int kScreenTop = 20; + const int kTextLeft = 8; + const int kTextTop = 4; + const int kGaugeX = 0; + const int kGaugeY = -13; // ??? + const int kScreenBMW = 160; // Screen BitMap Width? + const uint16 kChrW = 64; + const uint16 kChrH = 32; + const uint16 kChrH2 = kChrH * 2; + const uint16 kChrH3 = kChrH * 3; + const int kChrLen = (kChrW / 2) * kChrH; + const int kChrBMW = kChrW / 2; + const int kLCutaway = 4; const uint16 kChrDy[19] = {kChr0, kChrH, kChrH2, kChrH, kChrH2, kChrH2, kChrH, kChrH2, kChrH2, kChr0, @@ -224,31 +224,31 @@ class ImmortalEngine : public Engine { 0, 0, 0, 0, 0, 0}; // Disk offsets - const int kPaletteOffset = 21205; // This is the byte position of the palette data in the disk + const int kPaletteOffset = 21205; // This is the byte position of the palette data in the disk // Sprite constants - const int kMaxSpriteW = 64; - const int kMaxSpriteH = 64; - const int kSpriteDY = 32; - const int kVSX = kMaxSpriteW; - const int kVSY = kSpriteDY; - const int kVSBMW = (kViewPortW + kMaxSpriteW) / 2; - const int kVSLen = kVSBMW * (kViewPortH + kMaxSpriteH); - const int kVSDY = 32; // difference from top of screen to top of viewport in the virtual screen buffer - const int kMySuperBottom = kVSDY + kViewPortH; - const int kSuperBottom = 200; - const int kMySuperTop = kVSDY; - const int kSuperTop = 0; - const int kViewPortSpX = 32; - const int kViewPortSpY = 0; - const int kWizardX = 28; // Common sprite center for some reason - const int kWizardY = 37; + const int kMaxSpriteW = 64; + const int kMaxSpriteH = 64; + const int kSpriteDY = 32; + const int kVSX = kMaxSpriteW; + const int kVSY = kSpriteDY; + const int kVSBMW = (kViewPortW + kMaxSpriteW) / 2; + const int kVSLen = kVSBMW * (kViewPortH + kMaxSpriteH); + const int kVSDY = 32; // difference from top of screen to top of viewport in the virtual screen buffer + const int kMySuperBottom = kVSDY + kViewPortH; + const int kSuperBottom = 200; + const int kMySuperTop = kVSDY; + const int kSuperTop = 0; + const int kViewPortSpX = 32; + const int kViewPortSpY = 0; + const int kWizardX = 28; // Common sprite center for some reason + const int kWizardY = 37; // Asset constants - const char kGaugeOn = 1; // On uses the sprite at index 1 of the font spriteset - const char kGaugeOff = 0; // Off uses the sprite at index 0 of the font spriteset - const char kGaugeStop = 1; // Literally just means the final kGaugeOn char to draw - const char kGaugeStart = 1; // First kGaugeOn char to draw + const char kGaugeOn = 1; // On uses the sprite at index 1 of the font spriteset + const char kGaugeOff = 0; // Off uses the sprite at index 0 of the font spriteset + const char kGaugeStop = 1; // Literally just means the final kGaugeOn char to draw + const char kGaugeStart = 1; // First kGaugeOn char to draw // Level constants const int kStoryNull = 5; @@ -263,16 +263,16 @@ class ImmortalEngine : public Engine { // Misc Common::ErrorCode _err; // If this is not kNoError at any point, the engine will stop uint8 _certificate[16]; // The certificate (password) is basically the inventory/equipment array - uint8 _lastCertLen = 0; - bool _draw = 0; // Whether the screen should draw this frame - int _zero = 0; // No idea what this is yet - bool _gameOverFlag = false; - uint8 _gameFlags = 0; // Bitflag array of event flags, but only two were used (saving ana and saving the king) <-- why is gameOverFlag not in this? Lol - bool _themePaused = false; // In the source, this is actually considered a bit flag array of 2 bits (b0 and b1). However, it only ever checks for non-zero, so it's effectively only 1 bit. - int _titlesShown = 0; - int _time = 0; - int _promoting = 0; // I think promoting means the title stuff - bool _restart = false; + uint8 _lastCertLen = 0; + bool _draw = 0; // Whether the screen should draw this frame + int _zero = 0; // No idea what this is yet + bool _gameOverFlag = false; + uint8 _gameFlags = 0; // Bitflag array of event flags, but only two were used (saving ana and saving the king) <-- why is gameOverFlag not in this? Lol + bool _themePaused = false; // In the source, this is actually considered a bit flag array of 2 bits (b0 and b1). However, it only ever checks for non-zero, so it's effectively only 1 bit. + int _titlesShown = 0; + int _time = 0; + int _promoting = 0; // I think promoting means the title stuff + bool _restart = false; // Story members Story _stories[8]; @@ -315,7 +315,7 @@ class ImmortalEngine : public Engine { uint8 _secretDelta = 0; // Debug members - bool _singleStep; // Flag for _singleStep mode + bool _singleStep = false; // Flag for _singleStep mode // Input members int _pressedAction = 0; @@ -353,16 +353,16 @@ class ImmortalEngine : public Engine { uint16 _columnIndex[kViewPortCW + 1]; // Why the heck is this an entire array, when it's just an index that gets zeroed before it gets used anyway... uint16 _tIndex[kMaxDrawItems]; uint16 _tPriority[kMaxDrawItems]; - uint16 _viewPortX = 0; - uint16 _viewPortY = 0; - uint16 _myViewPortX = 0; // Probably mirror of viewportX - uint16 _myViewPortY = 0; - int _lastGauge = 0; // Mirror for player health, used to update health gauge display - uint16 _penX = 0; // Basically where in the screen we are currently drawing - uint16 _penY = 0; - uint16 _myUnivPointX = 0; - uint16 _myUnivPointY = 0; - int _num2DrawItems = 0; + uint16 _viewPortX = 0; + uint16 _viewPortY = 0; + uint16 _myViewPortX = 0; // Probably mirror of viewportX + uint16 _myViewPortY = 0; + int _lastGauge = 0; // Mirror for player health, used to update health gauge display + uint16 _penX = 0; // Basically where in the screen we are currently drawing + uint16 _penY = 0; + uint16 _myUnivPointX = 0; + uint16 _myUnivPointY = 0; + int _num2DrawItems = 0; Graphics::Surface *_mainSurface; GenericSprite _genSprites[6]; @@ -382,8 +382,6 @@ GenericSprite _genSprites[6]; * */ - void setSprites(Sprite *s); - /* * [Kernal.cpp] Functions from Kernal.gs and Driver.gs */ @@ -560,28 +558,12 @@ GenericSprite _genSprites[6]; //void setLastType <-- sta lastType //void getShowRoom <-- lda currentRoom - /* * [Cycle.cpp] Functions from Cyc */ // Misc - int cycleNew(CycID id); // Adds a cycle to the current list void cycleFreeAll(); // Delete all cycles - void cycleFree(int c); -DataSprite *cycleGetDataSprite(int c); // This takes the place of getFile + getNum - int cycleGetIndex(int c); - void cycleSetIndex(int c, int f); - int cycleGetFrame(int c); - int cycleGetNumFrames(int c); - bool cycleAdvance(int c); - CycID getCycList(int c); - - /* Unneccessary cycle functions - void cycleInit(); - void cycleFree(); - void cycleGetNumFrames(); - void cycleGetList();*/ /* diff --git a/engines/immortal/level.cpp b/engines/immortal/level.cpp index b125d6ed6b3d..93e776c3c248 100644 --- a/engines/immortal/level.cpp +++ b/engines/immortal/level.cpp @@ -74,12 +74,10 @@ void ImmortalEngine::levelLoadFile(int l) { for (int d = 0; d < _stories[l]._doors.size(); d++) { doorNew(_stories[l]._doors[d]); - debug("door %d", d); } for (int r = 0; r < _stories[l]._rooms.size(); r++) { - _rooms[r] = new Room(_stories[l]._rooms[r]._x, _stories[l]._rooms[r]._y, _stories[l]._rooms[r]._flags); - debug("Room %d", r); + _rooms[r] = new Room(_stories[l]._rooms[r]._x, _stories[l]._rooms[r]._y, _stories[l]._rooms[r]._flags, _sprites, _dataSprites, _cycles, _cycPtrs); Common::Array allFlames(_stories[l]._flames[r].size()); if (_stories[l]._flames[r].size() > 0) { @@ -89,28 +87,21 @@ void ImmortalEngine::levelLoadFile(int l) { sf._x = _stories[l]._flames[r][f]._x; sf._y = _stories[l]._flames[r][f]._y; allFlames[f] = sf; - debugN("F%d", f); } } _allFlames[r] = allFlames; - debug(""); if (_stories[l]._objects[r].size() > 0) { for (int o = 0; o < _stories[l]._objects[r].size(); o++) { //objNew(_stories[l]._objects[r][o]); - debugN("O%d", o); } } - debug(""); if (_stories[l]._monsters[r].size() > 0) { for (int m = 0; m < _stories[l]._monsters[r].size(); m++) { //monstNew(_stories[l]._monsters[r][m]); - debugN("M%d", m); } } - debug(""); - } // Set up the _initial variables for the engine scope @@ -123,6 +114,7 @@ void ImmortalEngine::univAtNew(int l) { _initialY = _stories[l]._initialUnivY; _initialBX = _stories[l]._playerPointX; _initialBY = _stories[l]._playerPointY; + //doorToNextLevel(_stories[l]._doorToNextLevel, _initialBX, _initialBY); //doorSetLadders(_stories[l]._doorSetLadders); //roomSetHole(_stories[l]._setHole, _stories[l]._setHoleX, _stories[l]._setHoleY); @@ -133,12 +125,14 @@ void ImmortalEngine::levelDrawAll() { _count++; //univAutoCenter(); clearSprites(); - _rooms[_currentRoom]->drawContents(); + // Room needs to be able to add to the sprite list, so we need to give it a pointer to it first + _rooms[_currentRoom]->drawContents(_viewPortX, _viewPortY, _numSprites); } void ImmortalEngine::levelShowRoom(int r, int bX, int bY) { _currentRoom = r; - _rooms[r]->flameSetRoom(_allFlames[r]); + cycleFreeAll(); // This may not be needed, or it may need to be changed slightly + _rooms[_currentRoom]->flameSetRoom(_allFlames[r]); //univSetRoom(r, bX, bY); //fset, spark, bullet, and door get set to the current room //roomGetCell(r, bX, bY); diff --git a/engines/immortal/room.cpp b/engines/immortal/room.cpp index 320624f16955..9ffdcc286c78 100644 --- a/engines/immortal/room.cpp +++ b/engines/immortal/room.cpp @@ -23,11 +23,16 @@ namespace Immortal { -Room::Room(uint8 x, uint8 y, RoomFlag f) { - _xPos = x; - _yPos = y; - _flags = f; - _candleTmp = 0; +Room::Room(uint8 x, uint8 y, RoomFlag f, Sprite *s, DataSprite *d, Cycle *c, Common::Array p) + : _xPos(x) + , _yPos(y) + , _flags(f) + , _sprites(s) + , _dataSprites(d) + , _cycles(c) + , _cycPtrs(p) + , _candleTmp(0) + , _randomSource("Immortal") { } void Room::addMonster() { @@ -65,7 +70,16 @@ void Room::getCell(uint16 &x, uint16 &y) { } void Room::setHole() {} -void Room::drawContents() {} + +void Room::drawContents(uint16 vX, uint16 vY, int nS) { + flameDrawAll(vX, vY, nS); + //sparkDrawAll(); + //bulletDrawAll(); + //genSpriteDrawAll(); + //loop over monsters and draw each + //loop over objects and draw each + //doorDrawAll(); +} bool Room::getWideWallNormal(uint8 x, uint8 y, uint8 xPrev, uint8 yPrev, int id, int spacing) { return true; diff --git a/engines/immortal/sprite_list.h b/engines/immortal/sprite_list.h index 7633becd4b7d..ad0a9af44be3 100644 --- a/engines/immortal/sprite_list.h +++ b/engines/immortal/sprite_list.h @@ -39,10 +39,13 @@ struct DataSprite { Common::Array _images; }; -// Cycles define the animation of sprites within a level. There is a fixed total of cycles available, and they are not room dependant -struct Cycle { - int _index; // In source this is actually the position within the *instruction list*, but since cycle's are structs, it's just the index of frames now - CycID _cycList; +struct Sprite { + int _image; // Index of _dSprite._frames[] + uint16 _X; + uint16 _Y; + uint16 _on; // 1 = active + uint16 _priority; +DataSprite *_dSprite; }; enum SpriteFrame { diff --git a/engines/immortal/story.h b/engines/immortal/story.h index 759bcb9e8a6b..0fb02e69ac24 100644 --- a/engines/immortal/story.h +++ b/engines/immortal/story.h @@ -129,18 +129,24 @@ struct ObjType { Use _run; }; +// Cycles define the animation of sprites within a level. There is a fixed total of cycles available, and they are not room dependant +struct Cycle { + int _index; // In source this is actually the position within the *instruction list*, but since cycle's are structs, it's just the index of frames now + CycID _cycList; +}; + /* Strictly speaking, many of these structs (which were rom data written dynamically * with compiler macros) combine multiple properties into single bytes (ex. room uses * bits 0-2 of X to also hold the roomOP, and bits 0-2 of Y to hold flags). However * for the moment there's no need to replicate this particular bit of space saving. */ struct SCycle { -DataSprite *_dSprite; +SpriteName _sName; bool _repeat; - int *_frames; +Common::Array _frames; SCycle() {} - SCycle(DataSprite *d, bool r, int *f) { - _dSprite = d; + SCycle(SpriteName s, bool r, Common::Array f) { + _sName = s; _repeat = r; _frames = f; } From d13fbf16a5163638b7f8c81cfa7e4af928f910f1 Mon Sep 17 00:00:00 2001 From: Quote58 Date: Tue, 23 Aug 2022 17:04:32 -0400 Subject: [PATCH 339/412] IMMORTAL: Implement flameSet.cpp --- engines/immortal/flameSet.cpp | 89 +++++++++++++++++++++++++++++------ 1 file changed, 75 insertions(+), 14 deletions(-) diff --git a/engines/immortal/flameSet.cpp b/engines/immortal/flameSet.cpp index fe335010cf40..994147d01aa7 100644 --- a/engines/immortal/flameSet.cpp +++ b/engines/immortal/flameSet.cpp @@ -35,23 +35,30 @@ namespace Immortal { -void Room::flameSetRoom(Common::Array allFlames) { - for (int i = 0; i < allFlames.size(); i++) { - Flame f; - f._p = allFlames[i]._p; - f._x = allFlames[i]._x; - f._y = allFlames[i]._y; - f._c = flameGetCyc(0 | _candleTmp); - _candleTmp = 1; - _fset.push_back(f); - } +void Room::flameInit() { + flameFreeAll(); + _candleTmp = 0; } -void Room::flameDrawAll() { +void Room::flameFreeAll() { + _numFlames = 0; + _numInRoom = 0; +} +void Room::flameDrawAll(uint16 vX, uint16 vY, int nS) { + for (int i = 0; i < _fset.size(); i++) { + univAddSprite(vX, vY, nS, _fset[i]._x, _fset[i]._y, _cycPtrs[_cycles[_fset[i]._c]._cycList]._sName, cycleGetFrame(_fset[i]._c), 0); + if (cycleAdvance(_fset[i]._c) == true) { + cycleFree(_fset[i]._c); + _fset[i]._c = flameGetCyc(&_fset[i], 1); + } + } } bool Room::roomLighted() { + // Just for now, we say it's always lit + return true; + // Very simple, just checks every torch and if any of them are lit, we say the room is lit for (int i = 0; i < _fset.size(); i++) { if (_fset[i]._p != kFlameOff) { @@ -72,7 +79,7 @@ void Room::lightTorch(int x, int y) { for (int i = 0; i < _fset.size(); i++) { if (_fset[i]._p == kFlameOff) { - if (Immortal::Util::inside(x, y, kLightTorchX, _fset[i]._x + 16, _fset[i]._y + 8)) { + if (Immortal::Utilities::inside(x, y, kLightTorchX, _fset[i]._x + 16, _fset[i]._y + 8)) { _fset[i]._p = kFlameNormal; } @@ -80,8 +87,62 @@ void Room::lightTorch(int x, int y) { } } -Cyc Room::flameGetCyc(int first) { - return kCycNone; +void Room::flameSetRoom(Common::Array allFlames) { + for (int i = 0; i < allFlames.size(); i++) { + Flame f; + f._p = allFlames[i]._p; + f._x = allFlames[i]._x; + f._y = allFlames[i]._y; + f._c = flameGetCyc(&f, (0 | _candleTmp)); + debug("made flame, cyc = %d", f._c); + _fset.push_back(f); + } + _candleTmp = 1; +} + +int Room::flameGetCyc(Flame *f, int first) { + /* I must say, although this is clever, it is the most + * convoluted way to do this I could imagine. Here's what it does: + * Get a random number between 0 and 255. Now reduce this number by the length + * of the array for the particular flame pattern until we are at less than 0. + * Now add back that same length. We are now at the length of the array + * minus a random amount between 0 and the length of the array. + * This gives us a random entry within the array to start at. + */ + CycID flamePatA[] = {kCycFNormal0, kCycFNormal1, kCycFNormal2, + kCycFNormal0, kCycFNormal1, kCycFNormal2, + kCycFNormal0, kCycFNormal1, kCycFNormal2, + kCycFNormal0, kCycFNormal1, kCycFNormal2}; + CycID flamePatB[] = {kCycFCandleBurst, kCycFCandleSway, kCycFCandleJump, + kCycFCandleLeap, kCycFCandleFlicker, + kCycFCandleFlicker, kCycFCandleFlicker, kCycFCandleFlicker}; + CycID flamePatC[] = {kCycFOff}; + CycID flamePatD[] = {kCycFFlicker0, kCycFFlicker1, kCycFFlicker2}; + + int numFlameCycs[] = {12, 8, 1, 3}; + + int r = getRandomNumber(255) & (kMaxFlameCycs - 1); + + do { + r -= numFlameCycs[(int) f->_p]; + } while (r >= 0); + + r += numFlameCycs[(int) f->_p]; + + // Why is this not indexed further? ie. LDA patternTable,x : STA $00 : LDA ($00),y instead of a branch tree? + // Pretty sure CPX 3 times is more than a single LDA (dp),y + switch (f->_p) { + case 0: + return cycleNew(flamePatA[r]); + case 1: + return cycleNew(flamePatB[r]); + case 2: + return cycleNew(flamePatC[r]); + case 3: + return cycleNew(flamePatD[r]); + default: + return 0; + } } } // namespace immortal From 259e993f680ec3a7dfed1749bca93298af5a5077 Mon Sep 17 00:00:00 2001 From: Quote58 Date: Tue, 23 Aug 2022 17:08:35 -0400 Subject: [PATCH 340/412] IMMORTAL: Spaces -> Tabs --- engines/immortal/univ.cpp | 2 +- engines/immortal/utilities.h | 58 ++++++++++++++++++------------------ 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/engines/immortal/univ.cpp b/engines/immortal/univ.cpp index f52997c0b2f2..91629b242533 100644 --- a/engines/immortal/univ.cpp +++ b/engines/immortal/univ.cpp @@ -24,7 +24,7 @@ namespace Immortal { void Room::univAddSprite(uint16 vX, uint16 vY, int nS, uint16 x, uint16 y, SpriteName n, int img, uint16 p) { - //Immortal::Utilities::addSprite(_sprites, vX, vY, nS, &_dataSprites[n], img, x, y, p); + //Immortal::Utilities::addSprite(_sprites, vX, vY, nS, &_dataSprites[n], img, x, y, p); } } // namespace immortal \ No newline at end of file diff --git a/engines/immortal/utilities.h b/engines/immortal/utilities.h index c41d1668b750..6da4088a2e48 100644 --- a/engines/immortal/utilities.h +++ b/engines/immortal/utilities.h @@ -30,47 +30,47 @@ namespace Immortal { enum BitMask16 : uint16 { - kMaskLow = 0x00FF, - kMaskHigh = 0xFF00, - kMaskLast = 0xF000, - kMaskFirst = 0x000F, - kMaskHLow = 0x0F00, - kMaskLHigh = 0x00F0, - kMaskNeg = 0x8000, - kMask12Bit = 0x0F9F // Compression code (pos, 00, len) is stored in lower 12 bits of word + kMaskLow = 0x00FF, + kMaskHigh = 0xFF00, + kMaskLast = 0xF000, + kMaskFirst = 0x000F, + kMaskHLow = 0x0F00, + kMaskLHigh = 0x00F0, + kMaskNeg = 0x8000, + kMask12Bit = 0x0F9F // Compression code (pos, 00, len) is stored in lower 12 bits of word }; enum BitMask8 : uint8 { - kMaskASCII = 0x7F, // The non-extended ASCII table uses 7 bits, this makes a couple of things easier - kMask8High = 0xF0, - kMask8Low = 0x0F + kMaskASCII = 0x7F, // The non-extended ASCII table uses 7 bits, this makes a couple of things easier + kMask8High = 0xF0, + kMask8Low = 0x0F }; enum ColourBitMask : uint16 { - kMaskRed = 0x0F00, - kMaskGreen = 0x00F0, - kMaskBlue = 0x000F + kMaskRed = 0x0F00, + kMaskGreen = 0x00F0, + kMaskBlue = 0x000F }; enum ChrMask : uint16 { - kChr0 = 0x0000, - kChrL = 0x0001, - kChrR = 0xFFFF, - kChrLD = 0x0002, - kChrRD = 0xFFFE + kChr0 = 0x0000, + kChrL = 0x0001, + kChrR = 0xFFFF, + kChrLD = 0x0002, + kChrRD = 0xFFFE }; enum Screen { // These are constants that are used for defining screen related arrays - kResH = 320, - kResV = 200, - kMaxSprites = 32, // Number of sprites allowed at once - kViewPortCW = 256 / 64, - kViewPortCH = 128 / kMaxSprites, - kMaxDrawItems = kViewPortCH + 1 + kMaxSprites, - kMaxSpriteAbove = 48, // Maximum sprite extents from center - kMaxSpriteBelow = 16, - kMaxSpriteLeft = 16, - kMaxSpriteRight = 16 + kResH = 320, + kResV = 200, + kMaxSprites = 32, // Number of sprites allowed at once + kViewPortCW = 256 / 64, + kViewPortCH = 128 / kMaxSprites, + kMaxDrawItems = kViewPortCH + 1 + kMaxSprites, + kMaxSpriteAbove = 48, // Maximum sprite extents from center + kMaxSpriteBelow = 16, + kMaxSpriteLeft = 16, + kMaxSpriteRight = 16 }; namespace Utilities { From 4b28cc268d216f26821eb3c770ecb67c07bfd9a7 Mon Sep 17 00:00:00 2001 From: Quote58 Date: Sat, 3 Sep 2022 23:47:52 -0400 Subject: [PATCH 341/412] IMMORTAL: Remove redundant namespaces in Utilities --- engines/immortal/utilities.cpp | 35 ++++++++++++++++------------------ engines/immortal/utilities.h | 2 +- 2 files changed, 17 insertions(+), 20 deletions(-) diff --git a/engines/immortal/utilities.cpp b/engines/immortal/utilities.cpp index 84c71b78ed26..21ca9e138108 100644 --- a/engines/immortal/utilities.cpp +++ b/engines/immortal/utilities.cpp @@ -23,57 +23,54 @@ namespace Immortal { -namespace Utilities { - -void Immortal::Utilities::delay(int j) { // Delay is measured in jiffies, which are 56.17ms +void Utilities::delay(int j) { // Delay is measured in jiffies, which are 56.17ms g_system->delayMillis(j * 56); } -void Immortal::Utilities::delay4(int j) { // Named in source quarterClock for some reason, 1/4 jiffies are 14.04ms +void Utilities::delay4(int j) { // Named in source quarterClock for some reason, 1/4 jiffies are 14.04ms g_system->delayMillis(j * 14); } -void Immortal::Utilities::delay8(int j) { // 1/8 jiffies are 7.02ms +void Utilities::delay8(int j) { // 1/8 jiffies are 7.02ms g_system->delayMillis(j * 7); } -bool Immortal::Utilities::inside(int x1, int y1, int a, int x2, int y2) { +bool Utilities::inside(int x1, int y1, int a, int x2, int y2) { return false; } -bool Immortal::Utilities::insideRect(int x, int y, int r) { +bool Utilities::insideRect(int x, int y, int r) { return false; } -void Immortal::Utilities::addSprite(Sprite *sprites, uint16 vpX, uint16 vpY, int num, DataSprite *d, int img, uint16 x, uint16 y, uint16 p) { - if (num != kMaxSprites) { +void Utilities::addSprite(Sprite *sprites, uint16 vpX, uint16 vpY, int *num, DataSprite *d, int img, uint16 x, uint16 y, uint16 p) { + debug("adding sprite..."); + if (*num != kMaxSprites) { if (x >= (kResH + kMaxSpriteLeft)) { x |= kMaskHigh; // Make it negative } - sprites[num]._X = (x << 1) + vpX; + sprites[*num]._X = (x << 1) + vpX; if (y >= (kMaxSpriteAbove + kResV)) { y |= kMaskHigh; } - sprites[num]._Y = (y << 1) + vpY; + sprites[*num]._Y = (y << 1) + vpY; if (p >= 0x80) { p |= kMaskHigh; } - sprites[num]._priority = ((p + y) ^ 0xFFFF) + 1; + sprites[*num]._priority = ((p + y) ^ 0xFFFF) + 1; - sprites[num]._image = img; - sprites[num]._dSprite = d; - sprites[num]._on = 1; - num += 1; - + sprites[*num]._image = img; + sprites[*num]._dSprite = d; + sprites[*num]._on = 1; + *num += 1; + debug("sprite added"); } else { debug("Max sprites reached beeeeeep!!"); } } -}; // namespace Utilities - }; // namespace Immortal \ No newline at end of file diff --git a/engines/immortal/utilities.h b/engines/immortal/utilities.h index 6da4088a2e48..0c8304f22f21 100644 --- a/engines/immortal/utilities.h +++ b/engines/immortal/utilities.h @@ -80,7 +80,7 @@ void delay4(int j); // || /4 void delay8(int j); // || /8 bool inside(int x1, int y1, int a, int x2, int y2); bool insideRect(int x, int y, int r); -void addSprite(Sprite *sprites, uint16 vpX, uint16 vpY, int num, DataSprite *d, int img, uint16 x, uint16 y, uint16 p); +void addSprite(Sprite *sprites, uint16 vpX, uint16 vpY, int *num, DataSprite *d, int img, uint16 x, uint16 y, uint16 p); }; // namespace Util From ff06e73d6f24ad501b037deae2c3ab0131963200 Mon Sep 17 00:00:00 2001 From: Quote58 Date: Sat, 3 Sep 2022 23:53:16 -0400 Subject: [PATCH 342/412] IMMORTAL: Room includes reference to sprite data from ImmortalEngine --- engines/immortal/level.cpp | 5 ++--- engines/immortal/room.cpp | 7 ++++--- engines/immortal/room.h | 13 +++++++------ 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/engines/immortal/level.cpp b/engines/immortal/level.cpp index 93e776c3c248..92510e2022f6 100644 --- a/engines/immortal/level.cpp +++ b/engines/immortal/level.cpp @@ -70,14 +70,13 @@ void ImmortalEngine::levelLoadFile(int l) { */ // Create the rooms and doors, then populate the rooms with their objects and actors - debug("loading level file..."); for (int d = 0; d < _stories[l]._doors.size(); d++) { doorNew(_stories[l]._doors[d]); } for (int r = 0; r < _stories[l]._rooms.size(); r++) { - _rooms[r] = new Room(_stories[l]._rooms[r]._x, _stories[l]._rooms[r]._y, _stories[l]._rooms[r]._flags, _sprites, _dataSprites, _cycles, _cycPtrs); + _rooms[r] = new Room(_stories[l]._rooms[r]._x, _stories[l]._rooms[r]._y, _stories[l]._rooms[r]._flags, _sprites, _dataSprites, _cycles, _cycPtrs, &_numSprites); Common::Array allFlames(_stories[l]._flames[r].size()); if (_stories[l]._flames[r].size() > 0) { @@ -126,7 +125,7 @@ void ImmortalEngine::levelDrawAll() { //univAutoCenter(); clearSprites(); // Room needs to be able to add to the sprite list, so we need to give it a pointer to it first - _rooms[_currentRoom]->drawContents(_viewPortX, _viewPortY, _numSprites); + _rooms[_currentRoom]->drawContents(_viewPortX, _viewPortY); } void ImmortalEngine::levelShowRoom(int r, int bX, int bY) { diff --git a/engines/immortal/room.cpp b/engines/immortal/room.cpp index 9ffdcc286c78..a66573f2e832 100644 --- a/engines/immortal/room.cpp +++ b/engines/immortal/room.cpp @@ -23,7 +23,7 @@ namespace Immortal { -Room::Room(uint8 x, uint8 y, RoomFlag f, Sprite *s, DataSprite *d, Cycle *c, Common::Array p) +Room::Room(uint8 x, uint8 y, RoomFlag f, Sprite *s, DataSprite *d, Cycle *c, Common::Array p, int *n) : _xPos(x) , _yPos(y) , _flags(f) @@ -31,6 +31,7 @@ Room::Room(uint8 x, uint8 y, RoomFlag f, Sprite *s, DataSprite *d, Cycle *c, Com , _dataSprites(d) , _cycles(c) , _cycPtrs(p) + , _numSprites(n) , _candleTmp(0) , _randomSource("Immortal") { } @@ -71,8 +72,8 @@ void Room::getCell(uint16 &x, uint16 &y) { void Room::setHole() {} -void Room::drawContents(uint16 vX, uint16 vY, int nS) { - flameDrawAll(vX, vY, nS); +void Room::drawContents(uint16 vX, uint16 vY) { + //flameDrawAll(vX, vY); //sparkDrawAll(); //bulletDrawAll(); //genSpriteDrawAll(); diff --git a/engines/immortal/room.h b/engines/immortal/room.h index 910101f211f4..b663329a3a4c 100644 --- a/engines/immortal/room.h +++ b/engines/immortal/room.h @@ -107,7 +107,7 @@ class Room { Common::RandomSource _randomSource; public: - Room(uint8 x, uint8 y, RoomFlag f, Sprite *s, DataSprite *d, Cycle *c, Common::Array p); + Room(uint8 x, uint8 y, RoomFlag f, Sprite *s, DataSprite *d, Cycle *c, Common::Array p, int *n); ~Room() {} /* @@ -120,8 +120,9 @@ class Room { const uint8 kMaxFlameCycs = 16; // Other - Sprite *_sprites; - Cycle *_cycles; + int *_numSprites; + Sprite *_sprites; + Cycle *_cycles; DataSprite *_dataSprites; Common::Array _cycPtrs; @@ -157,7 +158,7 @@ Common::Array _objects; //void getTilePair(uint8 x, uint8 y); // Modifies a struct of the tile number, aboveTile number, and the cell coordinates of the tile void setHole(); - void drawContents(uint16 vX, uint16 vY, int nS); + void drawContents(uint16 vX, uint16 vY); bool getTilePair(uint8 x, uint8 y, int id); bool getWideWallNormal(uint8 x, uint8 y, uint8 xPrev, uint8 yPrev, int id, int spacing); bool getWallNormal(uint8 x, uint8 y, uint8 xPrev, uint8 yPrev, int id); @@ -204,7 +205,7 @@ DataSprite *cycleGetDataSprite(int c); // This takes the place of getFile + ge //void flameNew() does not need to exist, because we create the duplicate SFlame in Level, and the array in immortal.h is not accessable from here void flameInit(); - void flameDrawAll(uint16 vX, uint16 vY, int nS); + void flameDrawAll(uint16 vX, uint16 vY); bool roomLighted(); void lightTorch(int x, int y); void flameFreeAll(); @@ -226,7 +227,7 @@ DataSprite *cycleGetDataSprite(int c); // This takes the place of getFile + ge * [Univ.cpp] Functions from Univ.GS */ - void univAddSprite(uint16 vX, uint16 vY, int nS, uint16 x, uint16 y, SpriteName n, int img, uint16 p); + void univAddSprite(uint16 vX, uint16 vY, uint16 x, uint16 y, SpriteName n, int img, uint16 p); }; From 89cbe5974d13b70f4729dd23047802903c15221e Mon Sep 17 00:00:00 2001 From: Quote58 Date: Sat, 3 Sep 2022 23:56:16 -0400 Subject: [PATCH 343/412] IMMORTAL: Initial implementation of superSprites() + adjustment to sprite structs --- engines/immortal/cycle.cpp | 11 ++- engines/immortal/flameSet.cpp | 4 +- engines/immortal/immortal.cpp | 5 +- engines/immortal/immortal.h | 9 +- engines/immortal/kernal.cpp | 22 +++-- engines/immortal/room.cpp | 2 +- engines/immortal/sprite_list.h | 21 +++-- engines/immortal/sprites.cpp | 167 +++++++++++++++++++++++++++++++-- engines/immortal/story.h | 3 - engines/immortal/univ.cpp | 5 +- 10 files changed, 213 insertions(+), 36 deletions(-) diff --git a/engines/immortal/cycle.cpp b/engines/immortal/cycle.cpp index 12b339090ba9..f2da5503c5f4 100644 --- a/engines/immortal/cycle.cpp +++ b/engines/immortal/cycle.cpp @@ -78,7 +78,16 @@ bool Room::cycleAdvance(int c) { } int Room::cycleGetFrame(int c) { - // This originally did some shenanigans in Kernal to get the number, but really it's just this + /* The source version of this is facinating. It is basically: + * in: cycList, Index + * index -> tmp + * Load the value of cycPtrs + cycList (returns address of start of cyc) + * Add index (returns address of frame in cyc) + * Store to the position of the next label + * Load a single byte from the value at the address in the label (returns frame value within cyc) + * This is essentially self-modifying code, and it saves 2 bytes of DP memory over the traditional + * STA DP : LDA (DP) + */ debug("%d", _cycPtrs[_cycles[c]._cycList]._frames[_cycles[c]._index]); return _cycPtrs[_cycles[c]._cycList]._frames[_cycles[c]._index]; } diff --git a/engines/immortal/flameSet.cpp b/engines/immortal/flameSet.cpp index 994147d01aa7..c861cb67220b 100644 --- a/engines/immortal/flameSet.cpp +++ b/engines/immortal/flameSet.cpp @@ -45,9 +45,9 @@ void Room::flameFreeAll() { _numInRoom = 0; } -void Room::flameDrawAll(uint16 vX, uint16 vY, int nS) { +void Room::flameDrawAll(uint16 vX, uint16 vY) { for (int i = 0; i < _fset.size(); i++) { - univAddSprite(vX, vY, nS, _fset[i]._x, _fset[i]._y, _cycPtrs[_cycles[_fset[i]._c]._cycList]._sName, cycleGetFrame(_fset[i]._c), 0); + univAddSprite(vX, vY, _fset[i]._x, _fset[i]._y, _cycPtrs[_cycles[_fset[i]._c]._cycList]._sName, cycleGetFrame(_fset[i]._c), 0); if (cycleAdvance(_fset[i]._c) == true) { cycleFree(_fset[i]._c); _fset[i]._c = flameGetCyc(&_fset[i], 1); diff --git a/engines/immortal/immortal.cpp b/engines/immortal/immortal.cpp index c75105de4133..e6b638da1d73 100644 --- a/engines/immortal/immortal.cpp +++ b/engines/immortal/immortal.cpp @@ -171,7 +171,6 @@ Common::Error ImmortalEngine::run() { _err = Common::kNoError; while (!shouldQuit()) { - /* The game loop runs at 60fps, which is 16 milliseconds per frame. * This loop keeps that time by getting the time in milliseconds at the start of the loop, * then again at the end, and the difference between them is the remainder @@ -187,9 +186,11 @@ Common::Error ImmortalEngine::run() { userIO(); noNetwork(); pollKeys(); - logic(); + //logic(); pollKeys(); if (logicFreeze() == 0) { + DataSprite *d = &_dataSprites[kFont]; + superSprite(d, 0xC0, 0x50, 0, 0, _screenBuff, kSuperTop, kMySuperBottom); drawUniv(); pollKeys(); fixColors(); diff --git a/engines/immortal/immortal.h b/engines/immortal/immortal.h index 0dcfe60b77a4..703b97478e4d 100644 --- a/engines/immortal/immortal.h +++ b/engines/immortal/immortal.h @@ -358,6 +358,9 @@ class ImmortalEngine : public Engine { uint16 _myViewPortX = 0; // Probably mirror of viewportX uint16 _myViewPortY = 0; int _lastGauge = 0; // Mirror for player health, used to update health gauge display + uint16 _lastBMW = 0; // Mirrors used to determine where bitmap width needs to be re-calculated + uint16 _lastY = 0; + uint16 _lastPoint = 0; uint16 _penX = 0; // Basically where in the screen we are currently drawing uint16 _penY = 0; uint16 _myUnivPointX = 0; @@ -581,8 +584,10 @@ GenericSprite _genSprites[6]; void initDataSprite(Common::SeekableReadStream *f, DataSprite *d, int index, uint16 cenX, uint16 cenY); // Initializes the data sprite // Main - void superSprite(int s, uint16 x, uint16 y, Image img, int bmw, byte *dst, int sT, int sB); - + void superSprite(DataSprite *dSprite, uint16 x, uint16 y, int img, int bmw, byte *dst, int superTop, int superBottom); + bool clipSprite(uint16 &height, uint16 &pointIndex, uint16 &skipY, DataSprite *dSprite, uint16 &pointX, uint16 &pointY, int img, int bmw, int superTop, int superBottom); + void spriteAligned(DataSprite *dSprite, Image &img, uint16 &skipY, uint16 &pointIndex, uint16 &height, int bmw, byte *dst); + void spriteNotAligned(); /* * [Compression.cpp] Functions from Compression.GS diff --git a/engines/immortal/kernal.cpp b/engines/immortal/kernal.cpp index 044fde879b06..c36e0f0d5bd2 100644 --- a/engines/immortal/kernal.cpp +++ b/engines/immortal/kernal.cpp @@ -55,9 +55,6 @@ void ImmortalEngine::drawUniv() { sortDrawItems(); // Sort said items drawItems(); // Draw the items over the background - // To start constructing the screem, we start with the frame as the base - memcpy(_screenBuff, _window, kScreenSize); - /* copyRectToSurface will apply the screenbuffer to the ScummVM surface. * We want to do 320 bytes per scanline, at location (0,0), with a * size of 320x200. @@ -112,11 +109,14 @@ void ImmortalEngine::addSprites() { // My goodness this routine is gross int tmpNum = _num2DrawItems; for (int i = 0; i < kMaxSprites; i++) { + // If the sprite is active if (_sprites[i]._on == 1) { + // If sprite X is an odd number??? if ((_sprites[i]._X & 1) != 0) { debug("not good! BRK"); return; } + int tmpx = (_sprites[i]._X - kMaxSpriteW) - _myViewPortX; if (tmpx < 0) { if (tmpx + (kMaxSpriteW * 2) < 0) { @@ -136,7 +136,8 @@ void ImmortalEngine::addSprites() { } DataSprite *tempD = _sprites[i]._dSprite; - Image *tempImg = &(_sprites[i]._dSprite->_images[_sprites[i]._image]); + debug("what sprite is this: %d %d %d", i, _sprites[i]._image, _sprites[i]._dSprite->_images.size()); + Image *tempImg = &(tempD->_images[0/*_sprites[i]._image*/]); int sx = ((_sprites[i]._X + tempImg->_deltaX) - tempD->_cenX) - _myViewPortX; int sy = ((_sprites[i]._Y + tempImg->_deltaY) - tempD->_cenY) - _myViewPortY; @@ -144,7 +145,7 @@ void ImmortalEngine::addSprites() { if (sx >= kViewPortW) { continue; } - } else if ((sx + tempImg->_rectX) <= 0) { + } else if ((sx + tempImg->_rectW) <= 0) { continue; } @@ -152,7 +153,7 @@ void ImmortalEngine::addSprites() { if (sy >= kViewPortH) { continue; } - } else if ((sy + tempImg->_rectY) <= 0) { + } else if ((sy + tempImg->_rectH) <= 0) { continue; } @@ -285,7 +286,7 @@ void ImmortalEngine::drawItems() { // If positive, it's a sprite uint16 x = (_sprites[index]._X - _myViewPortX) + kVSX; uint16 y = (_sprites[index]._Y - _myViewPortY) + kVSY; - superSprite(index, x, y, _sprites[index]._dSprite->_images[_sprites[index]._image], kVSBMW, _screenBuff, kMySuperTop, kMySuperBottom); + //superSprite(index, x, y, _sprites[index]._dSprite->_images[0/*_sprites[index]._image*/], kVSBMW, _screenBuff, kMySuperTop, kMySuperBottom); } n++; } while (n != _num2DrawItems); @@ -348,7 +349,7 @@ void ImmortalEngine::printChr(char c) { return; } - superSprite(0, x, y, _dataSprites[kFont]._images[(int) c], kScreenBMW, _screenBuff, kSuperTop, kSuperBottom); + //superSprite(0, x, y, _dataSprites[kFont]._images[(int) c], kScreenBMW, _screenBuff, kSuperTop, kSuperBottom); if ((c == 0x27) || (c == 'T')) { _penX -= 2; // Why is this done twice?? } @@ -536,7 +537,7 @@ void ImmortalEngine::initStoryStatic() { } void ImmortalEngine::kernalAddSprite(uint16 x, uint16 y, SpriteName n, int img, uint16 p) { - Immortal::Utilities::addSprite(_sprites, _viewPortX, _viewPortY, _numSprites, &_dataSprites[n], img, x, y, p); + Utilities::addSprite(_sprites, _viewPortX, _viewPortY, &_numSprites, &_dataSprites[n], img, x, y, p); } void ImmortalEngine::clearSprites() { @@ -644,6 +645,9 @@ void ImmortalEngine::loadWindow() { // Now that the bitmap is processed and stored in a byte buffer, we can close the file f.close(); + // To start constructing the screen, we start with the frame as the base + memcpy(_screenBuff, _window, kScreenSize); + } else { // Should probably give an error or something here debug("oh nose :("); diff --git a/engines/immortal/room.cpp b/engines/immortal/room.cpp index a66573f2e832..94107bc405b7 100644 --- a/engines/immortal/room.cpp +++ b/engines/immortal/room.cpp @@ -73,7 +73,7 @@ void Room::getCell(uint16 &x, uint16 &y) { void Room::setHole() {} void Room::drawContents(uint16 vX, uint16 vY) { - //flameDrawAll(vX, vY); + flameDrawAll(vX, vY); //sparkDrawAll(); //bulletDrawAll(); //genSpriteDrawAll(); diff --git a/engines/immortal/sprite_list.h b/engines/immortal/sprite_list.h index ad0a9af44be3..d80c37fa4aa0 100644 --- a/engines/immortal/sprite_list.h +++ b/engines/immortal/sprite_list.h @@ -24,18 +24,23 @@ namespace Immortal { +// We need a few two-dimentional vectors, and writing them out in full each time is tedious +template using CArray2D = Common::Array>; + struct Image { - uint16 _deltaX; - uint16 _deltaY; - uint16 _rectX; - uint16 _rectY; - byte *_bitmap; + uint16 _deltaX; + uint16 _deltaY; + uint16 _rectW; + uint16 _rectH; +Common::Array _scanWidth; +Common::Array _deltaPos; +CArray2D _bitmap; }; struct DataSprite { - uint16 _cenX; // These are the base center positions - uint16 _cenY; - uint16 _numImages; + uint16 _cenX; // These are the base center positions + uint16 _cenY; + uint16 _numImages; Common::Array _images; }; diff --git a/engines/immortal/sprites.cpp b/engines/immortal/sprites.cpp index 83bec3c409ef..1d471cd63d60 100644 --- a/engines/immortal/sprites.cpp +++ b/engines/immortal/sprites.cpp @@ -21,6 +21,36 @@ #include "immortal/immortal.h" +/* -- How does image construction work -- + * One thing to note about this translation, is that the source + * has a lot of address related stuff mixed in to it. This is + * because 'Super Sprites' could use a screen buffer and sprite + * data from anywhere in memory, including locations that cross + * bank boundaries. This means that you don't just have + * position -> relative position -> screen, you have + * position -> relative position -> relative *address* position -> screen + * With that out of the way, here's what a sprite is: + * A 'Super Sprite' is several layers of structures combined. + * This is both more and less complex in the source. It is structurally + * less complicated, only being seen as a sprite + frame, and a cycle. + * But in reality that comes with complicated indexing and routines + * designed just to get relative indexes that are already in memory. + * Instead, I have chosen to clean up the structure a little bit, + * which in turns makes it slightly more complicated on a top level. + * What we end up with, basically looks like this: + * Cycle (ram/rom) + * | + * Sprite (ram) + * | + * DataSprite (rom) + * | + * Frame (rom) + * | + * Scanline (rom) + * | + * Bitmap (rom) + */ + namespace Immortal { /* @@ -58,22 +88,133 @@ void ImmortalEngine::initDataSprite(Common::SeekableReadStream *f, DataSprite *d for (int i = 0; i < numImages; i++) { Image newImage; - f->seek(index + (i*2)); + f->seek(index + (i * 2)); int ptrFrame = f->readUint16LE(); f->seek(ptrFrame); - newImage._deltaX = f->readUint16LE() << 1; // the ASL might not be required, depending on how I translate the sprite drawing + newImage._deltaX = f->readUint16LE() << 1; // the ASL might not be required, depending on whether the data is actually in bytes or pixels <-- this also might not be used in the game anyway? Lol newImage._deltaY = f->readUint16LE(); - newImage._rectX = f->readUint16LE(); - newImage._rectY = f->readUint16LE(); + newImage._rectW = f->readUint16LE(); + newImage._rectH = f->readUint16LE(); + uint16 next = 0; + for (int j = 0; j < newImage._rectH; j++) { + next = f->readUint16LE(); + if (next >= 0x8000) { + next = uint16 (0 - next); + } else { + debug("HUH"); + } + //debug("First after RectH: %04X", next); + newImage._deltaPos.push_back(next); + next = f->readUint16LE(); + //debug("Second after RectH: %04X", next); + newImage._scanWidth.push_back(next); + Common::Array b; + b.resize(newImage._scanWidth[j]); + for (int k = 0; k < newImage._scanWidth[j]; k++) { + b[k] = f->readByte(); + //debugN("%02X", b[k]); + } + //debug(""); + newImage._bitmap.push_back(b); + } images.push_back(newImage); - // This is probably where we will get the bitmap when I know how to get it } d->_images = images; } +bool ImmortalEngine::clipSprite(uint16 &height, uint16 &pointIndex, uint16 &skipY, DataSprite *dSprite, uint16 &pointX, uint16 &pointY, int img, int bmw, int superTop, int superBottom) { + // This bit is to get the base index into the screen buffer, unless that's already been done, which is _lastPoint + if ((pointY != _lastY) || (bmw != _lastBMW)) { + _lastBMW = bmw; + _lastY = pointY; + if (pointY >= 0) { + _lastPoint = pointY * bmw; + } else { + pointY = !(pointY); + _lastPoint = pointY * bmw; + } + } + + pointIndex = _lastPoint; + + // Now we begin clipping, starting with totally offscreen + // We do this by checking if the sprite is above the top of the screen, or below the bottom of it + if (pointY > superBottom) { + return true; + + } else if ((height + pointY) < superTop) { + return true; + + // Now we actually clip top/bottom parts + } else { + + // Starting with checking if any of the sprite is under the bottom of the screen + if ((height + pointY) >= superBottom) { + height = superBottom - pointY; + } + + // Next we get the difference of overlap from the sprite if it is above the top + if ((superTop - pointY) >= 0) { + skipY = (superTop - pointY); + } + + // The image is clipped, time to move the index to the sprite's first scanline base position + pointIndex += (pointX / 2) + dSprite->_images[img]._rectW; + } + return false; +} + +void ImmortalEngine::spriteAligned(DataSprite *dSprite, Image &img, uint16 &skipY, uint16 &pointIndex, uint16 &height, int bmw, byte *dst) { + //debug("draw the sprite"); + + //debug("%d, %d, %d", height, skipY, pointIndex); + + byte pixel; + int pos; + debug("SPRITE START ------"); + for (int y = skipY; y < height; y++) { + for (int x = 0; x < img._scanWidth[y]; x ++) { + pos = ((pointIndex + (y * kResH)) - img._deltaPos[y]) + (x * 2); + pixel = img._bitmap[y][x]; + _screenBuff[pos] = (pixel & kMask8High) >> 4; + _screenBuff[pos + 1] = pixel & kMask8Low; + } + } + debug("SPRITE END -------"); +} + +void ImmortalEngine::spriteNotAligned() { -void ImmortalEngine::superSprite(int s, uint16 x, uint16 y, Image img, int bmw, byte *dst, int sT, int sB) {} +} + +void ImmortalEngine::superSprite(DataSprite *dSprite, uint16 pointX, uint16 pointY, int img, int bmw, byte *dst, int superTop, int superBottom) { + // Main image construction routine + + uint16 cenX = dSprite->_cenX; + uint16 cenY = dSprite->_cenY; + uint16 dY = dSprite->_images[img]._deltaY; + uint16 height = dSprite->_images[img]._rectH; + + uint16 skipY = 0; + uint16 pointIndex = 0; // This is screen and screen + 2 in the source + + pointX -= cenX; + pointY -= cenY; + pointY += dY; + + // Normally I would just make the return from clip be reversed, but the idea is that the return would be 'offscreen == true' + if (!(clipSprite(height, pointIndex, skipY, dSprite, pointX, pointY, img, bmw, superTop, superBottom))) { + // Alignment is determined by whether the x position of the point is positive or negative + if (pointX >= 0x8000) { + spriteAligned(dSprite, dSprite->_images[img], skipY, pointIndex, height, bmw, dst); + + } else { + spriteAligned(dSprite, dSprite->_images[img], skipY, pointIndex, height, bmw, dst); + } + } + +} } // namespace Immortal @@ -94,6 +235,20 @@ void ImmortalEngine::superSprite(int s, uint16 x, uint16 y, Image img, int bmw, + + + + + + + + + + + + + + diff --git a/engines/immortal/story.h b/engines/immortal/story.h index 0fb02e69ac24..eeea16426e53 100644 --- a/engines/immortal/story.h +++ b/engines/immortal/story.h @@ -30,9 +30,6 @@ namespace Immortal { -// We need a few two-dimentional vectors, and writing them out in full each time is tedious -template using CArray2D = Common::Array>; - // These maximum numbers aren't really needed, because most of these are vectors and have .size() enum StoryMaxes { kMaxRooms = 16, diff --git a/engines/immortal/univ.cpp b/engines/immortal/univ.cpp index 91629b242533..aef1aa889b6a 100644 --- a/engines/immortal/univ.cpp +++ b/engines/immortal/univ.cpp @@ -23,8 +23,9 @@ namespace Immortal { -void Room::univAddSprite(uint16 vX, uint16 vY, int nS, uint16 x, uint16 y, SpriteName n, int img, uint16 p) { - //Immortal::Utilities::addSprite(_sprites, vX, vY, nS, &_dataSprites[n], img, x, y, p); +void Room::univAddSprite(uint16 vX, uint16 vY, uint16 x, uint16 y, SpriteName n, int img, uint16 p) { + debug("%d %d %d", *_numSprites, n, img); + //Utilities::addSprite(_sprites, vX, vY, _numSprites, &_dataSprites[n], img, x, y, p); } } // namespace immortal \ No newline at end of file From b27988471cda4bb7427e18335ad36ca63b4c9b76 Mon Sep 17 00:00:00 2001 From: Quote58 Date: Tue, 6 Sep 2022 17:17:39 -0400 Subject: [PATCH 344/412] IMMORTAL: Implement utilities::inside() and insideRect() --- engines/immortal/utilities.cpp | 62 ++++++++++++++++++++++++++++++++-- engines/immortal/utilities.h | 4 +-- 2 files changed, 61 insertions(+), 5 deletions(-) diff --git a/engines/immortal/utilities.cpp b/engines/immortal/utilities.cpp index 21ca9e138108..4719a189eb02 100644 --- a/engines/immortal/utilities.cpp +++ b/engines/immortal/utilities.cpp @@ -35,10 +35,66 @@ void Utilities::delay8(int j) { // 1/8 jiffies are 7.02ms g_system->delayMillis(j * 7); } -bool Utilities::inside(int x1, int y1, int a, int x2, int y2) { - return false; +bool Utilities::inside(uint8 dist, uint8 cenX, uint8 cenY, uint8 pointX, uint8 pointY) { + // you can't be within 0 distance of something + if (dist == 0) { + return false; + } + + // we want the negative distance because this is a rectangle all the way around a point + uint8 negDist = ((dist ^ 0xFF) + 1) + 1; + + // First is the X, so we get delta X from the points + uint8 dX = cenX - pointX; + if (dX < 0x80) { + // Our point is beyond the other point + if (dX >= dist) { + // And it is further than point + distance, so it's not useable + return false; + } + + } else if (dX >= negDist) { + // If the negative delta X is *greater* than the negative distance, that means we're not far *enough* in the X + return false; + } + + // Exact same system here but with the Y positions instead + uint8 dY = cenY - pointY; + if (dY < 0x80) { + if (dY >= dist) { + return false; + } + + } else if (dY >= negDist) { + return false; + } + + // If all conditions are met, we are within the distance of the point + return true; } -bool Utilities::insideRect(int x, int y, int r) { + +bool Utilities::insideRect(uint8 rectX, uint8 rectY, uint8 w, uint8 h, uint8 pointX, uint8 pointY) { + /* Very simple comapred to inside, we simply check + * first if width and height are >0, to make sure + * the rectangle has a size, and then we see if + * the point is between the point X,Y and the + * point X,Y + the width,height of the rect. + * This is done by grabbing the delta X,Y and + * making sure it is not negative. + */ + if ((w | h) == 0) { + return false; + } + + uint8 dX = pointX - rectX; + uint8 dY = pointY - rectY; + + if ((dX < 0x80) && (dX < w)) { + if ((dY < 0x80) && (dY < h)) { + return true; + } + } + return false; } diff --git a/engines/immortal/utilities.h b/engines/immortal/utilities.h index 0c8304f22f21..9ddd18448848 100644 --- a/engines/immortal/utilities.h +++ b/engines/immortal/utilities.h @@ -78,8 +78,8 @@ namespace Utilities { void delay(int j); // Delay engine by j jiffies (from driver originally, but makes more sense grouped with misc) void delay4(int j); // || /4 void delay8(int j); // || /8 -bool inside(int x1, int y1, int a, int x2, int y2); -bool insideRect(int x, int y, int r); +bool inside(uint8 dist, uint8 centX, uint8 centY, uint8 pointX, uint8 pointY); +bool insideRect(uint8 rectX, uint8 rectY, uint8 w, uint8 h, uint8 pointX, uint8 pointY); void addSprite(Sprite *sprites, uint16 vpX, uint16 vpY, int *num, DataSprite *d, int img, uint16 x, uint16 y, uint16 p); }; // namespace Util From 8d9994ba56a61854af6aff98876683761299e9e8 Mon Sep 17 00:00:00 2001 From: Quote58 Date: Tue, 6 Sep 2022 19:18:59 -0400 Subject: [PATCH 345/412] IMMORTAL: Sprite drawing preliminarily implemented --- engines/immortal/immortal.cpp | 4 +-- engines/immortal/immortal.h | 8 +++--- engines/immortal/sprites.cpp | 53 ++++++++++++++++++++++------------- 3 files changed, 40 insertions(+), 25 deletions(-) diff --git a/engines/immortal/immortal.cpp b/engines/immortal/immortal.cpp index e6b638da1d73..fd55add4e92f 100644 --- a/engines/immortal/immortal.cpp +++ b/engines/immortal/immortal.cpp @@ -189,8 +189,8 @@ Common::Error ImmortalEngine::run() { //logic(); pollKeys(); if (logicFreeze() == 0) { - DataSprite *d = &_dataSprites[kFont]; - superSprite(d, 0xC0, 0x50, 0, 0, _screenBuff, kSuperTop, kMySuperBottom); + DataSprite *d = &_dataSprites[kGoblin2]; + superSprite(d, 20, 0xA0, 4, kVSBMW, _screenBuff, kSuperTop, kMySuperBottom); drawUniv(); pollKeys(); fixColors(); diff --git a/engines/immortal/immortal.h b/engines/immortal/immortal.h index 703b97478e4d..02b2d5e45de7 100644 --- a/engines/immortal/immortal.h +++ b/engines/immortal/immortal.h @@ -232,7 +232,7 @@ class ImmortalEngine : public Engine { const int kSpriteDY = 32; const int kVSX = kMaxSpriteW; const int kVSY = kSpriteDY; - const int kVSBMW = (kViewPortW + kMaxSpriteW) / 2; + const uint16 kVSBMW = (kViewPortW + kMaxSpriteW) / 2; const int kVSLen = kVSBMW * (kViewPortH + kMaxSpriteH); const int kVSDY = 32; // difference from top of screen to top of viewport in the virtual screen buffer const int kMySuperBottom = kVSDY + kViewPortH; @@ -584,9 +584,9 @@ GenericSprite _genSprites[6]; void initDataSprite(Common::SeekableReadStream *f, DataSprite *d, int index, uint16 cenX, uint16 cenY); // Initializes the data sprite // Main - void superSprite(DataSprite *dSprite, uint16 x, uint16 y, int img, int bmw, byte *dst, int superTop, int superBottom); - bool clipSprite(uint16 &height, uint16 &pointIndex, uint16 &skipY, DataSprite *dSprite, uint16 &pointX, uint16 &pointY, int img, int bmw, int superTop, int superBottom); - void spriteAligned(DataSprite *dSprite, Image &img, uint16 &skipY, uint16 &pointIndex, uint16 &height, int bmw, byte *dst); + void superSprite(DataSprite *dSprite, uint16 x, uint16 y, int img, uint16 bmw, byte *dst, int superTop, int superBottom); + bool clipSprite(uint16 &height, uint16 &pointIndex, uint16 &skipY, DataSprite *dSprite, uint16 &pointX, uint16 &pointY, int img, uint16 bmw, int superTop, int superBottom); + void spriteAligned(DataSprite *dSprite, Image &img, uint16 &skipY, uint16 &pointIndex, uint16 &height, uint16 bmw, byte *dst); void spriteNotAligned(); /* diff --git a/engines/immortal/sprites.cpp b/engines/immortal/sprites.cpp index 1d471cd63d60..45e442eb3f42 100644 --- a/engines/immortal/sprites.cpp +++ b/engines/immortal/sprites.cpp @@ -98,11 +98,6 @@ void ImmortalEngine::initDataSprite(Common::SeekableReadStream *f, DataSprite *d uint16 next = 0; for (int j = 0; j < newImage._rectH; j++) { next = f->readUint16LE(); - if (next >= 0x8000) { - next = uint16 (0 - next); - } else { - debug("HUH"); - } //debug("First after RectH: %04X", next); newImage._deltaPos.push_back(next); next = f->readUint16LE(); @@ -123,20 +118,23 @@ void ImmortalEngine::initDataSprite(Common::SeekableReadStream *f, DataSprite *d d->_images = images; } -bool ImmortalEngine::clipSprite(uint16 &height, uint16 &pointIndex, uint16 &skipY, DataSprite *dSprite, uint16 &pointX, uint16 &pointY, int img, int bmw, int superTop, int superBottom) { +bool ImmortalEngine::clipSprite(uint16 &height, uint16 &pointIndex, uint16 &skipY, DataSprite *dSprite, uint16 &pointX, uint16 &pointY, int img, uint16 bmw, int superTop, int superBottom) { // This bit is to get the base index into the screen buffer, unless that's already been done, which is _lastPoint if ((pointY != _lastY) || (bmw != _lastBMW)) { _lastBMW = bmw; _lastY = pointY; - if (pointY >= 0) { + if (pointY < 0x80) { _lastPoint = pointY * bmw; } else { - pointY = !(pointY); + pointY = (pointY ^ 0xFF) + 1; _lastPoint = pointY * bmw; + _lastPoint = 0 - _lastPoint; } } pointIndex = _lastPoint; + return false; + // Now we begin clipping, starting with totally offscreen // We do this by checking if the sprite is above the top of the screen, or below the bottom of it @@ -155,7 +153,7 @@ bool ImmortalEngine::clipSprite(uint16 &height, uint16 &pointIndex, uint16 &skip } // Next we get the difference of overlap from the sprite if it is above the top - if ((superTop - pointY) >= 0) { + if ((superTop - pointY) < 0x8000) { skipY = (superTop - pointY); } @@ -165,20 +163,37 @@ bool ImmortalEngine::clipSprite(uint16 &height, uint16 &pointIndex, uint16 &skip return false; } -void ImmortalEngine::spriteAligned(DataSprite *dSprite, Image &img, uint16 &skipY, uint16 &pointIndex, uint16 &height, int bmw, byte *dst) { +void ImmortalEngine::spriteAligned(DataSprite *dSprite, Image &img, uint16 &skipY, uint16 &pointIndex, uint16 &height, uint16 bmw, byte *dst) { //debug("draw the sprite"); - //debug("%d, %d, %d", height, skipY, pointIndex); + debug("%d, %d, %04X", height, skipY, pointIndex); byte pixel; - int pos; + // For debug currently, align to the word by default + pointIndex &= 0xFFFE; + + // Position is weird + pointIndex += 50; + debug("SPRITE START ------"); - for (int y = skipY; y < height; y++) { - for (int x = 0; x < img._scanWidth[y]; x ++) { - pos = ((pointIndex + (y * kResH)) - img._deltaPos[y]) + (x * 2); - pixel = img._bitmap[y][x]; - _screenBuff[pos] = (pixel & kMask8High) >> 4; - _screenBuff[pos + 1] = pixel & kMask8Low; + for (int y = 0; y < height; y++, pointIndex += (bmw * 2)) { + + //debug("%04X, %04X ", pointIndex, img._deltaPos[y]); + + if (img._deltaPos[y] < 0x8000) { + pointIndex += (img._deltaPos[y] * 2); + } + else { + pointIndex -= ((0 - img._deltaPos[y]) * 2); + } + + for (int x = 0; x < img._scanWidth[y]; x++, pointIndex += 2) { + + //if (y > skipY) { + pixel = img._bitmap[y][x]; + _screenBuff[pointIndex] = (pixel & kMask8High) >> 4; + _screenBuff[pointIndex + 1] = pixel & kMask8Low; + //} } } debug("SPRITE END -------"); @@ -188,7 +203,7 @@ void ImmortalEngine::spriteNotAligned() { } -void ImmortalEngine::superSprite(DataSprite *dSprite, uint16 pointX, uint16 pointY, int img, int bmw, byte *dst, int superTop, int superBottom) { +void ImmortalEngine::superSprite(DataSprite *dSprite, uint16 pointX, uint16 pointY, int img, uint16 bmw, byte *dst, int superTop, int superBottom) { // Main image construction routine uint16 cenX = dSprite->_cenX; From d8944244a1ea9610544a5cfb58b8b7cda946f132 Mon Sep 17 00:00:00 2001 From: Quote58 Date: Tue, 13 Sep 2022 03:19:29 -0400 Subject: [PATCH 346/412] IMMORTAL: Implement sprite drawing through superSprites() --- engines/immortal/immortal.h | 50 ++++++++--------- engines/immortal/sprites.cpp | 106 ++++++++++++++++++++--------------- 2 files changed, 85 insertions(+), 71 deletions(-) diff --git a/engines/immortal/immortal.h b/engines/immortal/immortal.h index 02b2d5e45de7..fe20b7cfa183 100644 --- a/engines/immortal/immortal.h +++ b/engines/immortal/immortal.h @@ -189,21 +189,21 @@ class ImmortalEngine : public Engine { const int kScreenH__ = 128; // ??? const int kViewPortW = 256; const int kViewPortH = 128; - const int kScreenSize = (kResH * kResV) * 2; // The size of the screen buffer is 320x200 - const int kScreenLeft = 32; - const int kScreenTop = 20; + const int kScreenSize = (kResH * kResV) * 2; // The size of the screen buffer is (320x200) * 2 byte words + const uint16 kScreenLeft = 32; + const uint16 kScreenTop = 20; const int kTextLeft = 8; const int kTextTop = 4; const int kGaugeX = 0; const int kGaugeY = -13; // ??? - const int kScreenBMW = 160; // Screen BitMap Width? + const uint16 kScreenBMW = 160; // Screen BitMap Width? const uint16 kChrW = 64; const uint16 kChrH = 32; const uint16 kChrH2 = kChrH * 2; const uint16 kChrH3 = kChrH * 3; - const int kChrLen = (kChrW / 2) * kChrH; - const int kChrBMW = kChrW / 2; - const int kLCutaway = 4; + const uint16 kChrLen = (kChrW / 2) * kChrH; + const uint16 kChrBMW = kChrW / 2; + const uint16 kLCutaway = 4; const uint16 kChrDy[19] = {kChr0, kChrH, kChrH2, kChrH, kChrH2, kChrH2, kChrH, kChrH2, kChrH2, kChr0, @@ -227,22 +227,22 @@ class ImmortalEngine : public Engine { const int kPaletteOffset = 21205; // This is the byte position of the palette data in the disk // Sprite constants - const int kMaxSpriteW = 64; - const int kMaxSpriteH = 64; - const int kSpriteDY = 32; - const int kVSX = kMaxSpriteW; - const int kVSY = kSpriteDY; + const uint16 kMaxSpriteW = 64; + const uint16 kMaxSpriteH = 64; + const uint16 kSpriteDY = 32; + const uint16 kVSX = kMaxSpriteW; + const uint16 kVSY = kSpriteDY; const uint16 kVSBMW = (kViewPortW + kMaxSpriteW) / 2; - const int kVSLen = kVSBMW * (kViewPortH + kMaxSpriteH); - const int kVSDY = 32; // difference from top of screen to top of viewport in the virtual screen buffer - const int kMySuperBottom = kVSDY + kViewPortH; - const int kSuperBottom = 200; - const int kMySuperTop = kVSDY; - const int kSuperTop = 0; - const int kViewPortSpX = 32; - const int kViewPortSpY = 0; - const int kWizardX = 28; // Common sprite center for some reason - const int kWizardY = 37; + const uint16 kVSLen = kVSBMW * (kViewPortH + kMaxSpriteH); + const uint16 kVSDY = 32; // difference from top of screen to top of viewport in the virtual screen buffer + const uint16 kMySuperBottom = kVSDY + kViewPortH; + const uint16 kSuperBottom = 200; + const uint16 kMySuperTop = kVSDY; + const uint16 kSuperTop = 0; + const uint16 kViewPortSpX = 32; + const uint16 kViewPortSpY = 0; + const uint16 kWizardX = 28; // Common sprite center for some reason + const uint16 kWizardY = 37; // Asset constants const char kGaugeOn = 1; // On uses the sprite at index 1 of the font spriteset @@ -409,6 +409,7 @@ GenericSprite _genSprites[6]; void addSprites(); // Add all active sprites that are in the viewport, into a list that will be sorted by priority void sortDrawItems(); // Sort said items void drawItems(); // Draw the items over the background + void setPen(uint16 penX, uint16 penY); // Sets the 'pen' x and y positions, including making y negative if above a certain point // Music void toggleSound(); // Actually pauses the sound, doesn't just turn it off/mute @@ -584,10 +585,9 @@ GenericSprite _genSprites[6]; void initDataSprite(Common::SeekableReadStream *f, DataSprite *d, int index, uint16 cenX, uint16 cenY); // Initializes the data sprite // Main - void superSprite(DataSprite *dSprite, uint16 x, uint16 y, int img, uint16 bmw, byte *dst, int superTop, int superBottom); - bool clipSprite(uint16 &height, uint16 &pointIndex, uint16 &skipY, DataSprite *dSprite, uint16 &pointX, uint16 &pointY, int img, uint16 bmw, int superTop, int superBottom); + void superSprite(DataSprite *dSprite, uint16 x, uint16 y, int img, uint16 bmw, byte *dst, uint16 superTop, uint16 superBottom); + bool clipSprite(uint16 &height, uint16 &pointIndex, uint16 &skipY, DataSprite *dSprite, uint16 &pointX, uint16 &pointY, int img, uint16 bmw, uint16 superTop, uint16 superBottom); void spriteAligned(DataSprite *dSprite, Image &img, uint16 &skipY, uint16 &pointIndex, uint16 &height, uint16 bmw, byte *dst); - void spriteNotAligned(); /* * [Compression.cpp] Functions from Compression.GS diff --git a/engines/immortal/sprites.cpp b/engines/immortal/sprites.cpp index 45e442eb3f42..3a982a916993 100644 --- a/engines/immortal/sprites.cpp +++ b/engines/immortal/sprites.cpp @@ -76,7 +76,7 @@ void ImmortalEngine::initDataSprite(Common::SeekableReadStream *f, DataSprite *d uint16 numImages = f->readUint16LE(); d->_numImages = numImages; - //debug("Number of Frames: %d", numFrames); + //debug("Number of Frames: %d", numImages); // Only here for dragon, but just in case, it's a high number so it should catch others if (numImages >= 0x0200) { @@ -118,92 +118,110 @@ void ImmortalEngine::initDataSprite(Common::SeekableReadStream *f, DataSprite *d d->_images = images; } -bool ImmortalEngine::clipSprite(uint16 &height, uint16 &pointIndex, uint16 &skipY, DataSprite *dSprite, uint16 &pointX, uint16 &pointY, int img, uint16 bmw, int superTop, int superBottom) { +bool ImmortalEngine::clipSprite(uint16 &height, uint16 &pointIndex, uint16 &skipY, DataSprite *dSprite, uint16 &pointX, uint16 &pointY, int img, uint16 bmw, uint16 superTop, uint16 superBottom) { + /* Something important to note here: + * In the source, bmw is not *2, and pointX is /2. However, the source + * was using a buffer of 2 pixels per byte. In ScummVM, the screen buffer + * is 1 pixel per byte. This means some calculations are slightly different. + */ + // This bit is to get the base index into the screen buffer, unless that's already been done, which is _lastPoint if ((pointY != _lastY) || (bmw != _lastBMW)) { _lastBMW = bmw; _lastY = pointY; - if (pointY < 0x80) { - _lastPoint = pointY * bmw; + if (pointY < kMaskNeg) { + // The source does not double the bmw here to get the bytes, why not? + _lastPoint = pointY * (bmw * 2); } else { - pointY = (pointY ^ 0xFF) + 1; - _lastPoint = pointY * bmw; + // Screen wrapping?? + uint16 temp = (0 - pointY) + 1; + _lastPoint = temp * bmw; _lastPoint = 0 - _lastPoint; } } pointIndex = _lastPoint; - return false; - // Now we begin clipping, starting with totally offscreen - // We do this by checking if the sprite is above the top of the screen, or below the bottom of it if (pointY > superBottom) { return true; - } else if ((height + pointY) < superTop) { + } else if ((pointY + height) < superTop) { return true; - // Now we actually clip top/bottom parts + /* The actual clipping is pretty simple: + * Lower height = stop drawing the sprite early. Higher SkipY = start drawing the sprite late + * So we just determine the delta for each based on superTop and superBottom + */ } else { // Starting with checking if any of the sprite is under the bottom of the screen - if ((height + pointY) >= superBottom) { + if ((pointY + height) >= superBottom) { height = superBottom - pointY; } // Next we get the difference of overlap from the sprite if it is above the top - if ((superTop - pointY) < 0x8000) { + if (uint16((superTop - pointY)) < kMaskNeg) { skipY = (superTop - pointY); } // The image is clipped, time to move the index to the sprite's first scanline base position - pointIndex += (pointX / 2) + dSprite->_images[img]._rectW; + pointIndex += (pointX) + dSprite->_images[img]._rectW; } return false; } void ImmortalEngine::spriteAligned(DataSprite *dSprite, Image &img, uint16 &skipY, uint16 &pointIndex, uint16 &height, uint16 bmw, byte *dst) { - //debug("draw the sprite"); - - debug("%d, %d, %04X", height, skipY, pointIndex); - - byte pixel; - // For debug currently, align to the word by default - pointIndex &= 0xFFFE; - - // Position is weird - pointIndex += 50; - - debug("SPRITE START ------"); + /* This is an approximation of the sprite drawing system in the source. + * It is an approximation because the source needed to do some things + * that aren't relevant anymore, and it had some....creative solutions. + * For example, transparency was handled with a 256 byte table of masks + * that was indexed by the pixel itself, and used to find what nyble needed + * to be masked. However we are using a slightly different kind of screen buffer, + * and so I chose a more traditional method. Likewise, alignement was + * relevant for the source, but is not relevant here (thankfully, considering + * how confusing sprite drawing is when not an even position). + */ + byte pixel1 = 0; + byte pixel2 = 0; + + // For every scanline before height for (int y = 0; y < height; y++, pointIndex += (bmw * 2)) { - //debug("%04X, %04X ", pointIndex, img._deltaPos[y]); - - if (img._deltaPos[y] < 0x8000) { + // We increase the position by one screen width + if (img._deltaPos[y] < kMaskNeg) { pointIndex += (img._deltaPos[y] * 2); } + + // And if the delta X for the line is positive, we add it. If negative we subtract else { pointIndex -= ((0 - img._deltaPos[y]) * 2); } + // For every pixel in the scanline for (int x = 0; x < img._scanWidth[y]; x++, pointIndex += 2) { + // SkipY defines the lines we don't draw because they are clipped + if (y >= skipY) { + + // For handling transparency, I chose to simply check if the pixel is 0, + // as that is the transparent colour + pixel1 = (img._bitmap[y][x] & kMask8High) >> 4; + pixel2 = (img._bitmap[y][x] & kMask8Low); + + if (pixel1 != 0) { + _screenBuff[pointIndex] = pixel1; + } + + if (pixel2 != 0) { + _screenBuff[pointIndex + 1] = pixel2; + } - //if (y > skipY) { - pixel = img._bitmap[y][x]; - _screenBuff[pointIndex] = (pixel & kMask8High) >> 4; - _screenBuff[pointIndex + 1] = pixel & kMask8Low; - //} + } } } - debug("SPRITE END -------"); } -void ImmortalEngine::spriteNotAligned() { - -} - -void ImmortalEngine::superSprite(DataSprite *dSprite, uint16 pointX, uint16 pointY, int img, uint16 bmw, byte *dst, int superTop, int superBottom) { +void ImmortalEngine::superSprite(DataSprite *dSprite, uint16 pointX, uint16 pointY, int img, uint16 bmw, byte *dst, uint16 superTop, uint16 superBottom) { // Main image construction routine uint16 cenX = dSprite->_cenX; @@ -220,13 +238,9 @@ void ImmortalEngine::superSprite(DataSprite *dSprite, uint16 pointX, uint16 poin // Normally I would just make the return from clip be reversed, but the idea is that the return would be 'offscreen == true' if (!(clipSprite(height, pointIndex, skipY, dSprite, pointX, pointY, img, bmw, superTop, superBottom))) { - // Alignment is determined by whether the x position of the point is positive or negative - if (pointX >= 0x8000) { - spriteAligned(dSprite, dSprite->_images[img], skipY, pointIndex, height, bmw, dst); - } else { - spriteAligned(dSprite, dSprite->_images[img], skipY, pointIndex, height, bmw, dst); - } + // Alignment was a factor in the assembly because it was essentially 2 pixels per byte. However ScummVM is 1 pixel per byte + spriteAligned(dSprite, dSprite->_images[img], skipY, pointIndex, height, bmw, dst); } } From 0467dbdb78162944f178ceebff169b9b4936b67d Mon Sep 17 00:00:00 2001 From: Quote58 Date: Tue, 13 Sep 2022 03:36:56 -0400 Subject: [PATCH 347/412] IMMORTAL: Enable sprite drawing in printChr() and drawGauge() --- engines/immortal/kernal.cpp | 10 +++++----- engines/immortal/logic.cpp | 20 ++++++++++++++++---- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/engines/immortal/kernal.cpp b/engines/immortal/kernal.cpp index c36e0f0d5bd2..9344ac283cf9 100644 --- a/engines/immortal/kernal.cpp +++ b/engines/immortal/kernal.cpp @@ -48,6 +48,9 @@ void ImmortalEngine::drawUniv() { _myUnivPointX = !(_myViewPortX & (kChrW - 1)) + kViewPortSpX; _myUnivPointY = !(_myViewPortY & (kChrH - 1)) + kViewPortSpY; + // To start constructing the screen, we start with the frame as the base + memcpy(_screenBuff, _window, kScreenSize); + makeMyCNM(); drawBGRND(); // Draw floor parts of leftmask rightmask and maskers addRows(); // Add rows to drawitem array @@ -286,7 +289,7 @@ void ImmortalEngine::drawItems() { // If positive, it's a sprite uint16 x = (_sprites[index]._X - _myViewPortX) + kVSX; uint16 y = (_sprites[index]._Y - _myViewPortY) + kVSY; - //superSprite(index, x, y, _sprites[index]._dSprite->_images[0/*_sprites[index]._image*/], kVSBMW, _screenBuff, kMySuperTop, kMySuperBottom); + superSprite(_sprites[index]._dSprite, x, y, _sprites[index]._image, kVSBMW, _screenBuff, kMySuperTop, kMySuperBottom); } n++; } while (n != _num2DrawItems); @@ -349,7 +352,7 @@ void ImmortalEngine::printChr(char c) { return; } - //superSprite(0, x, y, _dataSprites[kFont]._images[(int) c], kScreenBMW, _screenBuff, kSuperTop, kSuperBottom); + superSprite(&_dataSprites[kFont], x, y, (int) c, kScreenBMW, _screenBuff, kSuperTop, kSuperBottom); if ((c == 0x27) || (c == 'T')) { _penX -= 2; // Why is this done twice?? } @@ -645,9 +648,6 @@ void ImmortalEngine::loadWindow() { // Now that the bitmap is processed and stored in a byte buffer, we can close the file f.close(); - // To start constructing the screen, we start with the frame as the base - memcpy(_screenBuff, _window, kScreenSize); - } else { // Should probably give an error or something here debug("oh nose :("); diff --git a/engines/immortal/logic.cpp b/engines/immortal/logic.cpp index 2379914705e9..97319375a066 100644 --- a/engines/immortal/logic.cpp +++ b/engines/immortal/logic.cpp @@ -201,6 +201,18 @@ void ImmortalEngine::doSingleStep() { } } +void ImmortalEngine::setPen(uint16 penX, uint16 penY) { + _penX = penX & kMaskLow; + // Is this screen wrap? + if ((penY & kMaskLow) < 200) { + _penY = penY & kMaskLow; + } + + else { + _penY = penY | kMaskHigh; + } +} + void ImmortalEngine::updateHitGauge() { /* This HUD (essentially) drawing routine is a bit weird because * the game was originally meant to have multiple player characters @@ -211,7 +223,7 @@ void ImmortalEngine::updateHitGauge() { * probably just check a global 'health' variable instead. */ //int hits = _rooms[_currentRoom]._monsters[kPlayerID]._getHits(); - int hits = 0; + int hits = 15; if (hits != _lastGauge) { // Update the mirror value if the health has changed since last frame _lastGauge = hits; @@ -237,8 +249,9 @@ void ImmortalEngine::drawGauge(int h) { * the index of the chr for the other icons. */ int r = 16 - h; - _penX = kGaugeX; - _penY = kGaugeY; + setPen(kGaugeX, kGaugeY); + // Temporary x value, until it's clear why printchr is designed to add 8 pixels *before* drawing the char + _penX = 0xFFF0; h--; if (h >= 0) { // This could be written as a regular for loop, but the game thinks of start/stop as different from on @@ -248,7 +261,6 @@ void ImmortalEngine::drawGauge(int h) { if (h == 0) { // Redundant code is redundant printChr(kGaugeStop); - } else { printChr(kGaugeOn); } From a2bd437c5e10e0d1fa19e86347d0725c3bcb7da7 Mon Sep 17 00:00:00 2001 From: Quote58 Date: Thu, 22 Sep 2022 03:23:32 -0400 Subject: [PATCH 348/412] IMMORTAL: addSprite() moved out of utilities --- engines/immortal/utilities.cpp | 39 +++++++--------------------------- engines/immortal/utilities.h | 4 +++- 2 files changed, 11 insertions(+), 32 deletions(-) diff --git a/engines/immortal/utilities.cpp b/engines/immortal/utilities.cpp index 4719a189eb02..50957dede5e1 100644 --- a/engines/immortal/utilities.cpp +++ b/engines/immortal/utilities.cpp @@ -23,6 +23,14 @@ namespace Immortal { +/* + * + * ----- ----- + * ----- General Use ----- + * ----- ----- + * + */ + void Utilities::delay(int j) { // Delay is measured in jiffies, which are 56.17ms g_system->delayMillis(j * 56); } @@ -98,35 +106,4 @@ bool Utilities::insideRect(uint8 rectX, uint8 rectY, uint8 w, uint8 h, uint8 poi return false; } -void Utilities::addSprite(Sprite *sprites, uint16 vpX, uint16 vpY, int *num, DataSprite *d, int img, uint16 x, uint16 y, uint16 p) { - debug("adding sprite..."); - if (*num != kMaxSprites) { - if (x >= (kResH + kMaxSpriteLeft)) { - x |= kMaskHigh; // Make it negative - } - - sprites[*num]._X = (x << 1) + vpX; - - if (y >= (kMaxSpriteAbove + kResV)) { - y |= kMaskHigh; - } - - sprites[*num]._Y = (y << 1) + vpY; - - if (p >= 0x80) { - p |= kMaskHigh; - } - - sprites[*num]._priority = ((p + y) ^ 0xFFFF) + 1; - - sprites[*num]._image = img; - sprites[*num]._dSprite = d; - sprites[*num]._on = 1; - *num += 1; - debug("sprite added"); - } else { - debug("Max sprites reached beeeeeep!!"); - } -} - }; // namespace Immortal \ No newline at end of file diff --git a/engines/immortal/utilities.h b/engines/immortal/utilities.h index 9ddd18448848..c40904d8aa60 100644 --- a/engines/immortal/utilities.h +++ b/engines/immortal/utilities.h @@ -25,7 +25,9 @@ #include "common/debug.h" #include "common/debug-channels.h" #include "common/system.h" + #include "immortal/sprite_list.h" +#include "immortal/definitions.h" namespace Immortal { @@ -75,12 +77,12 @@ enum Screen { // These are constants t namespace Utilities { +// Other void delay(int j); // Delay engine by j jiffies (from driver originally, but makes more sense grouped with misc) void delay4(int j); // || /4 void delay8(int j); // || /8 bool inside(uint8 dist, uint8 centX, uint8 centY, uint8 pointX, uint8 pointY); bool insideRect(uint8 rectX, uint8 rectY, uint8 w, uint8 h, uint8 pointX, uint8 pointY); -void addSprite(Sprite *sprites, uint16 vpX, uint16 vpY, int *num, DataSprite *d, int img, uint16 x, uint16 y, uint16 p); }; // namespace Util From cdf322b93a71883b5ddb03ffa299184733d09d13 Mon Sep 17 00:00:00 2001 From: Quote58 Date: Thu, 22 Sep 2022 03:25:20 -0400 Subject: [PATCH 349/412] IMMORTAL: BMW is assumed to be in bytes and is converted to pixels for drawing --- engines/immortal/sprites.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/engines/immortal/sprites.cpp b/engines/immortal/sprites.cpp index 3a982a916993..31969a8e0a1d 100644 --- a/engines/immortal/sprites.cpp +++ b/engines/immortal/sprites.cpp @@ -98,18 +98,14 @@ void ImmortalEngine::initDataSprite(Common::SeekableReadStream *f, DataSprite *d uint16 next = 0; for (int j = 0; j < newImage._rectH; j++) { next = f->readUint16LE(); - //debug("First after RectH: %04X", next); newImage._deltaPos.push_back(next); next = f->readUint16LE(); - //debug("Second after RectH: %04X", next); newImage._scanWidth.push_back(next); Common::Array b; b.resize(newImage._scanWidth[j]); for (int k = 0; k < newImage._scanWidth[j]; k++) { b[k] = f->readByte(); - //debugN("%02X", b[k]); } - //debug(""); newImage._bitmap.push_back(b); } images.push_back(newImage); @@ -130,8 +126,8 @@ bool ImmortalEngine::clipSprite(uint16 &height, uint16 &pointIndex, uint16 &skip _lastBMW = bmw; _lastY = pointY; if (pointY < kMaskNeg) { - // The source does not double the bmw here to get the bytes, why not? - _lastPoint = pointY * (bmw * 2); + // For the Apple IIGS, pointY in pixels needed to be converted to bytes. For us, it's the other way around, we need bmw in pixels + _lastPoint = pointY * (bmw); } else { // Screen wrapping?? uint16 temp = (0 - pointY) + 1; @@ -166,7 +162,7 @@ bool ImmortalEngine::clipSprite(uint16 &height, uint16 &pointIndex, uint16 &skip } // The image is clipped, time to move the index to the sprite's first scanline base position - pointIndex += (pointX) + dSprite->_images[img]._rectW; + pointIndex += pointX;// + dSprite->_images[img]._rectW; } return false; } @@ -186,7 +182,7 @@ void ImmortalEngine::spriteAligned(DataSprite *dSprite, Image &img, uint16 &skip byte pixel2 = 0; // For every scanline before height - for (int y = 0; y < height; y++, pointIndex += (bmw * 2)) { + for (int y = 0; y < height; y++, pointIndex += (bmw)) { // We increase the position by one screen width if (img._deltaPos[y] < kMaskNeg) { @@ -224,6 +220,9 @@ void ImmortalEngine::spriteAligned(DataSprite *dSprite, Image &img, uint16 &skip void ImmortalEngine::superSprite(DataSprite *dSprite, uint16 pointX, uint16 pointY, int img, uint16 bmw, byte *dst, uint16 superTop, uint16 superBottom) { // Main image construction routine + // For the Apple IIGS, the bmw is in bytes, but for us it needs to be the reverse, in pixels + bmw <<= 1; + uint16 cenX = dSprite->_cenX; uint16 cenY = dSprite->_cenY; uint16 dY = dSprite->_images[img]._deltaY; From a3697c3bd52f6799dec458b6ef72de164ede616d Mon Sep 17 00:00:00 2001 From: Quote58 Date: Thu, 22 Sep 2022 03:27:05 -0400 Subject: [PATCH 350/412] IMMORTAL: univAddSprite() calls addSprite() through g_immortal instead of Utilities --- engines/immortal/univ.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/engines/immortal/univ.cpp b/engines/immortal/univ.cpp index aef1aa889b6a..33a8861c8467 100644 --- a/engines/immortal/univ.cpp +++ b/engines/immortal/univ.cpp @@ -23,9 +23,9 @@ namespace Immortal { -void Room::univAddSprite(uint16 vX, uint16 vY, uint16 x, uint16 y, SpriteName n, int img, uint16 p) { - debug("%d %d %d", *_numSprites, n, img); - //Utilities::addSprite(_sprites, vX, vY, _numSprites, &_dataSprites[n], img, x, y, p); +void Room::univAddSprite(uint16 vX, uint16 vY, uint16 x, uint16 y, SpriteName s, int img, uint16 p) { + //debug("%d %d %d", *_numSprites, n, img); + //g_immortal->addSprite(vX, vY, s, img, x, y, p); } } // namespace immortal \ No newline at end of file From c996c64b8c6fb578fbe6cf8991aeb6d7f064fba4 Mon Sep 17 00:00:00 2001 From: Quote58 Date: Thu, 22 Sep 2022 03:28:45 -0400 Subject: [PATCH 351/412] IMMORTAL: uint8 -> uint16 for several variables + initStoryStatic moved to story.cpp --- engines/immortal/story.cpp | 180 ++++++++++++++++++++++++++++++++++++- engines/immortal/story.h | 48 +++++----- 2 files changed, 201 insertions(+), 27 deletions(-) diff --git a/engines/immortal/story.cpp b/engines/immortal/story.cpp index e7c1424e45a4..51dd04437846 100644 --- a/engines/immortal/story.cpp +++ b/engines/immortal/story.cpp @@ -47,6 +47,180 @@ namespace Immortal { +void ImmortalEngine::initStoryStatic() { + Common::Array s{"#" + Common::String(kSwordBigFrame) + "sword@", + "You find an Elven sword of&agility. Take it?@", + "Search the bones?%", + "}The sword permanently endows you with Elven agility and quickness in combat.@", + "}You notice something that looks wet and green under the pile. Search further?%", + "#" + Common::String(kBagBigFrame) + " dust@", + "}You find a bag containing Dust of Complaisance.&@", + "}Drop the bait on the ground here?%", + "}To use this dust, you throw it in the air. Do that here?%", + "_}Don+t bother me, I+m cutting a gem. Yes, you need it. No, you can+t have it. I wouldn+t give it to anyone, least of all you. Go away. ]]]]=", + "_}Let me help you. Please take this gem. No, really, I insist. Take it and go with my blessings. Good luck. ]]]]=", + "#" + Common::String(kCarpetBigFrame) + "carpet@", + "#" + Common::String(kBombBigFrame) + " bomb@", + "A gas bomb that goblins&use to paralyze trolls.&@", + "Take it?<>@", + "%", + " other@", + "#" + Common::String(kKeyBigFrame) + " key@", + "#" + Common::String(kKeyBigFrame) + " key@", + "A key to a chest.&@", + "The chest is open. Examine&contents?%", + "Put it on?%", + "Drop it?%", + "It+s unlocked. Open it?%", + "It+s locked but you have&the key. Open it?%", + "It+s locked and you don+t&have the key.@", + "The lock, triggered by a&complicated set of latches,&is unfamiliar to you.@", + "#" + Common::String(kGoldBigFrame) + "$0 gold@", + "You find $0 gold pieces.&&^#" + Common::String(kPileFrame) + "@", + "@", + "You can+t plant them on&stone tiles.@", + "It+s locked but you are&able to unlock it with&the key.@", + "_}The king is not dead, but the poison is taking effect. When he sees you, he attempts to speak:[(Give me water... the fountain... I give you... information... peace...+[Give him water?%", + "_}You dont have any water to give him. He mumbles something. Then silence... You find a key on his body.]]]]=", + "_}He mumbles something. Then silence... You find a key on his body.]]]]=", + "_}I+ll tell you how to... next level... past slime... three jewels... slime... rock becomes... floor... right, left, center of the... [Then silence. His hand opens, releasing a key.]]]]=", + "You find a door key.&@", + "You find a note.&@", + "#" + Common::String(kNoteBigFrame) + "note@", + "He+s dead.&Look for possessions?%", + "You don+t have it. Check&your inventory.@", + "Game Over&&Play again?@", + "Congratulations!&&Play again?@", + "You find a bag of bait.&@", + "#" + Common::String(kBagBigFrame) + " bait@", + "You find a stone. @", + "#" + Common::String(kStoneBigFrame) + " stone@", + "You find a red gem.&@", + "#" + Common::String(kGemBigFrame) + " gem@", + "You find a scroll with&fireball spells.&@", + "#" + Common::String(kScrollBigFrame) + "$ shots@", + "You find a map warning&you about pit traps.&@", + "#" + Common::String(kMapBigFrame) + " map@", + "#" + Common::String(kVaseBigFrame) + " oil@", + "You apply the oil but notice&as you walk that the leather&is drying out quickly.@", + "}You discover a scroll with a charm spell to use on will o+ the wisps.&@", + "#" + Common::String(kScrollBigFrame) + " charm@", + "}This charms the will o+ the wisps to follow you. Read the spell again to turn them against your enemies.@", + "}It looks like water. Drink it?%", + "Drink it?%", + "}It works! You are much stronger.]]]=", + "}It looks like it has green stuff inside. Open it?%", + "Now this will take&effect when you press the&fire button.@", + "You find a potion,&Magic Muscle.&@", + "#" + Common::String(kVaseBigFrame) + " potion@", + "You find a bottle.&@", + "#" + Common::String(kVaseBigFrame) + " bottle@", + "#" + Common::String(kRingBigFrame) + "Protean@", + "You find a Protean Ring.&@", + "You find a troll ritual knife,&used to declare a fight to&the death. @", + "#" + Common::String(kKnifeBigFrame) + " knife@", + "_}It is a fine woman+s garment. Folded inside is a ring with the words,[`To Ana, so harm will never find you. -Your loving father, Dunric.+&@", + "You find a small, well&crafted ring. @", + "#" + Common::String(kRingBigFrame) + " gift@", + "#" + Common::String(kRingBigFrame) + " Ana+s@", + "_}She is hurt and upset when she finds you don+t have her ring or won+t give it to her. She scurries back into the hole. The hole is too small for you to follow.&@", + "_}`Sir, can you help me,+ the girl pleads. `I was kidnapped and dragged down here. All the man would say is `Mordamir+s orders.+[I ~" + Common::String(kStrGive2), + "escaped using a ring my father gave me, but now I+ve lost it. Did you find it?+%", + "_}We have met before, old man. Do you remember? Because you helped me, you may pass. But I warn you, we are at war with the trolls.[Over this ladder, across the spikes, is troll territory. Very dangerous.@", + "_}You are an impostor!]]]]=", + "_}Old man, do you remember me? I am king of the goblins. You didn+t give me the water. You left me to die after you took the key from me. Now you will pay.]]]]=", + "_}You quickly fall into a deep, healing sleep...[Vivid images of a beautiful enchanted city pass by. All the city people are young and glowing. Fountains fill the city, and the splash and ~" + Common::String(kStrDream1P2), + "sparkle of water is everywhere...[Suddenly the images go black. A face appears... Mordamir!]][ ~" + Common::String(kStrDream1P3), + "He is different from how you remember him. His gentle features are now withered. His kind eyes, now cold and sunken, seem to look through you with a dark, penetrating stare. You wake rejuvenated, but disturbed.]]]]]=", + "_}Here, take this ring in return. [I don+t know if it will help, but I heard the unpleasant little dwarf say, (Clockwise, three rings around the triangle.+[Could that be a clue to his exit puzzle? I must go. Goodbye.]]]]=", + "#" + Common::String(kSackBigFrame) + " spores@", + "You find a sack of bad&smelling spores.&@", + "Please insert play disk.@", + "New game?%", + "Enter certificate:&-=", + "Invalid certificate.@", + "End of level!&Here is your certificate:&&=", + "&@", + "\\ Electronic Arts presents&& The Immortal&&&&  1990 Will Harvey|]]]]]]]]\\]=", + " written by&& Will Harvey& Ian Gooding& Michael Marcantel& Brett G. Durrett& Douglas Fulton|]]]]]]]/=", + "_}Greetings, friend! Come, I+ve got something you need. These parts are plagued with slime.[You can+t venture safely without my slime oil for boots, a bargain at only 80 gold pieces.%", + "_}All right, 60 gold pieces for my oil. Rub it on your boots and slime won+t touch you. 60, friend.%", + "This room doesn+t resemble&any part of the map.@", + "This room resembles part&of the map.@"}; + _strPtrs = s; + + // Scope, amirite? + Common::Array cyc0{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,-1}; + Common::Array cyc1{15,16,17,18,19,20,21,22,-1}; + Common::Array cyc2{0,1,2,-1}; + Common::Array cyc3{3,4,5,-1}; + Common::Array cyc4{6,7,8,9,10,-1}; + Common::Array cyc5{11,12,13,14,15,-1}; + Common::Array cyc6{16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,-1}; + Common::Array cyc7{0,1,2,3,4,-1}; + Common::Array cyc8{5,1+5,2+5,3+5,4+5,-1}; + Common::Array cyc9{10,1+10,2+10,3+10,4+10,-1}; + Common::Array cyc10{15,1+15,2+15,3+15,4+15,-1}; + Common::Array cyc11{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,-1}; + Common::Array cyc12{0,1,2,3,4,5,6,7,8,9,-1}; + Common::Array cyc13{0,1,2,3, 0,1,2,3, 0,1,2,3, 0,1,2,3, 0,1,2,3, 0,1,2,3, 0,1,2,3, 0,1,2,3, -1}; + Common::Array cyc14{31,32,33,32, 34,35,36,35, 37,38,39,38, 40,41,42,41, 43,44,45,44, 46,47,48,47, 49,50,51,50, 52,53,54,53, -1}; + Common::Array cyc15{55, -1}; + Common::Array cyc16{63,64,65,66, 63,64,65,66, 63,64,65,66, 63,64,65,66, 63,64,65,66, 63,64,65,66, 63,64,65,66, 63,64,65,66,-1}; + Common::Array cyc17{0,1,0,-1}; + Common::Array cyc18{0,1,2,4,5,6,7,8,9,10,11,12,2,1,-1}; + Common::Array cyc19{0,0,1,2,13,14,15,16,4,2,3,-1}; + Common::Array cyc20{0,1,2,3,20,21,22,23,24,25,26,27,5,4,3,-1}; + Common::Array cyc21{0,1,2,3,-1}; + Common::Array cyc22{0,17,18,19,3,-1}; + Common::Array cyc23{0,1,-1}; + Common::Array cyc24{28,28,28,28,-1}; + Common::Array cyc25{15,16,15,16,15,1+15,1+15,-1}; + Common::Array cyc26{10+15,11+15,12+15,13+15,14+15,15+15,16+15,-1}; + Common::Array cyc27{2+15,3+15,4+15,5+15,-1}; + Common::Array cyc28{6+15,7+15,8+15,9+15,-1}; + Common::Array cyc29{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,-1}; + Common::Array cyc30{0,1,2,3,3,3,3,4,5,6,-1}; + Common::Array cyc31{0,1,2,3,4,5,6,7,8,-1}; + + Common::Array c{SCycle(kBubble, false, cyc0), SCycle(kBubble, false, cyc1), + SCycle(kSpark, false, cyc2), SCycle(kSpark, false, cyc3), + SCycle(kSpark, false, cyc4), SCycle(kSpark, false, cyc5), SCycle(kSpark, false, cyc6), + SCycle(kPipe, false, cyc7), SCycle(kPipe, false, cyc8), + SCycle(kPipe, false, cyc9), SCycle(kPipe, false, cyc10), + SCycle(kAnaVanish, false, cyc11), SCycle(kAnaGlimpse, false, cyc12), + SCycle(kKnife, true, cyc13), + SCycle(kSpark, true, cyc14), SCycle(kSpark, true, cyc15), SCycle(kSpark, true, cyc16), + SCycle(kBigBurst, false, cyc17), + SCycle(kFlame, false, cyc18), SCycle(kFlame, false, cyc19), SCycle(kFlame, false, cyc20), + SCycle(kFlame, false, cyc21), SCycle(kFlame, false, cyc22), SCycle(kFlame, false, cyc23), + SCycle(kFlame, false, cyc24), + SCycle(kCandle, false, cyc25), SCycle(kCandle, false, cyc26), SCycle(kCandle, false, cyc27), + SCycle(kCandle, false, cyc28), SCycle(kCandle, false, cyc29), + SCycle(kSink, false, cyc30), + SCycle(kNorlacDown, false, cyc31)}; + _cycPtrs = c; + + Common::Array m{}; + _motivePtrs = m; + + Common::Array d{}; + _damagePtrs = d; + + Common::Array u{}; + _usePtrs = u; + + Common::Array p{}; + _pickupPtrs = p; + + CArray2D pr{}; + _programPtrs = pr; + + Common::Array o{}; + _objTypePtrs = o; + +} + void ImmortalEngine::initStoryDynamic() { /* There is one major difference between the source logic and this method. * It doesn't change the game logic, but it does change the logic of storing @@ -69,7 +243,7 @@ void ImmortalEngine::initStoryDynamic() { // *NOTE* the data types Trap and Program will be in the static Story area, and referenced by an enum - const uint8 kZip = 5; + const uint16 kZip = 5; /* * ::: Level 0: Intro 1 ::: @@ -79,8 +253,8 @@ void ImmortalEngine::initStoryDynamic() { * including spawn point and entry/exit points */ int univRoom = 4; // The room the player starts in when beginning this level - uint8 univRoomX = 512; - uint8 univRoomY = 416; + uint16 univRoomX = 512; + uint16 univRoomY = 416; _stories[0]._level = 0; _stories[0]._part = 1; diff --git a/engines/immortal/story.h b/engines/immortal/story.h index eeea16426e53..4b369dbeb3f3 100644 --- a/engines/immortal/story.h +++ b/engines/immortal/story.h @@ -118,8 +118,8 @@ struct Use { }; struct ObjType { - Str _str = kStrNoDesc; - Str _desc = kStrNoDesc; + Str _str = kStrNull; + Str _desc = kStrNull; int _size = 0; Pickup _pickup; Use _use; @@ -150,11 +150,11 @@ Common::Array _frames; }; struct SRoom { - uint8 _x = 0; - uint8 _y = 0; + uint16 _x = 0; + uint16 _y = 0; RoomFlag _flags = kRoomFlag0; SRoom() {} - SRoom(uint8 x, uint8 y, RoomFlag f) { + SRoom(uint16 x, uint16 y, RoomFlag f) { _x = x; _y = y; _flags = f; @@ -163,13 +163,13 @@ struct SRoom { struct SDoor { uint8 _dir = 0; - uint8 _x = 0; - uint8 _y = 0; - uint8 _fromRoom = 0; - uint8 _toRoom = 0; + uint16 _x = 0; + uint16 _y = 0; + uint16 _fromRoom = 0; + uint16 _toRoom = 0; bool _isLocked = false; SDoor() {} - SDoor(uint8 d, uint8 x, uint8 y, uint8 f, uint8 t, bool l) { + SDoor(uint8 d, uint16 x, uint16 y, uint16 f, uint16 t, bool l) { _dir = d; _x = x; _y = y; @@ -180,11 +180,11 @@ struct SDoor { }; struct SFlame { - uint8 _x = 0; - uint8 _y = 0; + uint16 _x = 0; + uint16 _y = 0; FPattern _p = kFlameOff; SFlame() {} - SFlame(uint8 x, uint8 y, FPattern p) { + SFlame(uint16 x, uint16 y, FPattern p) { _x = x; _y = y; _p = p; @@ -192,14 +192,14 @@ FPattern _p = kFlameOff; }; struct SObj { - uint8 _x = 0; - uint8 _y = 0; + uint16 _x = 0; + uint16 _y = 0; SObjType _type = kTypeTrap; uint8 _flags = 0; SpriteFrame _frame = kNoFrame; Common::Array _traps; SObj() {} - SObj(uint8 x, uint8 y, SObjType t, SpriteFrame s, uint8 f, Common::Array traps) { + SObj(uint16 x, uint16 y, SObjType t, SpriteFrame s, uint8 f, Common::Array traps) { _x = x; _y = y; _type = t; @@ -210,15 +210,15 @@ Common::Array _traps; }; struct SMonster { - uint8 _x = 0; - uint8 _y = 0; - uint8 _hits = 0; + uint16 _x = 0; + uint16 _y = 0; + uint16 _hits = 0; MonsterFlag _madAt = kMonstIsNone; uint8 _flags = 0; SpriteName _sprite = kCandle; Common::Array _program; SMonster() {} - SMonster(uint8 x, uint8 y, uint8 h, MonsterFlag m, uint8 f, Common::Array p, SpriteName s) { + SMonster(uint16 x, uint16 y, uint16 h, MonsterFlag m, uint8 f, Common::Array p, SpriteName s) { _x = x; _y = y; _hits = h; @@ -233,10 +233,10 @@ struct Story { int _level = 0; int _part = 1; - uint8 _initialUnivX = 0; - uint8 _initialUnivY = 0; - uint8 _playerPointX = 0; - uint8 _playerPointY = 0; + uint16 _initialUnivX = 0; + uint16 _initialUnivY = 0; + uint16 _playerPointX = 0; + uint16 _playerPointY = 0; Common::Array _ladders; Common::Array _rooms; From 5c2163db8e182846ef3a9791ba7319e827d34014 Mon Sep 17 00:00:00 2001 From: Quote58 Date: Thu, 22 Sep 2022 03:32:57 -0400 Subject: [PATCH 352/412] IMMORTAL: Room object utilizes g_immortal instead of passing pointers from engine members --- engines/immortal/room.cpp | 7 +------ engines/immortal/room.h | 30 +++++++++++------------------- 2 files changed, 12 insertions(+), 25 deletions(-) diff --git a/engines/immortal/room.cpp b/engines/immortal/room.cpp index 94107bc405b7..5351375162d6 100644 --- a/engines/immortal/room.cpp +++ b/engines/immortal/room.cpp @@ -23,15 +23,10 @@ namespace Immortal { -Room::Room(uint8 x, uint8 y, RoomFlag f, Sprite *s, DataSprite *d, Cycle *c, Common::Array p, int *n) +Room::Room(uint8 x, uint8 y, RoomFlag f) : _xPos(x) , _yPos(y) , _flags(f) - , _sprites(s) - , _dataSprites(d) - , _cycles(c) - , _cycPtrs(p) - , _numSprites(n) , _candleTmp(0) , _randomSource("Immortal") { } diff --git a/engines/immortal/room.h b/engines/immortal/room.h index b663329a3a4c..7cc9937117b8 100644 --- a/engines/immortal/room.h +++ b/engines/immortal/room.h @@ -107,7 +107,7 @@ class Room { Common::RandomSource _randomSource; public: - Room(uint8 x, uint8 y, RoomFlag f, Sprite *s, DataSprite *d, Cycle *c, Common::Array p, int *n); + Room(uint8 x, uint8 y, RoomFlag f); ~Room() {} /* @@ -119,26 +119,20 @@ class Room { const uint8 kLightTorchX = 10; const uint8 kMaxFlameCycs = 16; - // Other - int *_numSprites; - Sprite *_sprites; - Cycle *_cycles; -DataSprite *_dataSprites; - Common::Array _cycPtrs; Common::Array _fset; Common::Array _monsters; Common::Array _objects; RoomFlag _flags; - uint8 _xPos; - uint8 _yPos; - uint8 _holeRoom; - uint8 _holeCellX; - uint8 _holeCellY; - uint8 _candleTmp; // Special case for candle in maze 0 - uint8 _numFlames; - uint8 _numInRoom; + uint8 _xPos = 0; + uint8 _yPos = 0; + uint8 _holeRoom = 0; + uint8 _holeCellX = 0; + uint8 _holeCellY = 0; + uint8 _candleTmp = 0; // Special case for candle in maze 0 + uint8 _numFlames = 0; + uint8 _numInRoom = 0; /* * --- Methods --- @@ -207,7 +201,7 @@ DataSprite *cycleGetDataSprite(int c); // This takes the place of getFile + ge void flameInit(); void flameDrawAll(uint16 vX, uint16 vY); bool roomLighted(); - void lightTorch(int x, int y); + void lightTorch(uint8 x, uint8 y); void flameFreeAll(); void flameSetRoom(Common::Array); int flameGetCyc(Flame *f, int first); @@ -227,11 +221,9 @@ DataSprite *cycleGetDataSprite(int c); // This takes the place of getFile + ge * [Univ.cpp] Functions from Univ.GS */ - void univAddSprite(uint16 vX, uint16 vY, uint16 x, uint16 y, SpriteName n, int img, uint16 p); + void univAddSprite(uint16 vX, uint16 vY, uint16 x, uint16 y, SpriteName s, int img, uint16 p); }; - - } // namespace immortal #endif From bf95330f2cff88ae447f3e6e7054e74fded60177 Mon Sep 17 00:00:00 2001 From: Quote58 Date: Thu, 22 Sep 2022 03:35:42 -0400 Subject: [PATCH 353/412] IMMORTAL: level.cpp no longer passes pointers to room object --- engines/immortal/level.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/engines/immortal/level.cpp b/engines/immortal/level.cpp index 92510e2022f6..61b17098756b 100644 --- a/engines/immortal/level.cpp +++ b/engines/immortal/level.cpp @@ -43,7 +43,7 @@ void ImmortalEngine::levelNew(int l) { levelStory(l); if (kLevelToMaze[l] != _lastLevelLoaded) { _lastLevelLoaded = kLevelToMaze[l]; - //loadMaze(l); + //loadMazeGraphics(l); } if (_level != _lastSongLoaded) { @@ -76,7 +76,7 @@ void ImmortalEngine::levelLoadFile(int l) { } for (int r = 0; r < _stories[l]._rooms.size(); r++) { - _rooms[r] = new Room(_stories[l]._rooms[r]._x, _stories[l]._rooms[r]._y, _stories[l]._rooms[r]._flags, _sprites, _dataSprites, _cycles, _cycPtrs, &_numSprites); + _rooms[r] = new Room(_stories[l]._rooms[r]._x, _stories[l]._rooms[r]._y, _stories[l]._rooms[r]._flags); Common::Array allFlames(_stories[l]._flames[r].size()); if (_stories[l]._flames[r].size() > 0) { @@ -124,7 +124,6 @@ void ImmortalEngine::levelDrawAll() { _count++; //univAutoCenter(); clearSprites(); - // Room needs to be able to add to the sprite list, so we need to give it a pointer to it first _rooms[_currentRoom]->drawContents(_viewPortX, _viewPortY); } From 7284826303a1e1b61ff2739ec29c004b16a45515 Mon Sep 17 00:00:00 2001 From: Quote58 Date: Thu, 22 Sep 2022 03:38:04 -0400 Subject: [PATCH 354/412] IMMORTAL: g_engine -> g_immortal + minor adjustments --- engines/immortal/immortal.cpp | 23 ++++---- engines/immortal/immortal.h | 98 ++++++++++++++++++++++++++++------- 2 files changed, 92 insertions(+), 29 deletions(-) diff --git a/engines/immortal/immortal.cpp b/engines/immortal/immortal.cpp index fd55add4e92f..e3ce80031edc 100644 --- a/engines/immortal/immortal.cpp +++ b/engines/immortal/immortal.cpp @@ -28,13 +28,13 @@ namespace Immortal { -ImmortalEngine *g_engine; +ImmortalEngine *g_immortal; ImmortalEngine::ImmortalEngine(OSystem *syst, const ADGameDescription *gameDesc) : Engine(syst) , _gameDescription(gameDesc) , _randomSource("Immortal") { - g_engine = this; + g_immortal = this; // Add the game folder to the search manager path variable const Common::FSNode gameDataDir(ConfMan.get("path")); @@ -151,21 +151,28 @@ Common::Error ImmortalEngine::run() { } //Main: - _zero = 0; - _dim = 0; - _usingNormal = 0; - _draw = 1; + _zero = 0; + _draw = 1; + _usingNormal = 1; + _penY = 7; + _penX = 1; initStoryStatic(); // Init the arrays of static story elements (done at compile time in the source) loadPalette(); // We need to grab the palette from the disk first + + // This is the equivalent of Main->InitGraphics->MyClearScreen in Driver useNormal(); // The first palette will be the default + loadFont(); // Load the font sprite loadWindow(); // Load the window background loadSingles("Song A"); // Music loadSprites(); // Get all the sprite data into memory + _playing = kSongNothing; _themePaused = 0; + clearSprites(); // Clear the sprites before we start + // This is where the request play disk would happen, but that's not needed here logicInit(); // Init the game logic _err = Common::kNoError; @@ -186,11 +193,9 @@ Common::Error ImmortalEngine::run() { userIO(); noNetwork(); pollKeys(); - //logic(); + logic(); pollKeys(); if (logicFreeze() == 0) { - DataSprite *d = &_dataSprites[kGoblin2]; - superSprite(d, 20, 0xA0, 4, kVSBMW, _screenBuff, kSuperTop, kMySuperBottom); drawUniv(); pollKeys(); fixColors(); diff --git a/engines/immortal/immortal.h b/engines/immortal/immortal.h index fe20b7cfa183..fce55cf9ea6b 100644 --- a/engines/immortal/immortal.h +++ b/engines/immortal/immortal.h @@ -77,6 +77,11 @@ enum InputAction { kActionDBGStep // Debug key for moving engine forward one frame at a time }; +enum ButtonHeldMask { + kButton0Held = 2, + kButton1Held = 4 +}; + enum InputDirection { kDirectionUp, kDirectionLeft, @@ -84,6 +89,12 @@ enum InputDirection { kDirectionRight }; +// Needed by kernal for text +enum FadeType { + kTextFadeIn, + kTextDontFadeIn +}; + // Needed by kernal for music enum Song { kSongNothing, @@ -92,6 +103,15 @@ enum Song { kSongText }; +enum Sound { + kSoundSwish = 6, + kSoundAwe, + kSoundHuh, + kSoundClank, + kSoundFireBall, + kSoundDoor +}; + // Needed by logic for various things enum MonsterID { kPlayerID @@ -132,7 +152,7 @@ struct Spark { struct GenericSprite { }; -// Doors are a property of the level, not the room, they defined the connections between rooms +// Doors are a property of the level, not the room, they define the connections between rooms struct Door { uint8 _x = 0; uint8 _y = 0; @@ -192,10 +212,10 @@ class ImmortalEngine : public Engine { const int kScreenSize = (kResH * kResV) * 2; // The size of the screen buffer is (320x200) * 2 byte words const uint16 kScreenLeft = 32; const uint16 kScreenTop = 20; - const int kTextLeft = 8; - const int kTextTop = 4; - const int kGaugeX = 0; - const int kGaugeY = -13; // ??? + const uint8 kTextLeft = 8; + const uint8 kTextTop = 4; + const uint8 kGaugeX = 0; + const uint8 kGaugeY = -13; // ??? const uint16 kScreenBMW = 160; // Screen BitMap Width? const uint16 kChrW = 64; const uint16 kChrH = 32; @@ -243,6 +263,18 @@ class ImmortalEngine : public Engine { const uint16 kViewPortSpY = 0; const uint16 kWizardX = 28; // Common sprite center for some reason const uint16 kWizardY = 37; + const uint16 kObjectY = 24; + const uint16 kObjectX = 32; + const uint16 kObjectHeight = 48; + const uint16 kObjectWidth = 64; + + // Text constants + const uint8 kMaxRows = 5; + const uint8 kMaxCollumns = 26; + + const uint16 kYesNoY = 88; + const uint16 kYesNoX1 = 8; + const uint16 kYesNoX2 = 182; // Asset constants const char kGaugeOn = 1; // On uses the sprite at index 1 of the font spriteset @@ -323,6 +355,14 @@ class ImmortalEngine : public Engine { int _pressedDirection = 0; int _heldDirection = 0; + // Text printing members + uint8 _slowText = 0; + uint8 _formatted = 0; + uint8 _collumn = 0; + uint8 _row = 0; + uint8 _myButton = 0; + uint8 _lastYes = 0; + // Music members Song _playing; // Currently playing song int _themeID = 0; // Not sure yet tbh @@ -343,7 +383,6 @@ class ImmortalEngine : public Engine { Common::Array _objTypePtrs; // Screen members - byte *_window; // Bitmap of the window around the game byte *_screenBuff; // The final buffer that will transfer to the screen uint16 _myCNM[(kViewPortCW + 1)][(kViewPortCH + 1)]; uint16 _myModCNM[(kViewPortCW + 1)][(kViewPortCH + 1)]; @@ -394,6 +433,7 @@ GenericSprite _genSprites[6]; void whiteScreen(); // Draws a white rectanlge on the screen buffer (but does not do anything with resetColors) void rect(int x, int y, int w, int h); // Draws a solid rectangle at x,y with size w,h. Also shadows for blit? void backspace(); // Moves draw position back and draws empty rect in place of char + void printByte(int b); void printChr(char c); void loadWindow(); // Gets the window.bm file void drawUniv(); // Draw the background, add the sprites, determine draw order, draw the sprites @@ -406,10 +446,14 @@ GenericSprite _genSprites[6]; void makeMyCNM(); // ? void drawBGRND(); // Draw floor parts of leftmask rightmask and maskers void addRows(); // Add rows to drawitem array + void addSprite(uint16 vpX, uint16 vpY, SpriteName s, int img, uint16 x, uint16 y, uint16 p); void addSprites(); // Add all active sprites that are in the viewport, into a list that will be sorted by priority void sortDrawItems(); // Sort said items void drawItems(); // Draw the items over the background + void drawIcon(int img); void setPen(uint16 penX, uint16 penY); // Sets the 'pen' x and y positions, including making y negative if above a certain point + void center(); + void carriageReturn(); // Music void toggleSound(); // Actually pauses the sound, doesn't just turn it off/mute @@ -417,11 +461,13 @@ GenericSprite _genSprites[6]; Song getPlaying(); void playMazeSong(); void playCombatSong(); + void playTextSong(); void doGroan(); void stopMusic(); void musicPause(int sID); void musicUnPause(int sID); void loadSingles(Common::String songName); // Loads and then parse the maze song + void standardBeep(); // Palette void loadPalette(); // Get the static palette data from the disk @@ -443,17 +489,17 @@ GenericSprite _genSprites[6]; // Assets Common::SeekableReadStream *loadIFF(Common::String fileName); // Loads a file and uncompresses if it is compressed void initStoryStatic(); // Sets up all of the global static story elements - //void loadMazeGraphics(); // Creates a universe with a maze + void loadMazeGraphics(int m); // Creates a universe with a maze void loadFont(); // Gets the font.spr file, and centers the sprite void clearSprites(); // Clears all sprites before drawing the current frame void loadSprites(); // Loads all the sprite files and centers their sprites (in spritelist, but called from kernal) - void kernalAddSprite(uint16 x, uint16 y, SpriteName n, int img, uint16 p); // Input void userIO(); // Get input void pollKeys(); // Buffer input void noNetwork(); // Setup input mirrors void waitKey(); // Waits until a key is pressed (until getInput() returns true) + void waitClick(); // Waits until one of the two buttons is pressed void blit8(); // This is actually just input, but it is called blit because it does a 'paddle blit' 8 times // These will replace the myriad of hardware input handling from the source @@ -525,19 +571,31 @@ GenericSprite _genSprites[6]; void miscInit(); void setRandomSeed(); void getRandom(); - void myDelay(); + + // Input related + bool buttonPressed(); + bool firePressed(); // Text printing - bool textPrint(Str s); - void textSub(); - void textEnd(Str s); - void textMiddle(Str s); - void textBeginning(Str s); - void yesNo(); + void myFadeOut(); + void myFadeIn(); + bool textPrint(Str s, int n); + bool textBeginning(Str s, int n); + bool textSub(Str s, FadeType f, int n); + void textEnd(Str s, int n); + void textMiddle(Str s, int n); - // Input related - void buttonPressed(); - void firePressed(); + void textCR(); + void textPageBreak(Common::String s, int &index); + void textAutoPageBreak(); + void textDoSpace(Common::String s, int index); + void textBounceDelay(); + + bool yesNo(); + void noOn(); + void yesOn(); + + void myDelay(int j); /* @@ -680,8 +738,8 @@ GenericSprite _genSprites[6]; } */ }; -extern ImmortalEngine *g_engine; -#define SHOULD_QUIT ::Immortal::g_engine->shouldQuit() +extern ImmortalEngine *g_immortal; +#define SHOULD_QUIT ::Immortal::g_immortal->shouldQuit() } // namespace Immortal From 4ca64366dc0fc695431075fbff5466aec93dcee7 Mon Sep 17 00:00:00 2001 From: Quote58 Date: Thu, 22 Sep 2022 03:40:30 -0400 Subject: [PATCH 355/412] IMMORTAL: flameSet and Cycle utilize g_immortal instead of utilities --- engines/immortal/cycle.cpp | 34 +++++++++++++++++----------------- engines/immortal/flameSet.cpp | 6 +++--- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/engines/immortal/cycle.cpp b/engines/immortal/cycle.cpp index f2da5503c5f4..bec8a6eba796 100644 --- a/engines/immortal/cycle.cpp +++ b/engines/immortal/cycle.cpp @@ -47,10 +47,10 @@ namespace Immortal { int Room::cycleNew(CycID id) { // An 'available' cyc is identified by the index being -1 for (int i = 0; i < kMaxCycles; i++) { - if (_cycles[i]._index == -1) { - _cycles[i]._index = 0; - _cycles[i]._cycList = id; - debug("made cyc, = %d", i); + if (g_immortal->_cycles[i]._index == -1) { + g_immortal->_cycles[i]._index = 0; + g_immortal->_cycles[i]._cycList = id; + //debug("made cyc, = %d", i); return i; } } @@ -59,18 +59,18 @@ int Room::cycleNew(CycID id) { } void Room::cycleFree(int c) { - _cycles[c]._index = -1; + g_immortal->_cycles[c]._index = -1; } bool Room::cycleAdvance(int c) { /* If we have reached the end, check if repeat == true, and set back to 0 if so * Otherwise, set to the last used index */ - _cycles[c]._index++; - if (_cycPtrs[_cycles[c]._cycList]._frames[_cycles[c]._index] == -1) { - if (_cycPtrs[_cycles[c]._cycList]._repeat == true) { - _cycles[c]._index = 0; + g_immortal->_cycles[c]._index++; + if (g_immortal->_cycPtrs[g_immortal->_cycles[c]._cycList]._frames[g_immortal->_cycles[c]._index] == -1) { + if (g_immortal->_cycPtrs[g_immortal->_cycles[c]._cycList]._repeat == true) { + g_immortal->_cycles[c]._index = 0; } else { - _cycles[c]._index--; + g_immortal->_cycles[c]._index--; return true; } } @@ -88,33 +88,33 @@ int Room::cycleGetFrame(int c) { * This is essentially self-modifying code, and it saves 2 bytes of DP memory over the traditional * STA DP : LDA (DP) */ - debug("%d", _cycPtrs[_cycles[c]._cycList]._frames[_cycles[c]._index]); - return _cycPtrs[_cycles[c]._cycList]._frames[_cycles[c]._index]; + //debug("%d", _cycPtrs[_cycles[c]._cycList]._frames[_cycles[c]._index]); + return g_immortal->_cycPtrs[g_immortal->_cycles[c]._cycList]._frames[g_immortal->_cycles[c]._index]; } int Room::cycleGetNumFrames(int c) { // Why in the world is this not kept as a property of the cycle? We have to calculate the size of the array each time int index = 0; - while (_cycPtrs[_cycles[c]._cycList]._frames[index] != -1) { + while (g_immortal->_cycPtrs[g_immortal->_cycles[c]._cycList]._frames[index] != -1) { index++; } return index; } DataSprite *Room::cycleGetDataSprite(int c) { - return &_dataSprites[_cycPtrs[_cycles[c]._cycList]._sName]; + return &g_immortal->_dataSprites[g_immortal->_cycPtrs[g_immortal->_cycles[c]._cycList]._sName]; } CycID Room::getCycList(int c) { - return _cycles[c]._cycList; + return g_immortal->_cycles[c]._cycList; } int Room::cycleGetIndex(int c) { - return _cycles[c]._index; + return g_immortal->_cycles[c]._index; } void Room::cycleSetIndex(int c, int f) { - _cycles[c]._index = f; + g_immortal->_cycles[c]._index = f; } diff --git a/engines/immortal/flameSet.cpp b/engines/immortal/flameSet.cpp index c861cb67220b..32e973c0734f 100644 --- a/engines/immortal/flameSet.cpp +++ b/engines/immortal/flameSet.cpp @@ -47,7 +47,7 @@ void Room::flameFreeAll() { void Room::flameDrawAll(uint16 vX, uint16 vY) { for (int i = 0; i < _fset.size(); i++) { - univAddSprite(vX, vY, _fset[i]._x, _fset[i]._y, _cycPtrs[_cycles[_fset[i]._c]._cycList]._sName, cycleGetFrame(_fset[i]._c), 0); + univAddSprite(vX, vY, _fset[i]._x, _fset[i]._y, g_immortal->_cycPtrs[g_immortal->_cycles[_fset[i]._c]._cycList]._sName, cycleGetFrame(_fset[i]._c), 0); if (cycleAdvance(_fset[i]._c) == true) { cycleFree(_fset[i]._c); _fset[i]._c = flameGetCyc(&_fset[i], 1); @@ -68,7 +68,7 @@ bool Room::roomLighted() { return false; } -void Room::lightTorch(int x, int y) { +void Room::lightTorch(uint8 x, uint8 y) { /* Checks every torch to see if it is: * pattern == off, and inside the point x,y * which is the fireball position. This is a @@ -79,7 +79,7 @@ void Room::lightTorch(int x, int y) { for (int i = 0; i < _fset.size(); i++) { if (_fset[i]._p == kFlameOff) { - if (Immortal::Utilities::inside(x, y, kLightTorchX, _fset[i]._x + 16, _fset[i]._y + 8)) { + if (Utilities::inside(kLightTorchX, x, y, _fset[i]._x + 16, _fset[i]._y + 8)) { _fset[i]._p = kFlameNormal; } From 13ab4219aea5780acbe5f75bcf7ea5beeb237737 Mon Sep 17 00:00:00 2001 From: Quote58 Date: Thu, 22 Sep 2022 03:41:44 -0400 Subject: [PATCH 356/412] IMMORTAL Remove kStrNoDesc because kStrNull exists --- engines/immortal/definitions.h | 1 - 1 file changed, 1 deletion(-) diff --git a/engines/immortal/definitions.h b/engines/immortal/definitions.h index 8de52483cc6c..de431f4c9e56 100644 --- a/engines/immortal/definitions.h +++ b/engines/immortal/definitions.h @@ -96,7 +96,6 @@ enum Motive { // This will likely be moved to a monster ai }; enum Str { - kStrNoDesc, kStrSword, kStrSwordDesc, kStrBonesText1, From 9e911f29d61a1371f0eb13451691f9b8b800ed44 Mon Sep 17 00:00:00 2001 From: Quote58 Date: Thu, 22 Sep 2022 03:42:33 -0400 Subject: [PATCH 357/412] IMMORTAL: Text rendering through textSub() and associated functions preliminary implementation --- engines/immortal/kernal.cpp | 416 ++++++++++++++++-------------------- engines/immortal/logic.cpp | 32 +-- engines/immortal/misc.cpp | 403 +++++++++++++++++++++++++++++++++- 3 files changed, 588 insertions(+), 263 deletions(-) diff --git a/engines/immortal/kernal.cpp b/engines/immortal/kernal.cpp index 9344ac283cf9..643ee8508784 100644 --- a/engines/immortal/kernal.cpp +++ b/engines/immortal/kernal.cpp @@ -48,25 +48,21 @@ void ImmortalEngine::drawUniv() { _myUnivPointX = !(_myViewPortX & (kChrW - 1)) + kViewPortSpX; _myUnivPointY = !(_myViewPortY & (kChrH - 1)) + kViewPortSpY; - // To start constructing the screen, we start with the frame as the base - memcpy(_screenBuff, _window, kScreenSize); - makeMyCNM(); drawBGRND(); // Draw floor parts of leftmask rightmask and maskers addRows(); // Add rows to drawitem array addSprites(); // Add all active sprites that are in the viewport, into a list that will be sorted by priority sortDrawItems(); // Sort said items drawItems(); // Draw the items over the background +} +void ImmortalEngine::copyToScreen() { /* copyRectToSurface will apply the screenbuffer to the ScummVM surface. * We want to do 320 bytes per scanline, at location (0,0), with a * size of 320x200. */ _mainSurface->copyRectToSurface(_screenBuff, kResH, 0, 0, kResH, kResV); -} - -void ImmortalEngine::copyToScreen() { if (_draw == 1) { g_system->copyRectToScreen((byte *)_mainSurface->getPixels(), kResH, 0, 0, kResH, kResV); g_system->updateScreen(); @@ -74,19 +70,24 @@ void ImmortalEngine::copyToScreen() { } void ImmortalEngine::clearScreen() { - //fill the visible screen with black pixels by drawing a rectangle + // Fill the visible screen with black pixels by drawing a rectangle //rect(32, 20, 256, 128, 0) + // This is just temporary, until rect() is implemented + for (int y = 0; y < 128; y++) { + for (int x = 0; x < 256; x++) { + _screenBuff[((y + 20) * kResH) + (x + 32)] = 0; + } + } + _penX = kTextLeft; + _penY = kTextTop; + if ((_dontResetColors & kMaskLow) == 0) { useNormal(); } -} - -void ImmortalEngine::whiteScreen() { - //fill the visible screen with black pixels by drawing a rectangle - //rect(32, 20, 256, 128, 13) + copyToScreen(); } void ImmortalEngine::mungeBM() {} @@ -96,6 +97,11 @@ void ImmortalEngine::sBlit() {} void ImmortalEngine::scroll() {} void ImmortalEngine::makeMyCNM() {} // ? +void ImmortalEngine::drawIcon(int img) { + superSprite(&_dataSprites[kObject], ((kObjectWidth / 2) + kScreenLeft) + _penX, _penY + (kObjectY + kScreenTop), img, kScreenBMW, _screenBuff, 0, 200); + _penY += kObjectHeight; +} + void ImmortalEngine::addRows() { // I'm not really sure how this works yet int i = _num2DrawItems; @@ -108,12 +114,43 @@ void ImmortalEngine::addRows() { _num2DrawItems = i; } +void ImmortalEngine::addSprite(uint16 vpX, uint16 vpY, SpriteName s, int img, uint16 x, uint16 y, uint16 p) { + debug("adding sprite..."); + if (_numSprites != kMaxSprites) { + if (x >= (kResH + kMaxSpriteLeft)) { + x |= kMaskHigh; // Make it negative + } + + _sprites[_numSprites]._X = (x << 1) + vpX; + + if (y >= (kMaxSpriteAbove + kResV)) { + y |= kMaskHigh; + } + + _sprites[_numSprites]._Y = (y << 1) + vpY; + + if (p >= 0x80) { + p |= kMaskHigh; + } + + _sprites[_numSprites]._priority = ((p + y) ^ 0xFFFF) + 1; + + _sprites[_numSprites]._image = img; + _sprites[_numSprites]._dSprite = &_dataSprites[s]; + _sprites[_numSprites]._on = 1; + _numSprites += 1; + debug("sprite added"); + } else { + debug("Max sprites reached beeeeeep!!"); + } +} + void ImmortalEngine::addSprites() { // My goodness this routine is gross int tmpNum = _num2DrawItems; for (int i = 0; i < kMaxSprites; i++) { // If the sprite is active - if (_sprites[i]._on == 1) { + if (/*_sprites[i]._on*/0 == 1) { // If sprite X is an odd number??? if ((_sprites[i]._X & 1) != 0) { debug("not good! BRK"); @@ -140,7 +177,7 @@ void ImmortalEngine::addSprites() { DataSprite *tempD = _sprites[i]._dSprite; debug("what sprite is this: %d %d %d", i, _sprites[i]._image, _sprites[i]._dSprite->_images.size()); - Image *tempImg = &(tempD->_images[0/*_sprites[i]._image*/]); + Image *tempImg = &(tempD->_images[_sprites[i]._image]); int sx = ((_sprites[i]._X + tempImg->_deltaX) - tempD->_cenX) - _myViewPortX; int sy = ((_sprites[i]._Y + tempImg->_deltaY) - tempD->_cenY) - _myViewPortY; @@ -299,6 +336,38 @@ void ImmortalEngine::backspace() { // Just moves the drawing position back by a char, and then draws an empty rect there (I think) _penX -= 8; //rect(_penX + 32, 40, 8, 16, 0); + + // The Y is set here presumably because it's only used for the certificate + for (int y = 0; y < 16; y++) { + for (int x = 0; x < 8; x++) { + _screenBuff[((y + 40) * kResH) + (x + (_penX + 32))] = 0; + } + } +} + +void ImmortalEngine::printByte(int b) { + int hundreds = 0; + int tens = 0; + + while ((b - 100) >= 0) { + hundreds++; + b -= 100; + } + + if (hundreds > 0) { + printChr(char (hundreds + '0')); + } + + while ((b - 10) >= 0) { + tens++; + b -= 10; + } + + if (tens > 0) { + printChr(char (tens + '0')); + } + + printChr(char (b + '0')); } void ImmortalEngine::printChr(char c) { @@ -310,36 +379,37 @@ void ImmortalEngine::printChr(char c) { return; } + // Why is single quote done twice? if (c == 0x27) { _penX -= 2; } - if ((c >= 'A') && (c <= 'Z')) { + switch (c) { + case 'm': + case 'w': + case 'M': + case 'W': + _penX += 8; + default: + break; + } + + if ((((c >= 'A') && (c <= 'Z'))) || ((c == kGaugeOn) || (c == kGaugeOff))) { _penX += 8; + } - } else { - switch (c) { - // Capitals, the health bar icons, and lower case m/w are all 2 chars wide - case 'm': - case 'w': - case 'M': - case 'W': - case 1: // Can't use the constant for this for some reason - case 0: - _penX += 8; - break; - case 'i': - _penX -= 3; - break; - case 'j': - case 't': - _penX -= 2; - break; - case 'l': - _penX -= 4; - default: - break; - } + switch (c) { + case 'i': + _penX -= 3; + break; + case 'j': + case 't': + _penX -= 2; + break; + case 'l': + _penX -= 4; + default: + break; } uint16 x = _penX + kScreenLeft; @@ -353,8 +423,15 @@ void ImmortalEngine::printChr(char c) { } superSprite(&_dataSprites[kFont], x, y, (int) c, kScreenBMW, _screenBuff, kSuperTop, kSuperBottom); - if ((c == 0x27) || (c == 'T')) { - _penX -= 2; // Why is this done twice?? + + // Single quote? + if (c == 0x27) { + _penX -= 2; + } + + // If the letter was a captial T, the next letter should be a little closer + if (c == 'T') { + _penX -= 2; } _penX += 8; @@ -368,181 +445,6 @@ void ImmortalEngine::printChr(char c) { * */ -void ImmortalEngine::initStoryStatic() { - Common::Array s{"#" + Common::String(kSwordBigFrame) + "sword@", - "You find an Elven sword of&agility. Take it?@", - "Search the bones?%", - "}The sword permanently endows you with Elven agility and quickness in combat.@", - "}You notice something that looks wet and green under the pile. Search further?%", - "#" + Common::String(kBagBigFrame) + " dust@" - "}You find a bag containing Dust of Complaisance.&@" - "}Drop the bait on the ground here?%" - "}To use this dust, you throw it in the air. Do that here?%" - "_}Don+t bother me, I+m cutting a gem. Yes, you need it. No, you can+t have it. I wouldn+t give it to anyone, least of all you. Go away. ]]]]=" - "_}Let me help you. Please take this gem. No, really, I insist. Take it and go with my blessings. Good luck. ]]]]=" - "#" + Common::String(kCarpetBigFrame) + "carpet@", - "#" + Common::String(kBombBigFrame) + " bomb@", - "A gas bomb that goblins&use to paralyze trolls.&@", - "Take it?<>@", - "%", - " other@", - "#" + Common::String(kKeyBigFrame) + " key@", - "#" + Common::String(kKeyBigFrame) + " key@", - "A key to a chest.&@", - "The chest is open. Examine&contents?%", - "Put it on?%", - "Drop it?%", - "It+s unlocked. Open it?%", - "It+s locked but you have&the key. Open it?%", - "It+s locked and you don+t&have the key.@", - "The lock, triggered by a&complicated set of latches,&is unfamiliar to you.@", - "#" + Common::String(kGoldBigFrame) + "$0 gold@", - "You find $0 gold pieces.&&^#" + Common::String(kPileFrame) + "@", - "@", - "You can+t plant them on&stone tiles.@", - "It+s locked but you are&able to unlock it with&the key.@", - "_}The king is not dead, but the poison is taking effect. When he sees you, he attempts to speak:[(Give me water... the fountain... I give you... information... peace...+[Give him water?%", - "_}You dont have any water to give him. He mumbles something. Then silence... You find a key on his body.]]]]=", - "_}He mumbles something. Then silence... You find a key on his body.]]]]=", - "_}I+ll tell you how to... next level... past slime... three jewels... slime... rock becomes... floor... right, left, center of the... [Then silence. His hand opens, releasing a key.]]]]=", - "You find a door key.&@", - "You find a note.&@", - "#" + Common::String(kNoteBigFrame) + "note@", - "He+s dead.&Look for possessions?%", - "You don+t have it. Check&your inventory.@", - "Game Over&&Play again?@", - "Congratulations!&&Play again?@", - "You find a bag of bait.&@", - "#" + Common::String(kBagBigFrame) + " bait@", - "You find a stone. @", - "#" + Common::String(kStoneBigFrame) + " stone@", - "You find a red gem.&@", - "#" + Common::String(kGemBigFrame) + " gem@", - "You find a scroll with&fireball spells.&@" - "#" + Common::String(kScrollBigFrame) + "$ shots@", - "You find a map warning&you about pit traps.&@" - "#" + Common::String(kMapBigFrame) + " map@", - "#" + Common::String(kVaseBigFrame) + " oil@", - "You apply the oil but notice&as you walk that the leather&is drying out quickly.@" - "}You discover a scroll with a charm spell to use on will o+ the wisps.&@" - "#" + Common::String(kScrollBigFrame) + " charm@", - "}This charms the will o+ the wisps to follow you. Read the spell again to turn them against your enemies.@" - "}It looks like water. Drink it?%", - "Drink it?%", - "}It works! You are much stronger.]]]=", - "}It looks like it has green stuff inside. Open it?%", - "Now this will take&effect when you press the&fire button.@", - "You find a potion,&Magic Muscle.&@", - "#" + Common::String(kVaseBigFrame) + " potion@", - "You find a bottle.&@", - "#" + Common::String(kVaseBigFrame) + " bottle@", - "#" + Common::String(kRingBigFrame) + "Protean@", - "You find a Protean Ring.&@", - "You find a troll ritual knife,&used to declare a fight to&the death. @", - "#" + Common::String(kKnifeBigFrame) + " knife@", - "_}It is a fine woman+s garment. Folded inside is a ring with the words,[`To Ana, so harm will never find you. -Your loving father, Dunric.+&@", - "You find a small, well&crafted ring. @", - "#" + Common::String(kRingBigFrame) + " gift@", - "#" + Common::String(kRingBigFrame) + " Ana+s@", - "_}She is hurt and upset when she finds you don+t have her ring or won+t give it to her. She scurries back into the hole. The hole is too small for you to follow.&@", - "_}`Sir, can you help me,+ the girl pleads. `I was kidnapped and dragged down here. All the man would say is `Mordamir+s orders.+[I escaped using a ring my father gave me, but now I+ve lost it. Did you find it?+%", - "_}We have met before, old man. Do you remember? Because you helped me, you may pass. But I warn you, we are at war with the trolls.[Over this ladder, across the spikes, is troll territory. Very dangerous.@", - "_}You are an impostor!]]]]=", - "_}Old man, do you remember me? I am king of the goblins. You didn+t give me the water. You left me to die after you took the key from me. Now you will pay.]]]]=", - "_}You quickly fall into a deep, healing sleep...[Vivid images of a beautiful enchanted city pass by. All the city people are young and glowing. Fountains fill the city, and the splash and sparkle of water is everywhere...[Suddenly the images go black. A face appears... Mordamir!]][He is different from how you remember him. His gentle features are now withered. His kind eyes, now cold and sunken, seem to look through you with a dark, penetrating stare. You wake rejuvenated, but disturbed.]]]]]=", - "_}Here, take this ring in return. [I don+t know if it will help, but I heard the unpleasant little dwarf say, (Clockwise, three rings around the triangle.+[Could that be a clue to his exit puzzle? I must go. Goodbye.]]]]=", - "#" + Common::String(kSackBigFrame) + " spores@", - "You find a sack of bad&smelling spores.&@", - "Please insert play disk.@", - "New game?%", - "Enter certificate:&-=", - "Invalid certificate.@", - "End of level!&Here is your certificate:&&=", - "&@", - " Electronic Arts presents&& The Immortal&&&&  1990 Will Harvey|]]]]]]]]]=", - " written by&& Will Harvey& Ian Gooding& Michael Marcantel& Brett G. Durrett& Douglas Fulton|]]]]]]]/=", - "_}Greetings, friend! Come, I+ve got something you need. These parts are plagued with slime.[You can+t venture safely without my slime oil for boots, a bargain at only 80 gold pieces.%", - "_}All right, 60 gold pieces for my oil. Rub it on your boots and slime won+t touch you. 60, friend.%", - "This room doesn+t resemble&any part of the map.@", - "This room resembles part&of the map.@"}; - _strPtrs = s; - - // Scope, amirite? - Common::Array cyc0{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,-1}; - Common::Array cyc1{15,16,17,18,19,20,21,22,-1}; - Common::Array cyc2{0,1,2,-1}; - Common::Array cyc3{3,4,5,-1}; - Common::Array cyc4{6,7,8,9,10,-1}; - Common::Array cyc5{11,12,13,14,15,-1}; - Common::Array cyc6{16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,-1}; - Common::Array cyc7{0,1,2,3,4,-1}; - Common::Array cyc8{5,1+5,2+5,3+5,4+5,-1}; - Common::Array cyc9{10,1+10,2+10,3+10,4+10,-1}; - Common::Array cyc10{15,1+15,2+15,3+15,4+15,-1}; - Common::Array cyc11{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,-1}; - Common::Array cyc12{0,1,2,3,4,5,6,7,8,9,-1}; - Common::Array cyc13{0,1,2,3, 0,1,2,3, 0,1,2,3, 0,1,2,3, 0,1,2,3, 0,1,2,3, 0,1,2,3, 0,1,2,3, -1}; - Common::Array cyc14{31,32,33,32, 34,35,36,35, 37,38,39,38, 40,41,42,41, 43,44,45,44, 46,47,48,47, 49,50,51,50, 52,53,54,53, -1}; - Common::Array cyc15{55, -1}; - Common::Array cyc16{63,64,65,66, 63,64,65,66, 63,64,65,66, 63,64,65,66, 63,64,65,66, 63,64,65,66, 63,64,65,66, 63,64,65,66,-1}; - Common::Array cyc17{0,1,0,-1}; - Common::Array cyc18{0,1,2,4,5,6,7,8,9,10,11,12,2,1,-1}; - Common::Array cyc19{0,0,1,2,13,14,15,16,4,2,3,-1}; - Common::Array cyc20{0,1,2,3,20,21,22,23,24,25,26,27,5,4,3,-1}; - Common::Array cyc21{0,1,2,3,-1}; - Common::Array cyc22{0,17,18,19,3,-1}; - Common::Array cyc23{0,1,-1}; - Common::Array cyc24{28,28,28,28,-1}; - Common::Array cyc25{15,16,15,16,15,1+15,1+15,-1}; - Common::Array cyc26{10+15,11+15,12+15,13+15,14+15,15+15,16+15,-1}; - Common::Array cyc27{2+15,3+15,4+15,5+15,-1}; - Common::Array cyc28{6+15,7+15,8+15,9+15,-1}; - Common::Array cyc29{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,-1}; - Common::Array cyc30{0,1,2,3,3,3,3,4,5,6,-1}; - Common::Array cyc31{0,1,2,3,4,5,6,7,8,-1}; - - Common::Array c{SCycle(kBubble, false, cyc0), SCycle(kBubble, false, cyc1), - SCycle(kSpark, false, cyc2), SCycle(kSpark, false, cyc3), - SCycle(kSpark, false, cyc4), SCycle(kSpark, false, cyc5), SCycle(kSpark, false, cyc6), - SCycle(kPipe, false, cyc7), SCycle(kPipe, false, cyc8), - SCycle(kPipe, false, cyc9), SCycle(kPipe, false, cyc10), - SCycle(kAnaVanish, false, cyc11), SCycle(kAnaGlimpse, false, cyc12), - SCycle(kKnife, true, cyc13), - SCycle(kSpark, true, cyc14), SCycle(kSpark, true, cyc15), SCycle(kSpark, true, cyc16), - SCycle(kBigBurst, false, cyc17), - SCycle(kFlame, false, cyc18), SCycle(kFlame, false, cyc19), SCycle(kFlame, false, cyc20), - SCycle(kFlame, false, cyc21), SCycle(kFlame, false, cyc22), SCycle(kFlame, false, cyc23), - SCycle(kFlame, false, cyc24), - SCycle(kCandle, false, cyc25), SCycle(kCandle, false, cyc26), SCycle(kCandle, false, cyc27), - SCycle(kCandle, false, cyc28), SCycle(kCandle, false, cyc29), - SCycle(kSink, false, cyc30), - SCycle(kNorlacDown, false, cyc31)}; - _cycPtrs = c; - - Common::Array m{}; - _motivePtrs = m; - - Common::Array d{}; - _damagePtrs = d; - - Common::Array u{}; - _usePtrs = u; - - Common::Array p{}; - _pickupPtrs = p; - - CArray2D pr{}; - _programPtrs = pr; - - Common::Array o{}; - _objTypePtrs = o; - -} - -void ImmortalEngine::kernalAddSprite(uint16 x, uint16 y, SpriteName n, int img, uint16 p) { - Utilities::addSprite(_sprites, _viewPortX, _viewPortY, &_numSprites, &_dataSprites[n], img, x, y, p); -} - void ImmortalEngine::clearSprites() { // Just sets the 'active' flag on all possible sprites to 0 for (int i = 0; i < kMaxSprites; i++) { @@ -557,6 +459,10 @@ void ImmortalEngine::cycleFreeAll() { } } +void ImmortalEngine::loadMazeGraphics(int m) { + //setColors(); +} + void ImmortalEngine::loadSprites() { /* This is a bit weird, so I'll explain. * In the source, this routine loads the files onto the heap, and then @@ -567,7 +473,7 @@ void ImmortalEngine::loadSprites() { * We aren't going to have the sprite properties inside the file data, so instead * we have an array of all game sprites _dataSprites which is indexed * soley by a sprite number now. This also means that a sprite itself has a reference to - * a datasprite, instead of the sprite index and separate the file pointer. Datasprite + * a datasprite, instead of the sprite index and separately the file pointer. Datasprite * is what needs the file, so that's where the pointer is. The index isn't used by * the sprite or datasprite themselves, so it isn't a member of either of them. */ @@ -621,9 +527,16 @@ void ImmortalEngine::loadSprites() { } void ImmortalEngine::loadWindow() { + /* Technically, the source uses loadIFF to just move the window bitmap from + * the file straight into the virtual screen buffer. However, since + * we will have to extract each pixel from the buffer to use with + * Surface anyway, we are doing the extracting in advance, since that is + * more or less what is happening at this point in the source. This will + * likely be combined with something else in the future. + */ + // Initialize the window bitmap Common::File f; - _window = new byte[kScreenSize]; if (f.open("WINDOWS.BM")) { @@ -640,8 +553,8 @@ void ImmortalEngine::loadWindow() { for (int x = 0; x < kResH; x += 2) { pos = (y * kResH) + x; pixel = f.readByte(); - _window[pos] = (pixel & kMask8High) >> 4; - _window[pos + 1] = pixel & kMask8Low; + _screenBuff[pos] = (pixel & kMask8High) >> 4; + _screenBuff[pos + 1] = pixel & kMask8Low; } } @@ -664,7 +577,7 @@ void ImmortalEngine::loadFont() { _dataSprites[kFont] = d; } else { - debug("file doesn't exit?!"); + debug("file doesn't exist?!"); } } @@ -774,12 +687,12 @@ void ImmortalEngine::setColors(uint16 pal[]) { void ImmortalEngine::fixColors() { // Pretty silly that this is done with two separate variables, could just index by one... - if (_dim == true) { - if (_usingNormal == true) { + if (_dim == 1) { + if (_usingNormal == 1) { useDim(); } } else { - if (_usingNormal == false) { + if (_usingNormal == 0) { useNormal(); } } @@ -789,13 +702,13 @@ void ImmortalEngine::pump() { // Flashes the screen (except the frame thankfully) white, black, white, black, then clears the screen and goes back to normal useWhite(); g_system->updateScreen(); - Immortal::Utilities::delay(2); + Utilities::delay(2); useBlack(); g_system->updateScreen(); - Immortal::Utilities::delay(2); + Utilities::delay(2); useWhite(); g_system->updateScreen(); - Immortal::Utilities::delay(2); + Utilities::delay(2); useBlack(); g_system->updateScreen(); clearScreen(); @@ -857,7 +770,7 @@ void ImmortalEngine::fade(uint16 pal[], int dir, int delay) { while ((count >= 0) && (count <= 256)) { fadePal(pal, count, target); - Immortal::Utilities::delay8(delay); + Utilities::delay8(delay); setColors(target); // Same as above, it was originally a branch, this does the same thing @@ -896,12 +809,12 @@ void ImmortalEngine::useWhite() { void ImmortalEngine::useNormal() { setColors(_palDefault); - _usingNormal = true; + _usingNormal = 1; } void ImmortalEngine::useDim() { setColors(_palDim); - _usingNormal = false; + _usingNormal = 0; } @@ -926,6 +839,19 @@ void ImmortalEngine::waitKey() { } } +// This was originally in Motives, which is weird since it seems more like an engine level function, so it's in kernal now +void ImmortalEngine::waitClick() { + bool wait = true; + while (wait == true) { + if (getInput() == true) { + Utilities::delay(25); + if (buttonPressed() || firePressed()) { + wait = false; + } + } + } +} + void ImmortalEngine::blit8() {} bool ImmortalEngine::getInput() { return true; @@ -1000,6 +926,10 @@ void ImmortalEngine::playMazeSong() { void ImmortalEngine::playCombatSong() { } +void ImmortalEngine::playTextSong() { + +} + void ImmortalEngine::loadSingles(Common::String songName) { debug("%s", songName.c_str()); } @@ -1010,6 +940,34 @@ void ImmortalEngine::stopMusic() { //stopSound(); } +/* + * + * ----- ----- + * ----- 'Pen' related Functions ----- + * ----- ----- + * + */ + +void ImmortalEngine::setPen(uint16 penX, uint16 penY) { + _penX = penX & kMaskLow; + if ((penY & kMaskLow) < 200) { + _penY = penY & kMaskLow; + } + + else { + _penY = penY | kMaskHigh; + } +} + +void ImmortalEngine::center() { + _penX = ((uint16) 128) - (kObjectWidth / 2); +} + +void ImmortalEngine::carriageReturn() { + _penY += 16; + _penX = kTextLeft; +} + } // namespace Immortal diff --git a/engines/immortal/logic.cpp b/engines/immortal/logic.cpp index 97319375a066..0a0c93119158 100644 --- a/engines/immortal/logic.cpp +++ b/engines/immortal/logic.cpp @@ -99,7 +99,7 @@ void ImmortalEngine::logic() { _levelOver = false; if (_level == (_maxLevels-1)) { - textPrint(kStrYouWin); + textPrint(kStrYouWin, 0); } else { makeCertificate(); @@ -201,18 +201,6 @@ void ImmortalEngine::doSingleStep() { } } -void ImmortalEngine::setPen(uint16 penX, uint16 penY) { - _penX = penX & kMaskLow; - // Is this screen wrap? - if ((penY & kMaskLow) < 200) { - _penY = penY & kMaskLow; - } - - else { - _penY = penY | kMaskHigh; - } -} - void ImmortalEngine::updateHitGauge() { /* This HUD (essentially) drawing routine is a bit weird because * the game was originally meant to have multiple player characters @@ -250,8 +238,6 @@ void ImmortalEngine::drawGauge(int h) { */ int r = 16 - h; setPen(kGaugeX, kGaugeY); - // Temporary x value, until it's clear why printchr is designed to add 8 pixels *before* drawing the char - _penX = 0xFFF0; h--; if (h >= 0) { // This could be written as a regular for loop, but the game thinks of start/stop as different from on @@ -277,7 +263,7 @@ void ImmortalEngine::drawGauge(int h) { bool ImmortalEngine::printAnd(Str s) { // Only ever used by fromOldGame() // Just prints what it's given and then checks for input - textPrint(s); + textPrint(s, 0); getInput(); if (_heldAction != kActionNothing) { return true; @@ -307,7 +293,7 @@ bool ImmortalEngine::fromOldGame() { } else { do { - if (!textPrint(kStrOldGame)) { + if (!textPrint(kStrOldGame, 0)) { // They choose not to load an old game return false; } @@ -511,7 +497,7 @@ void ImmortalEngine::calcCheckSum(int l, uint8 checksum[]) { } bool ImmortalEngine::getCertificate() { - textPrint(kStrCert); + textPrint(kStrCert, 0); int certLen = 0; bool entered = false; int k = 0; @@ -575,14 +561,14 @@ bool ImmortalEngine::getCertificate() { } if (certLen != 0) { if (certLen < 4) { - textPrint(kStrBadCertificate); + textPrint(kStrBadCertificate, 0); return false; } uint8 checksum[4]; calcCheckSum(certLen, checksum); for (int i = 0; i < 4; i++) { if (checksum[i] != _certificate[i]) { - textPrint(kStrBadCertificate); + textPrint(kStrBadCertificate, 0); return false; } } @@ -603,11 +589,11 @@ void ImmortalEngine::printCertificate() { */ char toHex[] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}; - textBeginning(kStrCert); + textBeginning(kStrCert, 0); for (int i = 0; i < _lastCertLen; i++) { printChr(toHex[_certificate[i]]); } - textEnd(kStrCert2); + textEnd(kStrCert2, 0); } bool ImmortalEngine::isSavedKing() { @@ -645,7 +631,7 @@ int ImmortalEngine::getLevel() { void ImmortalEngine::gameOverDisplay() { _themePaused = true; - textPrint(kStrGameOver); + textPrint(kStrGameOver, 0); } void ImmortalEngine::gameOver() { diff --git a/engines/immortal/misc.cpp b/engines/immortal/misc.cpp index 2eb393c2265b..450380b51c6d 100644 --- a/engines/immortal/misc.cpp +++ b/engines/immortal/misc.cpp @@ -38,8 +38,6 @@ void ImmortalEngine::miscInit() { void ImmortalEngine::setRandomSeed() {} void ImmortalEngine::getRandom() {} -void ImmortalEngine::myDelay() {} - /* * @@ -49,15 +47,357 @@ void ImmortalEngine::myDelay() {} * */ -bool ImmortalEngine::textPrint(Str s) { - return true; +// myFadeOut and myFadeIn are just RTS in the source, but they are called quite a lot +void ImmortalEngine::myFadeOut() { + return; +} + +void ImmortalEngine::myFadeIn() { + return; +} + +bool ImmortalEngine::textPrint(Str s, int n) { + _slowText = 0; + _formatted = 0; + _collumn = 0; + _row = 0; + playTextSong(); + clearScreen(); + return textSub(s, kTextFadeIn, n); +} + +bool ImmortalEngine::textBeginning(Str s, int n) { + _slowText = 0; + _formatted = 0; + _collumn = 0; + _row = 0; + playTextSong(); + clearScreen(); + return textSub(s, kTextDontFadeIn, n); +} + +void ImmortalEngine::textEnd(Str s, int n) { + textSub(s, kTextFadeIn, n); +} + +void ImmortalEngine::textMiddle(Str s, int n) { + textSub(s, kTextDontFadeIn, n); } -void ImmortalEngine::textSub() {} -void ImmortalEngine::textEnd(Str s) {} -void ImmortalEngine::textMiddle(Str s) {} -void ImmortalEngine::textBeginning(Str s) {} -void ImmortalEngine::yesNo() {} +bool ImmortalEngine::textSub(Str s, FadeType f, int n) { + bool done = false; + + char chr = 0; + int index = 0; + Common::String text = _strPtrs[s]; + + while (done == false) { + switch (text[index]) { + case '@': + case '=': + case char(0): + done = true; + // This is so the while loop can be a little cleaner + index--; + break; + case '&': + textCR(); + break; + case '$': + printByte(n); + copyToScreen(); + break; + case '_': + myFadeIn(); + _slowText = 1; + break; + case '<': + _slowText = 0; + break; + case '>': + _formatted = 0; + break; + case '\\': + normalFadeOut(); + break; + case '/': + slowFadeOut(); + break; + case '|': + normalFadeIn(); + break; + case '}': + _formatted = 1; + break; + case ']': + myDelay(40); + break; + case '{': + index++; + myDelay(text[index]); + break; + case '*': + textPageBreak(text, index); + break; + case '[': + textAutoPageBreak(); + break; + case '#': + index++; + drawIcon(text[index]); + break; + case '~': + text = _strPtrs[(int)text[index + 1]]; + index = -1; + break; + case '^': + center(); + break; + case '%': + return yesNo(); + case '+': + chr = 0x27; + break; + case '(': + chr = 0x60; + break; + default: + chr = text[index]; + _collumn++; + if (chr == ' ') { + if (text[index + 1] == '~') { + text = _strPtrs[(int)text[index + 2]]; + index = -1; + } + textDoSpace(text, index); + + } else { + printChr(chr); + // We need this to show up now, not when the frame ends, so we have to update the screen here + copyToScreen(); + if (_slowText != 0) { + myDelay(5); + switch (chr) { + case '?': + case ':': + myDelay(13); + case '.': + myDelay(13); + case ',': + myDelay(13); + default: + break; + } + } + } + break; + } + if (index == 0xFF) { + debug("String too long!"); + return false; + } + index++; + } + + //debug("printing index: %d", index); + + chr = text[index]; + + if (f != kTextFadeIn) { + return false; + } + + // If we need to display an 'OK' message + if (chr != '=') { + setPen(_penX, kYesNoY); + center(); + drawIcon(kOkayFrame); + copyToScreen(); + if (_slowText == 0) { + myFadeIn(); + } + waitClick(); + standardBeep(); + textBounceDelay(); + + } else if (_slowText == 0) { + myFadeIn(); + } + + return false; +} + +void ImmortalEngine::textCR() { + carriageReturn(); + _row++; + _collumn = 0; +} + +void ImmortalEngine::textPageBreak(Common::String s, int &index) { + _collumn = 0; + _row = 0; + if (_slowText == 0) { + myFadeIn(); + } + + index++; + myDelay((int) s[index]); + myFadeOut(); + clearScreen(); + + if (_slowText != 0) { + myFadeIn(); + } +} + +void ImmortalEngine::textAutoPageBreak() { + _collumn = 0; + _row = 0; + if (_slowText == 0) { + myFadeIn(); + } + + myDelay(140); + myFadeOut(); + clearScreen(); + + if (_slowText != 0) { + myFadeIn(); + } +} + +void ImmortalEngine::textDoSpace(Common::String s, int index) { + // If text is formatted, then check if the space between here and the end of the string will fit, if not, use a newline or pagebreak + if (_formatted != 0) { + bool foundEnd = false; + int start = index; + while (foundEnd == false) { + index++; + switch (s[index]) { + case '=': + case '@': + case '%': + case '[': + case ' ': + foundEnd = true; + default: + break; + } + } + if (((index - start) + _collumn) >= kMaxCollumns) { + if (_row < kMaxRows) { + textCR(); + + } else { + textAutoPageBreak(); + } + return; + } + } + printChr(' '); +} + +void ImmortalEngine::textBounceDelay() { + Utilities::delay(7); +} + +bool ImmortalEngine::yesNo() { + uint8 tyes[9] = {0, 1, 1, 1, 0, 0, 0, 0, 0}; + + getInput(); + + if (tyes[_heldDirection] == 0) { + noOn(); + _lastYes = 0; + + } else { + yesOn(); + _lastYes = 1; + } + + while (buttonPressed() || firePressed()) { + // If they have not pressed a button yet, we get the input after a delay + Utilities::delay(4); + getInput(); + + // And then if they have changed direction, we play a sound and update the direction and button gfx + if (tyes[_heldDirection] != _lastYes) { + _lastYes = tyes[_heldDirection]; + standardBeep(); + if (_lastYes == 0) { + noOn(); + + } else { + yesOn(); + } + // Since we need this to show up right during the text sequence, we need to update the screen + copyToScreen(); + } + } + + standardBeep(); + textBounceDelay(); + + // In source this is done weirdly so that it can use a result in A, except it never uses that result, so it's just weird. + return (!(bool) _lastYes); +} + +void ImmortalEngine::noOn() { + // Draw the No icon as on, and the Yes icon as off + setPen(kYesNoX1, kYesNoY); + drawIcon(kNoIconOn); + setPen(kYesNoX2, kYesNoY); + drawIcon(kYesIconOff); +} + +void ImmortalEngine::yesOn() { + // Draw the No icon as off, and the Yes icon as on + setPen(kYesNoX1, kYesNoY); + drawIcon(kNoIconOff); + setPen(kYesNoX2, kYesNoY); + drawIcon(kYesIconOn); +} + +void ImmortalEngine::myDelay(int j) { + int type = 0; + + // Update input + getInput(); + + // 0 = neither button held, 1 = one held, 2 = both held + if (_heldAction & kActionButton) { + type++; + } + + if (_heldAction & kActionFire) { + type++; + } + + do { + // If the button was *pressed* and not held, then skip any delay + if (!buttonPressed()) { + return; + } + + if (!firePressed()) { + return; + } + + // Otherwise, we delay by different amounts based on what's held down + switch (type) { + case 1: + Utilities::delay4(1); + break; + case 0: + Utilities::delay(1); + case 2: + default: + break; + } + + j--; + } while (j != 0); +} /* * @@ -67,8 +407,36 @@ void ImmortalEngine::yesNo() {} * */ -void ImmortalEngine::buttonPressed() {} -void ImmortalEngine::firePressed() {} +bool ImmortalEngine::buttonPressed() { + // Returns false if the button was pressed, but not held or up + getInput(); + + if (_heldAction == kActionButton) { + // Zero just the button0held bit + _myButton &= (0xFF - kButton0Held); + + } else if ((_myButton & kButton0Held) == 0) { + _myButton |= kButton0Held; + return false; + } + + return true; +} + +bool ImmortalEngine::firePressed() { + // Returns false if the button was pressed, but not held or up + getInput(); + + if (_heldAction == kActionFire) { + _myButton &= (0xFF - kButton1Held); + + } else if ((_myButton & kButton1Held) == 0) { + _myButton |= kButton1Held; + return false; + } + + return true; +} /* @@ -79,6 +447,19 @@ void ImmortalEngine::firePressed() {} * */ + +/* + * + * ----- ----- + * ----- Sound Related ----- + * ----- ----- + * + */ + +void ImmortalEngine::standardBeep() { + //playNote(4, 5, 0x4C); +} + } // namespace Immortal From d47efc743b9f6cda805d185f1a7f16342c5464b5 Mon Sep 17 00:00:00 2001 From: Quote58 Date: Mon, 26 Sep 2022 01:28:17 -0400 Subject: [PATCH 358/412] IMMORTAL: Preliminary loadMazeGraphics() and loadUniv() functions --- engines/immortal/kernal.cpp | 72 ++++++++++++++++++++++--------------- 1 file changed, 43 insertions(+), 29 deletions(-) diff --git a/engines/immortal/kernal.cpp b/engines/immortal/kernal.cpp index 643ee8508784..97a898771db6 100644 --- a/engines/immortal/kernal.cpp +++ b/engines/immortal/kernal.cpp @@ -87,15 +87,18 @@ void ImmortalEngine::clearScreen() { useNormal(); } + // Make sure it takes effect right away copyToScreen(); } +// These functions are not yet implemented void ImmortalEngine::mungeBM() {} void ImmortalEngine::blit() {} void ImmortalEngine::blit40() {} void ImmortalEngine::sBlit() {} void ImmortalEngine::scroll() {} -void ImmortalEngine::makeMyCNM() {} // ? +void ImmortalEngine::makeMyCNM() {} +// ----- void ImmortalEngine::drawIcon(int img) { superSprite(&_dataSprites[kObject], ((kObjectWidth / 2) + kScreenLeft) + _penX, _penY + (kObjectY + kScreenTop), img, kScreenBMW, _screenBuff, 0, 200); @@ -150,6 +153,7 @@ void ImmortalEngine::addSprites() { int tmpNum = _num2DrawItems; for (int i = 0; i < kMaxSprites; i++) { // If the sprite is active + // This is commented out for testing until the issue with the function is resolved if (/*_sprites[i]._on*/0 == 1) { // If sprite X is an odd number??? if ((_sprites[i]._X & 1) != 0) { @@ -176,7 +180,7 @@ void ImmortalEngine::addSprites() { } DataSprite *tempD = _sprites[i]._dSprite; - debug("what sprite is this: %d %d %d", i, _sprites[i]._image, _sprites[i]._dSprite->_images.size()); + //debug("what sprite is this: %d %d %d", i, _sprites[i]._image, _sprites[i]._dSprite->_images.size()); Image *tempImg = &(tempD->_images[_sprites[i]._image]); int sx = ((_sprites[i]._X + tempImg->_deltaX) - tempD->_cenX) - _myViewPortX; int sy = ((_sprites[i]._Y + tempImg->_deltaY) - tempD->_cenY) - _myViewPortY; @@ -211,7 +215,7 @@ void ImmortalEngine::addSprites() { void ImmortalEngine::sortDrawItems() { /* Just an implementation of bubble sort. - * Sorting largest to smallest entry, simply + * Sorting largest to smallest entry, by simply * swapping every two entries if they are not in order. */ @@ -333,11 +337,11 @@ void ImmortalEngine::drawItems() { } void ImmortalEngine::backspace() { - // Just moves the drawing position back by a char, and then draws an empty rect there (I think) + // Just moves the drawing position back by a char, and then draws an empty rect there _penX -= 8; //rect(_penX + 32, 40, 8, 16, 0); - // The Y is set here presumably because it's only used for the certificate + // The Y is hardcoded here presumably because it's only used for the certificate for (int y = 0; y < 16; y++) { for (int x = 0; x < 8; x++) { _screenBuff[((y + 40) * kResH) + (x + (_penX + 32))] = 0; @@ -424,7 +428,7 @@ void ImmortalEngine::printChr(char c) { superSprite(&_dataSprites[kFont], x, y, (int) c, kScreenBMW, _screenBuff, kSuperTop, kSuperBottom); - // Single quote? + // Back tick quote if (c == 0x27) { _penX -= 2; } @@ -460,7 +464,19 @@ void ImmortalEngine::cycleFreeAll() { } void ImmortalEngine::loadMazeGraphics(int m) { - //setColors(); + char mazeNum = m + '0'; + loadUniv(mazeNum); + setColors(_palUniv); +} + +void ImmortalEngine::loadUniv(char mazeNum) { + Common::String sCNM = "MAZE" + Common::String(mazeNum) + ".CNM"; + Common::SeekableReadStream *mazeCNM = loadIFF(sCNM); + debug("Size of maze CNM: %ld", mazeCNM->size()); + + Common::String sUNV = "MAZE" + Common::String(mazeNum) + ".UNV"; + Common::SeekableReadStream *mazeUNV = loadIFF(sUNV); + debug("Size of maze UNV: %ld", mazeUNV->size()); } void ImmortalEngine::loadSprites() { @@ -562,7 +578,7 @@ void ImmortalEngine::loadWindow() { f.close(); } else { - // Should probably give an error or something here + // Should probably give an error here debug("oh nose :("); } } @@ -577,7 +593,7 @@ void ImmortalEngine::loadFont() { _dataSprites[kFont] = d; } else { - debug("file doesn't exist?!"); + debug("file doesn't exist!"); } } @@ -726,9 +742,9 @@ void ImmortalEngine::fadePal(uint16 pal[], int count, uint16 target[]) { * kept, this is a direct translation of the bit manipulation sequence. */ uint16 maskPal[16] = {0xFFFF, 0x0000, 0x0000, 0x0000, - 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, - 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, - 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF}; + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF}; uint16 result; uint16 temp; @@ -826,10 +842,6 @@ void ImmortalEngine::useDim() { * */ -void ImmortalEngine::userIO() {} -void ImmortalEngine::pollKeys() {} -void ImmortalEngine::noNetwork() {} - void ImmortalEngine::waitKey() { bool wait = true; while (wait == true) { @@ -852,14 +864,17 @@ void ImmortalEngine::waitClick() { } } +// These functions are not yet implemented void ImmortalEngine::blit8() {} +void ImmortalEngine::addKeyBuffer() {} +void ImmortalEngine::clearKeyBuff() {} +void ImmortalEngine::userIO() {} +void ImmortalEngine::pollKeys() {} +void ImmortalEngine::noNetwork() {} bool ImmortalEngine::getInput() { return true; } - -void ImmortalEngine::addKeyBuffer() {} -void ImmortalEngine::clearKeyBuff() {} - +// ---- /* * @@ -917,18 +932,15 @@ void ImmortalEngine::musicUnPause(int sID) {} // *** Song ImmortalEngine::getPlaying() { + // Temporary value return kSongMaze; } -void ImmortalEngine::playMazeSong() { -} - -void ImmortalEngine::playCombatSong() { -} - -void ImmortalEngine::playTextSong() { - -} +// These functions are not yet implemented +void ImmortalEngine::playMazeSong() {} +void ImmortalEngine::playCombatSong() {} +void ImmortalEngine::playTextSong() {} +// ---- void ImmortalEngine::loadSingles(Common::String songName) { debug("%s", songName.c_str()); @@ -948,6 +960,7 @@ void ImmortalEngine::stopMusic() { * */ +// This sets the pen to a given x,y point void ImmortalEngine::setPen(uint16 penX, uint16 penY) { _penX = penX & kMaskLow; if ((penY & kMaskLow) < 200) { @@ -963,6 +976,7 @@ void ImmortalEngine::center() { _penX = ((uint16) 128) - (kObjectWidth / 2); } +// Reset the X position and move the Y position down by 16 pixels void ImmortalEngine::carriageReturn() { _penY += 16; _penX = kTextLeft; From a188dced1516eeec2bab993050e0f8bf4bf41d46 Mon Sep 17 00:00:00 2001 From: Quote58 Date: Mon, 26 Sep 2022 01:31:35 -0400 Subject: [PATCH 359/412] IMMORTAL: Formatting and comment adjustments across all several files --- engines/immortal/cycle.cpp | 3 +- engines/immortal/disk.cpp | 7 +- engines/immortal/disk.h | 24 ++--- engines/immortal/door.cpp | 49 ++++++----- engines/immortal/drawChr.cpp | 2 + engines/immortal/flameSet.cpp | 5 +- engines/immortal/immortal.cpp | 13 ++- engines/immortal/immortal.h | 58 ++++++------ engines/immortal/level.cpp | 2 +- engines/immortal/logic.cpp | 7 +- engines/immortal/misc.cpp | 4 +- engines/immortal/module.mk | 4 +- engines/immortal/room.h | 37 ++++---- engines/immortal/sprite_list.h | 12 +-- engines/immortal/sprites.cpp | 16 ++-- engines/immortal/story.cpp | 52 ++++++----- engines/immortal/story.h | 156 +++++++++++++++++---------------- engines/immortal/utilities.cpp | 4 +- 18 files changed, 238 insertions(+), 217 deletions(-) diff --git a/engines/immortal/cycle.cpp b/engines/immortal/cycle.cpp index bec8a6eba796..7d505a7a0fce 100644 --- a/engines/immortal/cycle.cpp +++ b/engines/immortal/cycle.cpp @@ -88,12 +88,11 @@ int Room::cycleGetFrame(int c) { * This is essentially self-modifying code, and it saves 2 bytes of DP memory over the traditional * STA DP : LDA (DP) */ - //debug("%d", _cycPtrs[_cycles[c]._cycList]._frames[_cycles[c]._index]); return g_immortal->_cycPtrs[g_immortal->_cycles[c]._cycList]._frames[g_immortal->_cycles[c]._index]; } int Room::cycleGetNumFrames(int c) { - // Why in the world is this not kept as a property of the cycle? We have to calculate the size of the array each time + // For whatever reason, this is not a property of the cycle, so it has to be re-calculated each time int index = 0; while (g_immortal->_cycPtrs[g_immortal->_cycles[c]._cycList]._frames[index] != -1) { index++; diff --git a/engines/immortal/disk.cpp b/engines/immortal/disk.cpp index 340a07d409ec..be6103e6c30c 100644 --- a/engines/immortal/disk.cpp +++ b/engines/immortal/disk.cpp @@ -295,7 +295,7 @@ void ProDOSDisk::searchDirectory(DirHeader *h, uint16 p, uint16 n, Common::Strin // It is a regular file if (dead < file type < pascal) and the file has a size if ((kFileTypeDead < fileEntry._type) && (fileEntry._type < kFileTypePascal) && (fileEntry._eof > 0)) { Common::String fileName = path + fileEntry._name; - debug("%s", fileName.c_str()); + //debug("%s", fileName.c_str()); ProDOSFile *currFile = new ProDOSFile(fileEntry._name, fileEntry._type, fileEntry._totalBlocks, fileEntry._eof, fileEntry._blockPtr, &_disk); _files.setVal(fileName, Common::SharedPtr(currFile)); @@ -305,7 +305,7 @@ void ProDOSDisk::searchDirectory(DirHeader *h, uint16 p, uint16 n, Common::Strin } else if (fileEntry._type == kFileTypeSubDir) { _disk.seek(fileEntry._blockPtr * kBlockSize); - debug("--- diving into a subdirectory ---"); + //debug("--- diving into a subdirectory ---"); uint16 subP = _disk.readUint16LE(); uint16 subN = _disk.readUint16LE(); @@ -316,7 +316,7 @@ void ProDOSDisk::searchDirectory(DirHeader *h, uint16 p, uint16 n, Common::Strin Common::String subPath = Common::String(path + subHead._name + '/'); searchDirectory(&subHead, subP, subN, path); - debug("--- surfacing to parent directory ---"); + //debug("--- surfacing to parent directory ---"); _disk.seek(currPos); } } @@ -425,7 +425,6 @@ Common::SeekableReadStream *ProDOSDisk::createReadStreamForMember(const Common:: return nullptr; } Common::SharedPtr f = _files.getValOrDefault(name); - f->printInfo(); return f->createReadStream(); } diff --git a/engines/immortal/disk.h b/engines/immortal/disk.h index 2d581c969c4a..57c057a8eb2c 100644 --- a/engines/immortal/disk.h +++ b/engines/immortal/disk.h @@ -95,12 +95,12 @@ class ProDOSFile : public Common::ArchiveMember { void printInfo(); private: - char _name[16]; - uint8 _type; // As defined by enum FileType - uint16 _blockPtr; // Block index in volume of index block or data - uint16 _totalBlocks; - uint32 _eof; // End Of File, used generally as size (exception being sparse files) -Common::File *_disk; // This is a pointer because it is the same _disk as in ProDosDisk, passed to the file object + char _name[16]; + uint8 _type; // As defined by enum FileType + uint16 _blockPtr; // Block index in volume of index block or data + uint16 _totalBlocks; + uint32 _eof; // End Of File, used generally as size (exception being sparse files) + Common::File *_disk; // This is a pointer because it is the same _disk as in ProDosDisk, passed to the file object }; /* This class defines the entire disk volume. Upon using the open() method, @@ -126,12 +126,12 @@ class ProDOSDisk : public Common::Archive { Common::SeekableReadStream *createReadStreamForMember(const Common::Path &path) const override; private: - byte _loader1[kBlockSize]; // There's not much reason for these to be needed, but I included them just in case - byte _loader2[kBlockSize]; -Common::String _name; // Name of volume - Common::File _disk; // The volume file itself - int _volBlocks; // Total blocks in volume - byte *_volBitmap; // This can determine if the volume is corrupt as it contains a bit for every block, where 0 = unused, 1 = used + byte _loader1[kBlockSize]; // There's not much reason for these to be needed, but I included them just in case + byte _loader2[kBlockSize]; +Common::String _name; // Name of volume + Common::File _disk; // The volume file itself + int _volBlocks; // Total blocks in volume + byte *_volBitmap; // This can determine if the volume is corrupt as it contains a bit for every block, where 0 = unused, 1 = used Common::HashMap> _files; // Hashmap of files in the volume, where key=Path, Value=ProDOSFile struct Date { diff --git a/engines/immortal/door.cpp b/engines/immortal/door.cpp index a97820658bcc..ee905d84e98d 100644 --- a/engines/immortal/door.cpp +++ b/engines/immortal/door.cpp @@ -20,7 +20,6 @@ */ /* [Alternate Name: Door Processing] - * --- What is a Door --- */ #include "immortal/immortal.h" @@ -28,10 +27,10 @@ namespace Immortal { enum DoorMask { - kDoorXMask = 0x1f, // Only relevant for extracting the data from the compressed bytes in the story record - kDoorYMask = 0x1f, + kDoorXMask = 0x1f, // Only relevant for extracting the data from the compressed bytes in the story record + kDoorYMask = 0x1f, kDoorFullMask = 0x40, - kDoorOnMask = 0x60 + kDoorOnMask = 0x60 }; enum DoorIs { @@ -50,10 +49,6 @@ enum DoorSide { kDoorTopBottom = 20 }; -void ImmortalEngine::doorOpenSecret() {} -void ImmortalEngine::doorCloseSecret() {} -void ImmortalEngine::doorInit() {} -void ImmortalEngine::doorClrLock() {} void ImmortalEngine::doorNew(SDoor door) { Door d; d._x = door._x; @@ -65,32 +60,46 @@ void ImmortalEngine::doorNew(SDoor door) { _doors.push_back(d); } -void ImmortalEngine::doorDrawAll() {} -void ImmortalEngine::doorOnDoorMat() {} - int ImmortalEngine::findDoorTop(int x, int y) { + +int ImmortalEngine::findDoorTop(int x, int y) { return 0; - } - int ImmortalEngine::findDoor(int x, int y) { +} + +int ImmortalEngine::findDoor(int x, int y) { return 0; - } +} + bool ImmortalEngine::doLockStuff(int d, MonsterID m, int top) { return true; } + bool ImmortalEngine::inDoorTop(int x, int y, MonsterID m) { return true; } + bool ImmortalEngine::inDoor(int x, int y, MonsterID m) { return true; } - int ImmortalEngine::doorDoStep(MonsterID m, int d, int index) { + +int ImmortalEngine::doorDoStep(MonsterID m, int d, int index) { return 0; - } - int ImmortalEngine::doorSetOn(int d) { +} + +int ImmortalEngine::doorSetOn(int d) { return 0; - } - int ImmortalEngine::doorComeOut(MonsterID m) { +} + +int ImmortalEngine::doorComeOut(MonsterID m) { return 0; - } +} + +// These functions are not yet implemented void ImmortalEngine::doorSetLadders(MonsterID m) {} +void ImmortalEngine::doorDrawAll() {} +void ImmortalEngine::doorOnDoorMat() {} +void ImmortalEngine::doorOpenSecret() {} +void ImmortalEngine::doorCloseSecret() {} +void ImmortalEngine::doorInit() {} +void ImmortalEngine::doorClrLock() {} } // namespace immortal \ No newline at end of file diff --git a/engines/immortal/drawChr.cpp b/engines/immortal/drawChr.cpp index 7ef77391543b..9a8b8e711ccf 100644 --- a/engines/immortal/drawChr.cpp +++ b/engines/immortal/drawChr.cpp @@ -23,9 +23,11 @@ namespace Immortal { +// These functions are not yet implemented int ImmortalEngine::mungeCBM(int numChrs) { return 0; } + void ImmortalEngine::storeAddr() {} void ImmortalEngine::mungeSolid() {} void ImmortalEngine::mungeLRHC() {} diff --git a/engines/immortal/flameSet.cpp b/engines/immortal/flameSet.cpp index 32e973c0734f..89732a91fde1 100644 --- a/engines/immortal/flameSet.cpp +++ b/engines/immortal/flameSet.cpp @@ -47,6 +47,7 @@ void Room::flameFreeAll() { void Room::flameDrawAll(uint16 vX, uint16 vY) { for (int i = 0; i < _fset.size(); i++) { + // For every flame in the room, add the sprite to the sprite table univAddSprite(vX, vY, _fset[i]._x, _fset[i]._y, g_immortal->_cycPtrs[g_immortal->_cycles[_fset[i]._c]._cycList]._sName, cycleGetFrame(_fset[i]._c), 0); if (cycleAdvance(_fset[i]._c) == true) { cycleFree(_fset[i]._c); @@ -56,7 +57,7 @@ void Room::flameDrawAll(uint16 vX, uint16 vY) { } bool Room::roomLighted() { - // Just for now, we say it's always lit + // For testing purposes, we say it's always lit return true; // Very simple, just checks every torch and if any of them are lit, we say the room is lit @@ -94,7 +95,7 @@ void Room::flameSetRoom(Common::Array allFlames) { f._x = allFlames[i]._x; f._y = allFlames[i]._y; f._c = flameGetCyc(&f, (0 | _candleTmp)); - debug("made flame, cyc = %d", f._c); + //debug("made flame, cyc = %d", f._c); _fset.push_back(f); } _candleTmp = 1; diff --git a/engines/immortal/immortal.cpp b/engines/immortal/immortal.cpp index e3ce80031edc..a47301a3cf25 100644 --- a/engines/immortal/immortal.cpp +++ b/engines/immortal/immortal.cpp @@ -55,16 +55,15 @@ uint16 ImmortalEngine::xba(uint16 ab) { /* XBA in 65816 swaps the low and high bits of a given word in A. * This is used very frequently, so this function just makes * initial translation a little more straightforward. Eventually, - * logic should be refactored to not require this. + * code should be refactored to not require this. */ return ((ab & kMaskLow) << 8) | ((ab & kMaskHigh) >> 8); } uint16 ImmortalEngine::rol(uint16 ab, int n) { - /* Oops, another opcode that doesn't have a nice translation. - * This just replicates bit rotation because apparently C - * doesn't have this natively??? This assumes a 16 bit - * unsigned int because that's all we need for the 65816. + /* This just replicates bit rotation, and it + * assumes a 16 bit unsigned int because that's all + * we need for the 65816. */ return (ab << n) | (ab >> (-n & 15)); } @@ -150,7 +149,7 @@ Common::Error ImmortalEngine::run() { return Common::kPathDoesNotExist; } - //Main: + // Main: _zero = 0; _draw = 1; _usingNormal = 1; @@ -163,7 +162,7 @@ Common::Error ImmortalEngine::run() { // This is the equivalent of Main->InitGraphics->MyClearScreen in Driver useNormal(); // The first palette will be the default - loadFont(); // Load the font sprite + loadFont(); // Load the font sprites loadWindow(); // Load the window background loadSingles("Song A"); // Music loadSprites(); // Get all the sprite data into memory diff --git a/engines/immortal/immortal.h b/engines/immortal/immortal.h index fce55cf9ea6b..7ff63fc75915 100644 --- a/engines/immortal/immortal.h +++ b/engines/immortal/immortal.h @@ -226,9 +226,9 @@ class ImmortalEngine : public Engine { const uint16 kLCutaway = 4; const uint16 kChrDy[19] = {kChr0, kChrH, kChrH2, kChrH, kChrH2, - kChrH2, kChrH, kChrH2, kChrH2, kChr0, - kChr0, kChrH2, kChrH, kChrH2, kChrH2, - kChrH2, kChrH, kChrH2, kChrH2}; + kChrH2, kChrH, kChrH2, kChrH2, kChr0, + kChr0, kChrH2, kChrH, kChrH2, kChrH2, + kChrH2, kChrH, kChrH2, kChrH2}; const uint16 kChrMask[19] = {kChr0, kChr0, kChr0, kChr0, kChrR, kChrL, kChr0, kChrL, @@ -240,8 +240,8 @@ class ImmortalEngine : public Engine { 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0}; + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0}; // Disk offsets const int kPaletteOffset = 21205; // This is the byte position of the palette data in the disk @@ -347,7 +347,7 @@ class ImmortalEngine : public Engine { uint8 _secretDelta = 0; // Debug members - bool _singleStep = false; // Flag for _singleStep mode + bool _singleStep = false; // Flag for _singleStep mode // Input members int _pressedAction = 0; @@ -365,11 +365,11 @@ class ImmortalEngine : public Engine { // Music members Song _playing; // Currently playing song - int _themeID = 0; // Not sure yet tbh - int _combatID = 0; + int _themeID = 0; // Not sure yet tbh + int _combatID = 0; // Asset members - int _numSprites = 0; // This is more accurately actually the index within the sprite array, so _numSprites + 1 is the current number of sprites + int _numSprites = 0; // This is more accurately actually the index within the sprite array, so _numSprites + 1 is the current number of sprites DataSprite _dataSprites[kFont + 1]; // All the sprite data, indexed by SpriteName Sprite _sprites[kMaxSprites]; // All the sprites shown on screen Cycle _cycles[kMaxCycles]; @@ -384,27 +384,27 @@ class ImmortalEngine : public Engine { // Screen members byte *_screenBuff; // The final buffer that will transfer to the screen - uint16 _myCNM[(kViewPortCW + 1)][(kViewPortCH + 1)]; - uint16 _myModCNM[(kViewPortCW + 1)][(kViewPortCH + 1)]; - uint16 _myModLCNM[(kViewPortCW + 1)][(kViewPortCH + 1)]; - uint16 _columnX[kViewPortCW + 1]; - uint16 _columnTop[kViewPortCW + 1]; - uint16 _columnIndex[kViewPortCW + 1]; // Why the heck is this an entire array, when it's just an index that gets zeroed before it gets used anyway... + uint16 _myCNM[(kViewPortCW + 1)][(kViewPortCH + 1)]; + uint16 _myModCNM[(kViewPortCW + 1)][(kViewPortCH + 1)]; + uint16 _myModLCNM[(kViewPortCW + 1)][(kViewPortCH + 1)]; + uint16 _columnX[kViewPortCW + 1]; + uint16 _columnTop[kViewPortCW + 1]; + uint16 _columnIndex[kViewPortCW + 1]; // Why the heck is this an entire array, when it's just an index that gets zeroed before it gets used anyway... uint16 _tIndex[kMaxDrawItems]; uint16 _tPriority[kMaxDrawItems]; - uint16 _viewPortX = 0; - uint16 _viewPortY = 0; - uint16 _myViewPortX = 0; // Probably mirror of viewportX - uint16 _myViewPortY = 0; - int _lastGauge = 0; // Mirror for player health, used to update health gauge display - uint16 _lastBMW = 0; // Mirrors used to determine where bitmap width needs to be re-calculated - uint16 _lastY = 0; - uint16 _lastPoint = 0; - uint16 _penX = 0; // Basically where in the screen we are currently drawing - uint16 _penY = 0; - uint16 _myUnivPointX = 0; - uint16 _myUnivPointY = 0; - int _num2DrawItems = 0; + uint16 _viewPortX = 0; + uint16 _viewPortY = 0; + uint16 _myViewPortX = 0; // Probably mirror of viewportX + uint16 _myViewPortY = 0; + int _lastGauge = 0; // Mirror for player health, used to update health gauge display + uint16 _lastBMW = 0; // Mirrors used to determine where bitmap width needs to be re-calculated + uint16 _lastY = 0; + uint16 _lastPoint = 0; + uint16 _penX = 0; // Basically where in the screen we are currently drawing + uint16 _penY = 0; + uint16 _myUnivPointX = 0; + uint16 _myUnivPointY = 0; + int _num2DrawItems = 0; Graphics::Surface *_mainSurface; GenericSprite _genSprites[6]; @@ -412,6 +412,7 @@ GenericSprite _genSprites[6]; int _dontResetColors = 0; // Not sure yet bool _usingNormal = 0; // Whether the palette is using normal bool _dim = 0; // Whether the palette is dim + uint16 _palUniv[16]; uint16 _palDefault[16]; uint16 _palWhite[16]; uint16 _palBlack[16]; @@ -489,6 +490,7 @@ GenericSprite _genSprites[6]; // Assets Common::SeekableReadStream *loadIFF(Common::String fileName); // Loads a file and uncompresses if it is compressed void initStoryStatic(); // Sets up all of the global static story elements + void loadUniv(char mazeNum); void loadMazeGraphics(int m); // Creates a universe with a maze void loadFont(); // Gets the font.spr file, and centers the sprite void clearSprites(); // Clears all sprites before drawing the current frame diff --git a/engines/immortal/level.cpp b/engines/immortal/level.cpp index 61b17098756b..47822b23d18c 100644 --- a/engines/immortal/level.cpp +++ b/engines/immortal/level.cpp @@ -43,7 +43,7 @@ void ImmortalEngine::levelNew(int l) { levelStory(l); if (kLevelToMaze[l] != _lastLevelLoaded) { _lastLevelLoaded = kLevelToMaze[l]; - //loadMazeGraphics(l); + loadMazeGraphics(l); } if (_level != _lastSongLoaded) { diff --git a/engines/immortal/logic.cpp b/engines/immortal/logic.cpp index 0a0c93119158..20106566dd4c 100644 --- a/engines/immortal/logic.cpp +++ b/engines/immortal/logic.cpp @@ -519,7 +519,6 @@ bool ImmortalEngine::getCertificate() { } else { // The input was a key - if (certLen != kMaxCertificate) { if ((k >= 'a') && (k < '{')) { k -= 0x20; @@ -532,7 +531,6 @@ bool ImmortalEngine::getCertificate() { else { if (k < 'A') { - // Terrible, I know. But this seems to be the logic. continue; } @@ -584,8 +582,7 @@ void ImmortalEngine::printCertificate() { * this one is nice and simple. You could also * just add the appropriate offset for the letters, * but grabbing it from a table is faster and doesn't - * use a lot of space (especially if it's used anywhere else). - * Why doesn't the game use rom table indexing like this more often? + * use a lot of space (especially if it's used anywhere else) */ char toHex[] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}; @@ -614,7 +611,7 @@ bool ImmortalEngine::isSavedAna() { /* - * Functions that don't really need to be functions + * These functions don't really need to be functions */ void ImmortalEngine::setGameFlags(uint16 f) { diff --git a/engines/immortal/misc.cpp b/engines/immortal/misc.cpp index 450380b51c6d..38fe11f6cc19 100644 --- a/engines/immortal/misc.cpp +++ b/engines/immortal/misc.cpp @@ -198,9 +198,7 @@ bool ImmortalEngine::textSub(Str s, FadeType f, int n) { } index++; } - - //debug("printing index: %d", index); - + chr = text[index]; if (f != kTextFadeIn) { diff --git a/engines/immortal/module.mk b/engines/immortal/module.mk index 3812d27981ce..3d98cfe27292 100644 --- a/engines/immortal/module.mk +++ b/engines/immortal/module.mk @@ -12,8 +12,8 @@ MODULE_OBJS = \ misc.o \ cycle.o \ drawChr.o \ - level.o \ - story.o \ + level.o \ + story.o \ room.o \ flameSet.o \ univ.o \ diff --git a/engines/immortal/room.h b/engines/immortal/room.h index 7cc9937117b8..97c25fba2f1d 100644 --- a/engines/immortal/room.h +++ b/engines/immortal/room.h @@ -119,20 +119,21 @@ class Room { const uint8 kLightTorchX = 10; const uint8 kMaxFlameCycs = 16; -Common::Array _cycPtrs; -Common::Array _fset; -Common::Array _monsters; -Common::Array _objects; - - RoomFlag _flags; - uint8 _xPos = 0; - uint8 _yPos = 0; - uint8 _holeRoom = 0; - uint8 _holeCellX = 0; - uint8 _holeCellY = 0; - uint8 _candleTmp = 0; // Special case for candle in maze 0 - uint8 _numFlames = 0; - uint8 _numInRoom = 0; + Common::Array _cycPtrs; + Common::Array _fset; + Common::Array _monsters; + Common::Array _objects; + + RoomFlag _flags; + + uint8 _xPos = 0; + uint8 _yPos = 0; + uint8 _holeRoom = 0; + uint8 _holeCellX = 0; + uint8 _holeCellY = 0; + uint8 _candleTmp = 0; // Special case for candle in maze 0 + uint8 _numFlames = 0; + uint8 _numInRoom = 0; /* * --- Methods --- @@ -171,7 +172,7 @@ Common::Array _objects; */ // Init - int cycleNew(CycID id); // Adds a cycle to the current list + int cycleNew(CycID id); // Adds a cycle to the current list void cycleFree(int c); // Getters @@ -185,7 +186,7 @@ DataSprite *cycleGetDataSprite(int c); // This takes the place of getFile + ge // Misc bool cycleAdvance(int c); - CycID getCycList(int c); + CycID getCycList(int c); /* Unneccessary cycle functions void cycleInit(); @@ -204,7 +205,7 @@ DataSprite *cycleGetDataSprite(int c); // This takes the place of getFile + ge void lightTorch(uint8 x, uint8 y); void flameFreeAll(); void flameSetRoom(Common::Array); - int flameGetCyc(Flame *f, int first); + int flameGetCyc(Flame *f, int first); /* * [bullet.cpp] Functions from Bullet.GS @@ -221,7 +222,7 @@ DataSprite *cycleGetDataSprite(int c); // This takes the place of getFile + ge * [Univ.cpp] Functions from Univ.GS */ - void univAddSprite(uint16 vX, uint16 vY, uint16 x, uint16 y, SpriteName s, int img, uint16 p); + void univAddSprite(uint16 vX, uint16 vY, uint16 x, uint16 y, SpriteName s, int img, uint16 p); }; } // namespace immortal diff --git a/engines/immortal/sprite_list.h b/engines/immortal/sprite_list.h index d80c37fa4aa0..26d6fb5ab6ef 100644 --- a/engines/immortal/sprite_list.h +++ b/engines/immortal/sprite_list.h @@ -32,25 +32,25 @@ struct Image { uint16 _deltaY; uint16 _rectW; uint16 _rectH; -Common::Array _scanWidth; -Common::Array _deltaPos; -CArray2D _bitmap; + Common::Array _scanWidth; + Common::Array _deltaPos; + CArray2D _bitmap; }; struct DataSprite { uint16 _cenX; // These are the base center positions uint16 _cenY; uint16 _numImages; -Common::Array _images; + Common::Array _images; }; struct Sprite { - int _image; // Index of _dSprite._frames[] + int _image; // Index of _dSprite._images[] uint16 _X; uint16 _Y; uint16 _on; // 1 = active uint16 _priority; -DataSprite *_dSprite; + DataSprite *_dSprite; }; enum SpriteFrame { diff --git a/engines/immortal/sprites.cpp b/engines/immortal/sprites.cpp index 31969a8e0a1d..c8c61f8ade59 100644 --- a/engines/immortal/sprites.cpp +++ b/engines/immortal/sprites.cpp @@ -63,7 +63,7 @@ namespace Immortal { // This function is basically setSpriteCenter + getSpriteInfo from the source void ImmortalEngine::initDataSprite(Common::SeekableReadStream *f, DataSprite *d, int index, uint16 cenX, uint16 cenY) { - // We set the center X and Y, for some reason + // We set the center X and Y d->_cenX = cenX; d->_cenY = cenY; @@ -76,7 +76,6 @@ void ImmortalEngine::initDataSprite(Common::SeekableReadStream *f, DataSprite *d uint16 numImages = f->readUint16LE(); d->_numImages = numImages; - //debug("Number of Frames: %d", numImages); // Only here for dragon, but just in case, it's a high number so it should catch others if (numImages >= 0x0200) { @@ -91,7 +90,7 @@ void ImmortalEngine::initDataSprite(Common::SeekableReadStream *f, DataSprite *d f->seek(index + (i * 2)); int ptrFrame = f->readUint16LE(); f->seek(ptrFrame); - newImage._deltaX = f->readUint16LE() << 1; // the ASL might not be required, depending on whether the data is actually in bytes or pixels <-- this also might not be used in the game anyway? Lol + newImage._deltaX = f->readUint16LE() << 1; // This member does not seem to be used in the actual game, and it is not clear whether it needs the << 1 or if that was fixed before release newImage._deltaY = f->readUint16LE(); newImage._rectW = f->readUint16LE(); newImage._rectH = f->readUint16LE(); @@ -127,9 +126,10 @@ bool ImmortalEngine::clipSprite(uint16 &height, uint16 &pointIndex, uint16 &skip _lastY = pointY; if (pointY < kMaskNeg) { // For the Apple IIGS, pointY in pixels needed to be converted to bytes. For us, it's the other way around, we need bmw in pixels + // This should probably use mult16() instead of * _lastPoint = pointY * (bmw); } else { - // Screen wrapping?? + // Screen wrapping? uint16 temp = (0 - pointY) + 1; _lastPoint = temp * bmw; _lastPoint = 0 - _lastPoint; @@ -175,8 +175,8 @@ void ImmortalEngine::spriteAligned(DataSprite *dSprite, Image &img, uint16 &skip * that was indexed by the pixel itself, and used to find what nyble needed * to be masked. However we are using a slightly different kind of screen buffer, * and so I chose a more traditional method. Likewise, alignement was - * relevant for the source, but is not relevant here (thankfully, considering - * how confusing sprite drawing is when not an even position). + * relevant for the source, but is not relevant here, and the sprite drawing + * is not accomplished by indexed a set of code blocks. */ byte pixel1 = 0; byte pixel2 = 0; @@ -218,7 +218,7 @@ void ImmortalEngine::spriteAligned(DataSprite *dSprite, Image &img, uint16 &skip } void ImmortalEngine::superSprite(DataSprite *dSprite, uint16 pointX, uint16 pointY, int img, uint16 bmw, byte *dst, uint16 superTop, uint16 superBottom) { - // Main image construction routine + // Main sprite image construction routine // For the Apple IIGS, the bmw is in bytes, but for us it needs to be the reverse, in pixels bmw <<= 1; @@ -229,7 +229,7 @@ void ImmortalEngine::superSprite(DataSprite *dSprite, uint16 pointX, uint16 poin uint16 height = dSprite->_images[img]._rectH; uint16 skipY = 0; - uint16 pointIndex = 0; // This is screen and screen + 2 in the source + uint16 pointIndex = 0; // This is 'screen' and 'screen + 2' in the source pointX -= cenX; pointY -= cenY; diff --git a/engines/immortal/story.cpp b/engines/immortal/story.cpp index 51dd04437846..c0b39350a102 100644 --- a/engines/immortal/story.cpp +++ b/engines/immortal/story.cpp @@ -32,7 +32,8 @@ * objects, and everything in the rooms. */ -/* UNIVAT 1024,480, 1152, 464, \-1, -1, zip,level1Ladders, rooma, 704/64, 544/32\ +/* These are the UNIVAT for each Story entry + UNIVAT 1024,480, 1152, 464, \-1, -1, zip,level1Ladders, rooma, 704/64, 544/32\ UNIVAT 304, 448, 472+32, 500+16, \-1, -1, zip,level12Ladders, -1, 0, 0\ UNIVAT 600, 450, 560, 598, \-1, r2.b+(16*r2.a), zip,level3Ladders, r2.b, 640/64, 576/32\ UNIVAT 120, 540, 188, 584, \-1, -1, zip,level4Ladders, -1, 0, 0\ @@ -149,7 +150,6 @@ void ImmortalEngine::initStoryStatic() { "This room resembles part&of the map.@"}; _strPtrs = s; - // Scope, amirite? Common::Array cyc0{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,-1}; Common::Array cyc1{15,16,17,18,19,20,21,22,-1}; Common::Array cyc2{0,1,2,-1}; @@ -158,9 +158,9 @@ void ImmortalEngine::initStoryStatic() { Common::Array cyc5{11,12,13,14,15,-1}; Common::Array cyc6{16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,-1}; Common::Array cyc7{0,1,2,3,4,-1}; - Common::Array cyc8{5,1+5,2+5,3+5,4+5,-1}; - Common::Array cyc9{10,1+10,2+10,3+10,4+10,-1}; - Common::Array cyc10{15,1+15,2+15,3+15,4+15,-1}; + Common::Array cyc8{5,1 + 5,2 + 5,3 + 5,4 + 5,-1}; + Common::Array cyc9{10,1 + 10,2 + 10,3 + 10,4 + 10,-1}; + Common::Array cyc10{15,1 + 15,2 + 15,3 + 15,4 + 15,-1}; Common::Array cyc11{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,-1}; Common::Array cyc12{0,1,2,3,4,5,6,7,8,9,-1}; Common::Array cyc13{0,1,2,3, 0,1,2,3, 0,1,2,3, 0,1,2,3, 0,1,2,3, 0,1,2,3, 0,1,2,3, 0,1,2,3, -1}; @@ -175,10 +175,10 @@ void ImmortalEngine::initStoryStatic() { Common::Array cyc22{0,17,18,19,3,-1}; Common::Array cyc23{0,1,-1}; Common::Array cyc24{28,28,28,28,-1}; - Common::Array cyc25{15,16,15,16,15,1+15,1+15,-1}; - Common::Array cyc26{10+15,11+15,12+15,13+15,14+15,15+15,16+15,-1}; - Common::Array cyc27{2+15,3+15,4+15,5+15,-1}; - Common::Array cyc28{6+15,7+15,8+15,9+15,-1}; + Common::Array cyc25{15,16,15,16,15,1 + 15,1 + 15,-1}; + Common::Array cyc26{10 + 15,11+ 15,12 + 15,13 + 15,14 + 15,15 + 15,16 + 15,-1}; + Common::Array cyc27{2 + 15,3 + 15,4 + 15,5 + 15,-1}; + Common::Array cyc28{6 + 15,7 + 15,8 + 15,9 + 15,-1}; Common::Array cyc29{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,-1}; Common::Array cyc30{0,1,2,3,3,3,3,4,5,6,-1}; Common::Array cyc31{0,1,2,3,4,5,6,7,8,-1}; @@ -277,9 +277,9 @@ void ImmortalEngine::initStoryDynamic() { /* All of the doors */ Common::Array doors{SDoor(0, 704, 224, 0, 2, false), SDoor(1, 576, 352, 4, 0, true), - SDoor(1, 704, 96, 2, 1, false), SDoor(1, 960, 128, 7, 2, false), - SDoor(1, 1088,160, 3, 7, false), SDoor(1, 1088,320, 6, 3, false), - SDoor(1, 896, 416, 4, 3, false)}; + SDoor(1, 704, 96, 2, 1, false), SDoor(1, 960, 128, 7, 2, false), + SDoor(1, 1088,160, 3, 7, false), SDoor(1, 1088,320, 6, 3, false), + SDoor(1, 896, 416, 4, 3, false)}; _stories[0]._doors = doors; /* All of the flames @@ -309,23 +309,23 @@ void ImmortalEngine::initStoryDynamic() { Common::Array noObj{}; Common::Array o5{SObj(kZip, kZip, kTypeTrap, kNoFrame, kObjIsRunning + kObjIsInvisible, o5Traps), - SObj(459, 379, kTypeCoin, kRingFrame, kObjNone, noTraps), - SObj(446, 327, kTypeWowCharm, kScrollFrame, kObjNone, noTraps)}; + SObj(459, 379, kTypeCoin, kRingFrame, kObjNone, noTraps), + SObj(446, 327, kTypeWowCharm, kScrollFrame, kObjNone, noTraps)}; Common::Array o7{SObj(145, 138, kTypeTrap, kNoFrame, kObjIsRunning + kObjIsInvisible, o7Traps)}; Common::Array o8{SObj(kZip, kZip, kTypeTrap, kNoFrame, kObjIsRunning + kObjIsInvisible, o8Traps)}; Common::Array o9{SObj(1052, 309, kTypeDead, kDeadGoblinFrame, kObjIsChest + kObjIsOnGround, noTraps), SObj(kZip, kZip, kTypeFireBall, kScrollFrame, kObjUsesFireButton, noTraps), SObj(128, 464, kTypeDunRing, kRingFrame, 0, noTraps), SObj(837, 421, kTypeChest, kChest0Frame, kObjIsChest, noTraps), - SObj(kZip, kZip, kTypeDeathMap, kScrollFrame, 0, noTraps), - SObj(597, 457, kTypeWater, kVaseFrame, 0, noTraps), - SObj(kZip, kZip, kTypeSpores, kSporesFrame, 0, noTraps), - SObj(kZip, kZip, kTypeWormFood, kNoFrame, 0, noTraps), - SObj(205, 158, kTypeChestKey, kKeyFrame, 0, noTraps)}; + SObj(kZip, kZip, kTypeDeathMap, kScrollFrame, 0, noTraps), + SObj(597, 457, kTypeWater, kVaseFrame, 0, noTraps), + SObj(kZip, kZip, kTypeSpores, kSporesFrame, 0, noTraps), + SObj(kZip, kZip, kTypeWormFood, kNoFrame, 0, noTraps), + SObj(205, 158, kTypeChestKey, kKeyFrame, 0, noTraps)}; Common::Array oE{SObj(1184, 426, kTypePhant, kAltarFrame, 0, noTraps), - SObj(145, 138, kTypeGold, kNoFrame, kObjIsRunning, noTraps), - SObj(671, 461, kTypeHay, kNoFrame, kObjIsRunning + kObjIsInvisible, noTraps), - SObj(780, 508, kTypeBeam, kNoFrame, kObjIsRunning + kObjIsInvisible, noTraps)}; + SObj(145, 138, kTypeGold, kNoFrame, kObjIsRunning, noTraps), + SObj(671, 461, kTypeHay, kNoFrame, kObjIsRunning + kObjIsInvisible, noTraps), + SObj(780, 508, kTypeBeam, kNoFrame, kObjIsRunning + kObjIsInvisible, noTraps)}; CArray2D objects{o5, o7, o8, o9, noObj, noObj, oE, noObj}; _stories[0]._objects = objects; @@ -341,15 +341,19 @@ void ImmortalEngine::initStoryDynamic() { Common::Array noMonst{}; Common::Array m5{SMonster(448, 344, 12, kMonstPlayer, kMonstA + kMonstIsEngage + kMonstIsTough, progShade, kShadow), - SMonster(590, 381, 12, kMonstPlayer, kMonstA + kMonstIsEngage + kMonstIsTough, progShade, kShadow)}; + SMonster(590, 381, 12, kMonstPlayer, kMonstA + kMonstIsEngage + kMonstIsTough, progShade, kShadow)}; Common::Array m9{SMonster(1106, 258, 3, kMonstPlayer, kMonstA + kMonstIsEngage, progEasy, kGoblin0), SMonster(832, 364, 10, kMonstA, kMonstB + kMonstIsPoss, progUlindor, kUlindor3), - SMonster(838, 370, 15, kMonstPlayer, kMonstA + kMonstIsEngage, progGoblin5, kGoblin7)}; + SMonster(838, 370, 15, kMonstPlayer, kMonstA + kMonstIsEngage, progGoblin5, kGoblin7)}; Common::Array mE{SMonster(1136, 464, 15, kMonstMonster, kMonstPlayer + kMonstIsEngage, progPlayer, kWizard0)}; Common::Array mF{SMonster(1182, 116, 5, kMonstPlayer, kMonstA + kMonstIsEngage, progWill2, kGoblin5)}; CArray2D monsters{m5, noMonst, noMonst, m9, noMonst, noMonst, mE, mF}; _stories[0]._monsters = monsters; + /* + * ::: Level 0: Intro 2 ::: + */ + } } // namespace Immortal diff --git a/engines/immortal/story.h b/engines/immortal/story.h index 4b369dbeb3f3..6bd87d1400fc 100644 --- a/engines/immortal/story.h +++ b/engines/immortal/story.h @@ -97,33 +97,33 @@ enum SObjPickup { }; struct Pickup { - //pointer to function int _param; + // This will be a pointer to function }; -// Iirc damage is used by object types as well as enemy types +// Damage is used by object types as well as enemy types enum SDamage { }; struct Damage { }; -// Use is self explanitory, it defines the function and parameters for using an object +// Use defines the function and parameters for using an object enum SObjUse { }; struct Use { - //pointer to function int _param; + // This will be a pointer to function }; struct ObjType { Str _str = kStrNull; Str _desc = kStrNull; int _size = 0; - Pickup _pickup; Use _use; Use _run; + Pickup _pickup; }; // Cycles define the animation of sprites within a level. There is a fixed total of cycles available, and they are not room dependant @@ -138,43 +138,48 @@ struct Cycle { * for the moment there's no need to replicate this particular bit of space saving. */ struct SCycle { -SpriteName _sName; - bool _repeat; -Common::Array _frames; + SpriteName _sName; + Common::Array _frames; + bool _repeat; SCycle() {} SCycle(SpriteName s, bool r, Common::Array f) { - _sName = s; - _repeat = r; - _frames = f; + _sName = s; + _repeat = r; + _frames = f; } }; struct SRoom { uint16 _x = 0; uint16 _y = 0; - RoomFlag _flags = kRoomFlag0; - SRoom() {} - SRoom(uint16 x, uint16 y, RoomFlag f) { - _x = x; - _y = y; - _flags = f; - } + + RoomFlag _flags = kRoomFlag0; + SRoom() {} + SRoom(uint16 x, uint16 y, RoomFlag f) { + _x = x; + _y = y; + _flags = f; + } }; struct SDoor { - uint8 _dir = 0; - uint16 _x = 0; - uint16 _y = 0; + uint8 _dir = 0; + uint16 _x = 0; + uint16 _y = 0; + uint16 _fromRoom = 0; uint16 _toRoom = 0; - bool _isLocked = false; - SDoor() {} - SDoor(uint8 d, uint16 x, uint16 y, uint16 f, uint16 t, bool l) { - _dir = d; - _x = x; - _y = y; - _fromRoom = f; - _toRoom = t; + + bool _isLocked = false; + SDoor() {} + SDoor(uint8 d, uint16 x, uint16 y, uint16 f, uint16 t, bool l) { + _dir = d; + _x = x; + _y = y; + + _fromRoom = f; + _toRoom = t; + _isLocked = l; } }; @@ -182,68 +187,71 @@ struct SDoor { struct SFlame { uint16 _x = 0; uint16 _y = 0; -FPattern _p = kFlameOff; + + FPattern _p = kFlameOff; SFlame() {} - SFlame(uint16 x, uint16 y, FPattern p) { - _x = x; + SFlame(uint16 x, uint16 y, FPattern p) { + _x = x; _y = y; - _p = p; - } + _p = p; + } }; struct SObj { - uint16 _x = 0; - uint16 _y = 0; - SObjType _type = kTypeTrap; - uint8 _flags = 0; -SpriteFrame _frame = kNoFrame; -Common::Array _traps; + uint16 _x = 0; + uint16 _y = 0; + uint8 _flags = 0; + + SObjType _type = kTypeTrap; + SpriteFrame _frame = kNoFrame; + Common::Array _traps; SObj() {} SObj(uint16 x, uint16 y, SObjType t, SpriteFrame s, uint8 f, Common::Array traps) { - _x = x; - _y = y; - _type = t; - _flags = f; - _traps = traps; - _frame = s; + _x = x; + _y = y; + _type = t; + _flags = f; + _traps = traps; + _frame = s; } }; struct SMonster { - uint16 _x = 0; - uint16 _y = 0; - uint16 _hits = 0; -MonsterFlag _madAt = kMonstIsNone; - uint8 _flags = 0; - SpriteName _sprite = kCandle; -Common::Array _program; + uint16 _x = 0; + uint16 _y = 0; + uint16 _hits = 0; + uint8 _flags = 0; + + MonsterFlag _madAt = kMonstIsNone; + SpriteName _sprite = kCandle; + Common::Array _program; SMonster() {} SMonster(uint16 x, uint16 y, uint16 h, MonsterFlag m, uint8 f, Common::Array p, SpriteName s) { - _x = x; - _y = y; - _hits = h; - _madAt = m; - _flags = f; - _program = p; - _sprite = s; + _x = x; + _y = y; + _hits = h; + _madAt = m; + _flags = f; + _program = p; + _sprite = s; } }; struct Story { - int _level = 0; - int _part = 1; - - uint16 _initialUnivX = 0; - uint16 _initialUnivY = 0; - uint16 _playerPointX = 0; - uint16 _playerPointY = 0; - - Common::Array _ladders; -Common::Array _rooms; -Common::Array _doors; - CArray2D _flames; - CArray2D _objects; - CArray2D _monsters; + int _level = 0; + int _part = 1; + + uint16 _initialUnivX = 0; + uint16 _initialUnivY = 0; + uint16 _playerPointX = 0; + uint16 _playerPointY = 0; + + Common::Array _ladders; + Common::Array _rooms; + Common::Array _doors; + CArray2D _flames; + CArray2D _objects; + CArray2D _monsters; }; } // namespace immortal diff --git a/engines/immortal/utilities.cpp b/engines/immortal/utilities.cpp index 50957dede5e1..0825510193d7 100644 --- a/engines/immortal/utilities.cpp +++ b/engines/immortal/utilities.cpp @@ -90,7 +90,9 @@ bool Utilities::insideRect(uint8 rectX, uint8 rectY, uint8 w, uint8 h, uint8 poi * This is done by grabbing the delta X,Y and * making sure it is not negative. */ - if ((w | h) == 0) { + + // The source specifically checks only for w *and* h being 0, so you could give it a rect with a width or height or 0, just not both + if ((w == 0) && (h == 0)) { return false; } From 3feb762d90017a7e2046a54451ee700f4a3ff6f8 Mon Sep 17 00:00:00 2001 From: Quote58 Date: Sun, 30 Oct 2022 19:25:11 -0400 Subject: [PATCH 360/412] IMMORTAL: Implement loadUniv() and add stub for makeBlisters() --- engines/immortal/immortal.h | 27 ++++++++-- engines/immortal/kernal.cpp | 104 +++++++++++++++++++++++++++++++++--- 2 files changed, 119 insertions(+), 12 deletions(-) diff --git a/engines/immortal/immortal.h b/engines/immortal/immortal.h index 7ff63fc75915..954963bde225 100644 --- a/engines/immortal/immortal.h +++ b/engines/immortal/immortal.h @@ -382,11 +382,29 @@ class ImmortalEngine : public Engine { CArray2D _programPtrs; Common::Array _objTypePtrs; - // Screen members - byte *_screenBuff; // The final buffer that will transfer to the screen + // Universe members + uint16 _univRectX = 0; + uint16 _univRectY = 0; + uint16 _numAnims = 0; + uint16 _numCols = 0; + uint16 _numRows = 0; + uint16 _numChrs = 0; + uint16 _num2Cols = 0; + uint16 _num2Rows = 0; + uint16 _num2Cells = 0; + uint16 _num2Chrs = 0; + Common::Array _univ; // This doesn't really need to exist in the way that it did in the source, but for now it will be utilized essentially the same way + uint16 *_CNM; + Common::Array _LCNM; + uint16 *_modCNM; + uint16 *_modLCNM; + uint16 _myCNM[(kViewPortCW + 1)][(kViewPortCH + 1)]; uint16 _myModCNM[(kViewPortCW + 1)][(kViewPortCH + 1)]; uint16 _myModLCNM[(kViewPortCW + 1)][(kViewPortCH + 1)]; + + // Screen members + byte *_screenBuff; // The final buffer that will transfer to the screen uint16 _columnX[kViewPortCW + 1]; uint16 _columnTop[kViewPortCW + 1]; uint16 _columnIndex[kViewPortCW + 1]; // Why the heck is this an entire array, when it's just an index that gets zeroed before it gets used anyway... @@ -490,8 +508,9 @@ GenericSprite _genSprites[6]; // Assets Common::SeekableReadStream *loadIFF(Common::String fileName); // Loads a file and uncompresses if it is compressed void initStoryStatic(); // Sets up all of the global static story elements - void loadUniv(char mazeNum); - void loadMazeGraphics(int m); // Creates a universe with a maze + int loadUniv(char mazeNum); // Unpacks the .CNM and .UNV files into all the CNM stuff, returns the total length of everything + void loadMazeGraphics(int m); // Creates a universe with a maze + void makeBlisters(int povX, int povY); // Turns the unmodified CNM/CBM/LCNM etc into the modified ones to actually be used for drawing the game void loadFont(); // Gets the font.spr file, and centers the sprite void clearSprites(); // Clears all sprites before drawing the current frame void loadSprites(); // Loads all the sprite files and centers their sprites (in spritelist, but called from kernal) diff --git a/engines/immortal/kernal.cpp b/engines/immortal/kernal.cpp index 97a898771db6..741ae1af6e40 100644 --- a/engines/immortal/kernal.cpp +++ b/engines/immortal/kernal.cpp @@ -48,12 +48,12 @@ void ImmortalEngine::drawUniv() { _myUnivPointX = !(_myViewPortX & (kChrW - 1)) + kViewPortSpX; _myUnivPointY = !(_myViewPortY & (kChrH - 1)) + kViewPortSpY; - makeMyCNM(); - drawBGRND(); // Draw floor parts of leftmask rightmask and maskers - addRows(); // Add rows to drawitem array - addSprites(); // Add all active sprites that are in the viewport, into a list that will be sorted by priority - sortDrawItems(); // Sort said items - drawItems(); // Draw the items over the background + //makeMyCNM(); + //drawBGRND(); // Draw floor parts of leftmask rightmask and maskers + //addRows(); // Add rows to drawitem array + //addSprites(); // Add all active sprites that are in the viewport, into a list that will be sorted by priority + //sortDrawItems(); // Sort said items + //drawItems(); // Draw the items over the background } void ImmortalEngine::copyToScreen() { @@ -466,17 +466,96 @@ void ImmortalEngine::cycleFreeAll() { void ImmortalEngine::loadMazeGraphics(int m) { char mazeNum = m + '0'; loadUniv(mazeNum); - setColors(_palUniv); + //setColors(_palUniv); } -void ImmortalEngine::loadUniv(char mazeNum) { +int ImmortalEngine::loadUniv(char mazeNum) { + int lData = 0; + int lStuff = 0x26; + + // We start by loading the mazeN.CNM file with loadIFF (a little silly since we know this isn't compressed) Common::String sCNM = "MAZE" + Common::String(mazeNum) + ".CNM"; Common::SeekableReadStream *mazeCNM = loadIFF(sCNM); + if (!mazeCNM) { + debug("Error, couldn't load maze %d.CNM", mazeNum); + return -1; + } debug("Size of maze CNM: %ld", mazeCNM->size()); + // The logical CNM contains the contents of mazeN.CNM, with every entry being multiplied by two (why are these byte indexes instead of word indexes in the file?) + mazeCNM->seek(0); + for (int i = 0; i < mazeCNM->size(); i++) { + _LCNM.push_back(mazeCNM->readUint16LE() << 1); + } + + // Next we load the mazeN.UNV file, which contains the compressed data but is not itself compressed (again, a little silly) Common::String sUNV = "MAZE" + Common::String(mazeNum) + ".UNV"; Common::SeekableReadStream *mazeUNV = loadIFF(sUNV); + if (!mazeUNV) { + debug("Error, couldn't load maze %d.UNV", mazeNum); + return -1; + } debug("Size of maze UNV: %ld", mazeUNV->size()); + + lData = mazeUNV->size(); + + mazeUNV->seek(0x20); + _univRectX = mazeUNV->readUint16LE() << 1; + _numCols = _univRectX >> 6; + _num2Cols = _numCols << 1; + + // univRectY is mazeUNV[22] + _univRectY = mazeUNV->readUint16LE(); + _numRows = _univRectY >> 5; + _num2Rows = _numRows << 1; + + // If there are animations (are there ever?), the univ data is expanded from 26 to include them + if (mazeUNV->readUint16LE() != 0) { + mazeUNV->seek(0x2C); + lStuff += mazeUNV->readUint16LE(); + } + + // This is probably not how _univ is actually populated, but just to make sure I don't forget about, let's make sure it has the data + mazeUNV->seek(0); + for (int i = 0; i < lStuff; i++) { + _univ.push_back(mazeUNV->readUint16LE()); + } + + // lData is everything from the .UNV file after the universe variables + lData -= lStuff; + + // The data to uncompress is after the universe data in the file + mazeUNV->seek(lStuff); + Common::SeekableReadStream *pCNM = unCompress((Common::File *) mazeUNV, lData); + + // Now we move the data of the uncompressed CNM into it's actual location + // This data type will likely change, it's just unclear how the munge functions work currently + _CNM = (uint16 *)malloc(pCNM->size()); + pCNM->seek(0); + pCNM->read(_CNM, pCNM->size()); + + _num2Cells = _num2Cols * _numRows; + _numChrs = 0; + + // Check every entry in the CNM, with the highest number being the highest number of chrs? + for (int i = 0; i < _num2Cells; i++) { + if (_CNM[i] >= _numChrs) { + _numChrs = _CNM[i]; + } + } + + // Inc one more time being 0 counts + _numChrs++; + _num2Chrs = _numChrs << 1; + + int lCNMCBM = mungeCBM(_num2Chrs); + + // We don't actually want to blister any rooms yet, so we give it a POV of (0,0) + makeBlisters(0, 0); + return _LCNM.size() + /*_modCNM.size()*/ + /*_modLCNM.size()*/ + _univ.size() + lCNMCBM; +} + +void ImmortalEngine::makeBlisters(int povX, int povY) { } void ImmortalEngine::loadSprites() { @@ -599,6 +678,15 @@ void ImmortalEngine::loadFont() { } Common::SeekableReadStream *ImmortalEngine::loadIFF(Common::String fileName) { + /* Technically the way this works in the source is that it loads the file + * to a destination address, and then checks the start of that address, and + * if it needs to uncompress, it gives that same address to the uncompress + * routine, overwriting the file in it's place. This is of course slightly + * different here, for simplicity we are not overwriting the original file + * pointer, instead just returning either a compressed or uncompressed + * file pointer. + */ + Common::File f; if (!f.open(fileName)) { debug("*surprised pikachu face*"); From 8232bfd367f8145a1f35f5f8f9c63e1e1fd0874b Mon Sep 17 00:00:00 2001 From: Quote58 Date: Mon, 31 Oct 2022 05:31:58 -0400 Subject: [PATCH 361/412] IMMORTAL: Update disk.cpp to use strncpy() instead of strcpy() --- engines/immortal/disk.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engines/immortal/disk.cpp b/engines/immortal/disk.cpp index be6103e6c30c..dac2d02260d8 100644 --- a/engines/immortal/disk.cpp +++ b/engines/immortal/disk.cpp @@ -34,7 +34,7 @@ ProDOSFile::ProDOSFile(char name[15], uint8 type, uint16 tBlk, uint32 eof, uint1 , _eof(eof) , _blockPtr(bPtr) , _disk(disk) { - strcpy(_name, name); + strncpy(_name, name, 15); } /* For debugging purposes, this prints the meta data of a file */ From e16f087c544ae5d121244f61466c5a9b5d08f8c5 Mon Sep 17 00:00:00 2001 From: Quote58 Date: Wed, 11 Jan 2023 21:59:40 -0500 Subject: [PATCH 362/412] IMMORTAL: Rewrite loadUniv() based on new understanding of CNM --- engines/immortal/drawChr.cpp | 24 ++++++++-- engines/immortal/immortal.h | 48 +++++++++++++------- engines/immortal/kernal.cpp | 86 +++++++++++++++++++++--------------- 3 files changed, 102 insertions(+), 56 deletions(-) diff --git a/engines/immortal/drawChr.cpp b/engines/immortal/drawChr.cpp index 9a8b8e711ccf..6f0cfe87a17c 100644 --- a/engines/immortal/drawChr.cpp +++ b/engines/immortal/drawChr.cpp @@ -23,12 +23,15 @@ namespace Immortal { -// These functions are not yet implemented -int ImmortalEngine::mungeCBM(int numChrs) { - return 0; +int ImmortalEngine::mungeCBM() { + + return 0;//_CNM - pDraw; +} + +void ImmortalEngine::storeAddr() { + } -void ImmortalEngine::storeAddr() {} void ImmortalEngine::mungeSolid() {} void ImmortalEngine::mungeLRHC() {} void ImmortalEngine::mungeLLHC() {} @@ -40,4 +43,17 @@ void ImmortalEngine::drawURHC(int chr, int x, int y) {} void ImmortalEngine::drawLLHC(int chr, int x, int y) {} void ImmortalEngine::drawLRHC(int chr, int x, int y) {} + + + + + + + + + + + + + } // namespace immortal \ No newline at end of file diff --git a/engines/immortal/immortal.h b/engines/immortal/immortal.h index 954963bde225..47b0207876f7 100644 --- a/engines/immortal/immortal.h +++ b/engines/immortal/immortal.h @@ -162,6 +162,20 @@ struct Door { uint8 _on = 0; }; +// Universe is a set of properties for the entire level, nor just the room +struct Univ { + uint16 _rectX = 0; + uint16 _rectY = 0; + uint16 _numAnims = 0; + uint16 _numCols = 0; + uint16 _numRows = 0; + uint16 _numChrs = 0; + uint16 _num2Cols = 0; + uint16 _num2Rows = 0; + uint16 _num2Cells = 0; + uint16 _num2Chrs = 0; +}; + struct ImmortalGameDescription; // Forward declaration because we will need the Disk and Room classes @@ -224,6 +238,7 @@ class ImmortalEngine : public Engine { const uint16 kChrLen = (kChrW / 2) * kChrH; const uint16 kChrBMW = kChrW / 2; const uint16 kLCutaway = 4; + const uint16 kLDrawSolid = 32 * ((3 * 16) + 5); const uint16 kChrDy[19] = {kChr0, kChrH, kChrH2, kChrH, kChrH2, kChrH2, kChrH, kChrH2, kChrH2, kChr0, @@ -243,6 +258,14 @@ class ImmortalEngine : public Engine { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + const uint16 kTBlisterCorners[60] = {7, 1, 1, 1, 1, 1, 5, 3, 1, 1, 1, 1, 1, 3, 5, 3, 5, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 8, 8, 16, 16, 16, 16, 8, + 8, 8, 8, 16, 16, 16, 16, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; + + const uint16 kTLogicalCorners[19] = {1, 1, 1, 1, 16, 8, 1, 8, + 16, 1, 1, 8, 1, 16, 8, 16, + 1, 16, 8}; + // Disk offsets const int kPaletteOffset = 21205; // This is the byte position of the palette data in the disk @@ -382,22 +405,15 @@ class ImmortalEngine : public Engine { CArray2D _programPtrs; Common::Array _objTypePtrs; - // Universe members - uint16 _univRectX = 0; - uint16 _univRectY = 0; - uint16 _numAnims = 0; - uint16 _numCols = 0; - uint16 _numRows = 0; - uint16 _numChrs = 0; - uint16 _num2Cols = 0; - uint16 _num2Rows = 0; - uint16 _num2Cells = 0; - uint16 _num2Chrs = 0; - Common::Array _univ; // This doesn't really need to exist in the way that it did in the source, but for now it will be utilized essentially the same way - uint16 *_CNM; - Common::Array _LCNM; + // Universe members in order of their original memory layout + uint16 *_logicalCNM; // As confusing as this is, we get Logical CNM from the .CNM file, and we get the CNM from the .UNV file uint16 *_modCNM; - uint16 *_modLCNM; + uint16 *_modLogicalCNM; + Univ *_univ; // Pointer to the struct that contains the universe properties + Common::SeekableReadStream *_dataBuffer; // This contains the CNM and the CBM + uint16 *_CNM; // Stands for CHARACTER NUMBER MAP + byte *_CBM; // Stands for CHARACTER BIT MAP (?) + byte *_oldCBM; uint16 _myCNM[(kViewPortCW + 1)][(kViewPortCH + 1)]; uint16 _myModCNM[(kViewPortCW + 1)][(kViewPortCH + 1)]; @@ -534,7 +550,7 @@ GenericSprite _genSprites[6]; */ // Main - int mungeCBM(int numChrs); + int mungeCBM(); void storeAddr(); void mungeSolid(); void mungeLRHC(); diff --git a/engines/immortal/kernal.cpp b/engines/immortal/kernal.cpp index 741ae1af6e40..9a83108d65fb 100644 --- a/engines/immortal/kernal.cpp +++ b/engines/immortal/kernal.cpp @@ -482,13 +482,19 @@ int ImmortalEngine::loadUniv(char mazeNum) { } debug("Size of maze CNM: %ld", mazeCNM->size()); - // The logical CNM contains the contents of mazeN.CNM, with every entry being multiplied by two (why are these byte indexes instead of word indexes in the file?) + // The logical CNM contains the contents of mazeN.CNM, with every entry being bitshifted left once + _logicalCNM = (uint16 *) malloc(mazeCNM->size()); mazeCNM->seek(0); - for (int i = 0; i < mazeCNM->size(); i++) { - _LCNM.push_back(mazeCNM->readUint16LE() << 1); + mazeCNM->read(_logicalCNM, mazeCNM->size()); + for (int i = 0; i < (mazeCNM->size()); i++) { + _logicalCNM[i] <<= 1; } - // Next we load the mazeN.UNV file, which contains the compressed data but is not itself compressed (again, a little silly) + // This is where the source defines the location of the pointers for modCNM, lModCNM, and then the universe properties + // So in similar fasion, here we will create the struct for universe + _univ = new Univ(); + + // Next we load the mazeN.UNV file, which contains the compressed data for multiple things Common::String sUNV = "MAZE" + Common::String(mazeNum) + ".UNV"; Common::SeekableReadStream *mazeUNV = loadIFF(sUNV); if (!mazeUNV) { @@ -497,17 +503,29 @@ int ImmortalEngine::loadUniv(char mazeNum) { } debug("Size of maze UNV: %ld", mazeUNV->size()); + // This is also where the pointer to CNM is defined, because it is 26 bytes after the pointer to Univ. However for our purposes + // These are separate + + // After which, we set data length to be the total size of the file lData = mazeUNV->size(); + // The first data we need is found at index 20 mazeUNV->seek(0x20); - _univRectX = mazeUNV->readUint16LE() << 1; - _numCols = _univRectX >> 6; - _num2Cols = _numCols << 1; + + // The view port of the level is longer than it is wide, so there are more columns than rows + // numCols = rectX / 64 (charW) + _univ->_rectX = mazeUNV->readUint16LE() << 1; + _univ->_numCols = _univ->_rectX >> 6; + _univ->_num2Cols = _univ->_numCols << 1; // univRectY is mazeUNV[22] - _univRectY = mazeUNV->readUint16LE(); - _numRows = _univRectY >> 5; - _num2Rows = _numRows << 1; + // numRows = rectY / 32 (charH) + _univ->_rectY = mazeUNV->readUint16LE(); + _univ->_numRows = _univ->_rectY >> 5; + _univ->_num2Rows = _univ->_numRows << 1; + + // Technically this is done right after decompressing the data, but it is more relevant here for now + _univ->_num2Cells = _univ->_num2Cols * _univ->_numRows; // If there are animations (are there ever?), the univ data is expanded from 26 to include them if (mazeUNV->readUint16LE() != 0) { @@ -515,44 +533,40 @@ int ImmortalEngine::loadUniv(char mazeNum) { lStuff += mazeUNV->readUint16LE(); } - // This is probably not how _univ is actually populated, but just to make sure I don't forget about, let's make sure it has the data - mazeUNV->seek(0); - for (int i = 0; i < lStuff; i++) { - _univ.push_back(mazeUNV->readUint16LE()); - } - - // lData is everything from the .UNV file after the universe variables + // lData is everything from the .UNV file after the universe properties lData -= lStuff; - // The data to uncompress is after the universe data in the file - mazeUNV->seek(lStuff); - Common::SeekableReadStream *pCNM = unCompress((Common::File *) mazeUNV, lData); - - // Now we move the data of the uncompressed CNM into it's actual location - // This data type will likely change, it's just unclear how the munge functions work currently - _CNM = (uint16 *)malloc(pCNM->size()); - pCNM->seek(0); - pCNM->read(_CNM, pCNM->size()); + // At this point in the source, the data after universe properties is moved to the end of the heap - _num2Cells = _num2Cols * _numRows; - _numChrs = 0; + // We then uncompress all of that data, into the place in the heap where the CNM is supposed to be (the Maze Heap) + mazeUNV->seek(lStuff); + _dataBuffer = unCompress((Common::File *) mazeUNV, lData); + debug("size of uncompressed CNM/CBM data %ld", _dataBuffer->size()); // Check every entry in the CNM, with the highest number being the highest number of chrs? - for (int i = 0; i < _num2Cells; i++) { - if (_CNM[i] >= _numChrs) { - _numChrs = _CNM[i]; + _univ->_numChrs = 0; + _dataBuffer->seek(0); + for (int i = 0; i < _univ->_num2Cells; i++) { + uint16 chr = _dataBuffer->readUint16LE(); + if (chr >= _univ->_numChrs) { + _univ->_numChrs = chr; } } - // Inc one more time being 0 counts - _numChrs++; - _num2Chrs = _numChrs << 1; + _dataBuffer->seek(0); + _univ->_numChrs++; // Inc one more time being 0 counts + _univ->_num2Chrs = _univ->_numChrs << 1; - int lCNMCBM = mungeCBM(_num2Chrs); + //int lCNMCBM = mungeCBM(_univ->_num2Chrs); + int lCNMCBM = mungeCBM(); + + debug("nchrs %04X, n2cells %04X, univX %04X, univY %04X, cols %04X, rows %04X, lstuff %04X", _univ->_numChrs, _univ->_num2Cells, _univ->_rectX, _univ->_rectY, _univ->_numCols, _univ->_numRows, lStuff); // We don't actually want to blister any rooms yet, so we give it a POV of (0,0) makeBlisters(0, 0); - return _LCNM.size() + /*_modCNM.size()*/ + /*_modLCNM.size()*/ + _univ.size() + lCNMCBM; + + // We return the final size of everything by adding logicalCNM + modCNM + modLogicalCNM + univ + length of expanded CNM/CBM + return mazeCNM->size() /*+ _modCNM.size() + _modLCNM.size()*/ + lStuff + lCNMCBM; } void ImmortalEngine::makeBlisters(int povX, int povY) { From 55590df288f0d00b7172383724a2c1bd8e2423ef Mon Sep 17 00:00:00 2001 From: Quote58 Date: Wed, 18 Jan 2023 18:32:19 -0500 Subject: [PATCH 363/412] IMMORTAL: Fix whitespace at end of most files --- engines/immortal/bullet.cpp | 2 +- engines/immortal/cycle.cpp | 19 ----------------- engines/immortal/definitions.h | 2 +- engines/immortal/disk.cpp | 38 ---------------------------------- engines/immortal/disk.h | 33 ----------------------------- engines/immortal/door.cpp | 2 +- engines/immortal/drawChr.cpp | 15 +------------- engines/immortal/flameSet.cpp | 21 ------------------- engines/immortal/kernal.cpp | 20 ------------------ engines/immortal/level.cpp | 18 ---------------- engines/immortal/logic.cpp | 19 ----------------- engines/immortal/misc.cpp | 24 --------------------- engines/immortal/room.cpp | 17 --------------- engines/immortal/room.h | 15 -------------- engines/immortal/sprite_list.h | 13 ------------ engines/immortal/sprites.cpp | 38 ---------------------------------- engines/immortal/story.cpp | 25 ---------------------- engines/immortal/story.h | 11 ---------- engines/immortal/univ.cpp | 2 +- engines/immortal/utilities.cpp | 2 +- engines/immortal/utilities.h | 2 +- 21 files changed, 7 insertions(+), 331 deletions(-) diff --git a/engines/immortal/bullet.cpp b/engines/immortal/bullet.cpp index e8770ec881e7..e17e84c29f12 100644 --- a/engines/immortal/bullet.cpp +++ b/engines/immortal/bullet.cpp @@ -29,4 +29,4 @@ namespace Immortal { -} // namespace immortal \ No newline at end of file +} // namespace immortal diff --git a/engines/immortal/cycle.cpp b/engines/immortal/cycle.cpp index 7d505a7a0fce..83d5cda2177c 100644 --- a/engines/immortal/cycle.cpp +++ b/engines/immortal/cycle.cpp @@ -118,22 +118,3 @@ void Room::cycleSetIndex(int c, int f) { } // namespace Immortal - - - - - - - - - - - - - - - - - - - diff --git a/engines/immortal/definitions.h b/engines/immortal/definitions.h index de431f4c9e56..d19c3debad6e 100644 --- a/engines/immortal/definitions.h +++ b/engines/immortal/definitions.h @@ -237,4 +237,4 @@ enum SObjType { } // namespace immortal -#endif \ No newline at end of file +#endif diff --git a/engines/immortal/disk.cpp b/engines/immortal/disk.cpp index dac2d02260d8..e52a96c390c2 100644 --- a/engines/immortal/disk.cpp +++ b/engines/immortal/disk.cpp @@ -429,41 +429,3 @@ Common::SeekableReadStream *ProDOSDisk::createReadStreamForMember(const Common:: } } // namespace Immortal - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/engines/immortal/disk.h b/engines/immortal/disk.h index 57c057a8eb2c..41292574db57 100644 --- a/engines/immortal/disk.h +++ b/engines/immortal/disk.h @@ -213,36 +213,3 @@ Common::HashMap> _files; // Hashma } // namespace Immortal #endif - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/engines/immortal/door.cpp b/engines/immortal/door.cpp index ee905d84e98d..f93487620b4b 100644 --- a/engines/immortal/door.cpp +++ b/engines/immortal/door.cpp @@ -102,4 +102,4 @@ void ImmortalEngine::doorCloseSecret() {} void ImmortalEngine::doorInit() {} void ImmortalEngine::doorClrLock() {} -} // namespace immortal \ No newline at end of file +} // namespace immortal diff --git a/engines/immortal/drawChr.cpp b/engines/immortal/drawChr.cpp index 6f0cfe87a17c..b898849b113c 100644 --- a/engines/immortal/drawChr.cpp +++ b/engines/immortal/drawChr.cpp @@ -43,17 +43,4 @@ void ImmortalEngine::drawURHC(int chr, int x, int y) {} void ImmortalEngine::drawLLHC(int chr, int x, int y) {} void ImmortalEngine::drawLRHC(int chr, int x, int y) {} - - - - - - - - - - - - - -} // namespace immortal \ No newline at end of file +} // namespace immortal diff --git a/engines/immortal/flameSet.cpp b/engines/immortal/flameSet.cpp index 89732a91fde1..e3c0ca2ba7f9 100644 --- a/engines/immortal/flameSet.cpp +++ b/engines/immortal/flameSet.cpp @@ -147,24 +147,3 @@ int Room::flameGetCyc(Flame *f, int first) { } } // namespace immortal - - - - - - - - - - - - - - - - - - - - - diff --git a/engines/immortal/kernal.cpp b/engines/immortal/kernal.cpp index 9a83108d65fb..e03a47597dbb 100644 --- a/engines/immortal/kernal.cpp +++ b/engines/immortal/kernal.cpp @@ -1085,23 +1085,3 @@ void ImmortalEngine::carriageReturn() { } } // namespace Immortal - - - - - - - - - - - - - - - - - - - - diff --git a/engines/immortal/level.cpp b/engines/immortal/level.cpp index 47822b23d18c..5d297ba8e70d 100644 --- a/engines/immortal/level.cpp +++ b/engines/immortal/level.cpp @@ -156,21 +156,3 @@ bool ImmortalEngine::levelIsShowRoom(int r) { } } // namespace immortal - - - - - - - - - - - - - - - - - - diff --git a/engines/immortal/logic.cpp b/engines/immortal/logic.cpp index 20106566dd4c..6a7b5349d232 100644 --- a/engines/immortal/logic.cpp +++ b/engines/immortal/logic.cpp @@ -658,22 +658,3 @@ void ImmortalEngine::doGroan() { } // namespace Immortal - - - - - - - - - - - - - - - - - - - diff --git a/engines/immortal/misc.cpp b/engines/immortal/misc.cpp index 38fe11f6cc19..6a10b596c46d 100644 --- a/engines/immortal/misc.cpp +++ b/engines/immortal/misc.cpp @@ -459,27 +459,3 @@ void ImmortalEngine::standardBeep() { } } // namespace Immortal - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/engines/immortal/room.cpp b/engines/immortal/room.cpp index 5351375162d6..47de77211fb2 100644 --- a/engines/immortal/room.cpp +++ b/engines/immortal/room.cpp @@ -86,20 +86,3 @@ bool Room::getWallNormal(uint8 x, uint8 y, uint8 xPrev, uint8 yPrev, int id) { } } // namespace immortal - - - - - - - - - - - - - - - - - diff --git a/engines/immortal/room.h b/engines/immortal/room.h index 97c25fba2f1d..5811b589e4d9 100644 --- a/engines/immortal/room.h +++ b/engines/immortal/room.h @@ -228,18 +228,3 @@ DataSprite *cycleGetDataSprite(int c); // This takes the place of getFile + ge } // namespace immortal #endif - - - - - - - - - - - - - - - diff --git a/engines/immortal/sprite_list.h b/engines/immortal/sprite_list.h index 26d6fb5ab6ef..3ef3e1307e15 100644 --- a/engines/immortal/sprite_list.h +++ b/engines/immortal/sprite_list.h @@ -297,16 +297,3 @@ enum SpriteName { } // namespace immortal #endif - - - - - - - - - - - - - diff --git a/engines/immortal/sprites.cpp b/engines/immortal/sprites.cpp index c8c61f8ade59..170c8131b1d9 100644 --- a/engines/immortal/sprites.cpp +++ b/engines/immortal/sprites.cpp @@ -245,41 +245,3 @@ void ImmortalEngine::superSprite(DataSprite *dSprite, uint16 pointX, uint16 poin } } // namespace Immortal - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/engines/immortal/story.cpp b/engines/immortal/story.cpp index c0b39350a102..0d598f82b24d 100644 --- a/engines/immortal/story.cpp +++ b/engines/immortal/story.cpp @@ -357,28 +357,3 @@ void ImmortalEngine::initStoryDynamic() { } } // namespace Immortal - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/engines/immortal/story.h b/engines/immortal/story.h index 6bd87d1400fc..f201c8ae0e49 100644 --- a/engines/immortal/story.h +++ b/engines/immortal/story.h @@ -257,14 +257,3 @@ struct Story { } // namespace immortal #endif - - - - - - - - - - - diff --git a/engines/immortal/univ.cpp b/engines/immortal/univ.cpp index 33a8861c8467..9458d645f1e7 100644 --- a/engines/immortal/univ.cpp +++ b/engines/immortal/univ.cpp @@ -28,4 +28,4 @@ void Room::univAddSprite(uint16 vX, uint16 vY, uint16 x, uint16 y, SpriteName s, //g_immortal->addSprite(vX, vY, s, img, x, y, p); } -} // namespace immortal \ No newline at end of file +} // namespace immortal diff --git a/engines/immortal/utilities.cpp b/engines/immortal/utilities.cpp index 0825510193d7..46d098a2fb0d 100644 --- a/engines/immortal/utilities.cpp +++ b/engines/immortal/utilities.cpp @@ -108,4 +108,4 @@ bool Utilities::insideRect(uint8 rectX, uint8 rectY, uint8 w, uint8 h, uint8 poi return false; } -}; // namespace Immortal \ No newline at end of file +}; // namespace Immortal diff --git a/engines/immortal/utilities.h b/engines/immortal/utilities.h index c40904d8aa60..d1a1fcd064ff 100644 --- a/engines/immortal/utilities.h +++ b/engines/immortal/utilities.h @@ -88,4 +88,4 @@ bool insideRect(uint8 rectX, uint8 rectY, uint8 w, uint8 h, uint8 pointX, uint8 }; // namespace Immortal -#endif \ No newline at end of file +#endif From 98247630c2c720008f693b95a17734e88553c60c Mon Sep 17 00:00:00 2001 From: Quote58 Date: Wed, 18 Jan 2023 18:34:18 -0500 Subject: [PATCH 364/412] IMMORTAL: Remove unnecessary commented line --- engines/immortal/compression.cpp | 29 +---------------------------- 1 file changed, 1 insertion(+), 28 deletions(-) diff --git a/engines/immortal/compression.cpp b/engines/immortal/compression.cpp index 0f39f6ff806e..696a635b7db9 100644 --- a/engines/immortal/compression.cpp +++ b/engines/immortal/compression.cpp @@ -250,8 +250,7 @@ void ImmortalEngine::appendList(uint16 codeW, uint16 k, uint16 &hash, uint16 &fi link = hash >> 1; - ptk[prev] = (link << 8) | (ptk[prev] & kMaskLow); - //start[prev] = ((link >> 4) & kMaskLast) | start[prev]; // Yikes this statement is gross + ptk[prev] = (link << 8) | (ptk[prev] & kMaskLow); start[prev] |= (link >> 4) & kMaskLast; found = true; } @@ -260,29 +259,3 @@ void ImmortalEngine::appendList(uint16 codeW, uint16 k, uint16 &hash, uint16 &fi } } // namespace immortal - - - - - - - - - - - - - - - - - - - - - - - - - - From 9cbe97d557da566cf6121c177e566a264a520b3e Mon Sep 17 00:00:00 2001 From: Quote58 Date: Sun, 22 Jan 2023 16:17:49 -0500 Subject: [PATCH 365/412] IMMORTAL: IMMORTAL_IMMORTAL_H -> IMMORTAL_H --- engines/immortal/immortal.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/engines/immortal/immortal.h b/engines/immortal/immortal.h index 47b0207876f7..7b40f084f6ee 100644 --- a/engines/immortal/immortal.h +++ b/engines/immortal/immortal.h @@ -19,8 +19,8 @@ * */ -#ifndef IMMORTAL_IMMORTAL_H -#define IMMORTAL_IMMORTAL_H +#ifndef IMMORTAL_H +#define IMMORTAL_H // Audio is only handled in kernal, therefore it is only needed here #include "audio/mixer.h" From 4103ebe6003f3c2f9b2d2a54caa61eee42b3985f Mon Sep 17 00:00:00 2001 From: Quote58 Date: Sun, 22 Jan 2023 16:25:55 -0500 Subject: [PATCH 366/412] IMMORTAL: Fix formatting for switch statements --- engines/immortal/flameSet.cpp | 20 +-- engines/immortal/kernal.cpp | 72 ++++++----- engines/immortal/logic.cpp | 174 ++++++++++++------------- engines/immortal/misc.cpp | 233 ++++++++++++++++++---------------- 4 files changed, 260 insertions(+), 239 deletions(-) diff --git a/engines/immortal/flameSet.cpp b/engines/immortal/flameSet.cpp index e3c0ca2ba7f9..dcb4c9f4307d 100644 --- a/engines/immortal/flameSet.cpp +++ b/engines/immortal/flameSet.cpp @@ -133,16 +133,16 @@ int Room::flameGetCyc(Flame *f, int first) { // Why is this not indexed further? ie. LDA patternTable,x : STA $00 : LDA ($00),y instead of a branch tree? // Pretty sure CPX 3 times is more than a single LDA (dp),y switch (f->_p) { - case 0: - return cycleNew(flamePatA[r]); - case 1: - return cycleNew(flamePatB[r]); - case 2: - return cycleNew(flamePatC[r]); - case 3: - return cycleNew(flamePatD[r]); - default: - return 0; + case 0: + return cycleNew(flamePatA[r]); + case 1: + return cycleNew(flamePatB[r]); + case 2: + return cycleNew(flamePatC[r]); + case 3: + return cycleNew(flamePatD[r]); + default: + return 0; } } diff --git a/engines/immortal/kernal.cpp b/engines/immortal/kernal.cpp index e03a47597dbb..6c565fae9ffd 100644 --- a/engines/immortal/kernal.cpp +++ b/engines/immortal/kernal.cpp @@ -389,13 +389,14 @@ void ImmortalEngine::printChr(char c) { } switch (c) { - case 'm': - case 'w': - case 'M': - case 'W': - _penX += 8; - default: - break; + case 'm': + case 'w': + case 'M': + case 'W': + _penX += 8; + // fall through + default: + break; } if ((((c >= 'A') && (c <= 'Z'))) || ((c == kGaugeOn) || (c == kGaugeOff))) { @@ -403,17 +404,19 @@ void ImmortalEngine::printChr(char c) { } switch (c) { - case 'i': - _penX -= 3; - break; - case 'j': - case 't': - _penX -= 2; - break; - case 'l': - _penX -= 4; - default: - break; + case 'i': + _penX -= 3; + break; + case 'j': + // fall through + case 't': + _penX -= 2; + break; + case 'l': + _penX -= 4; + // fall through + default: + break; } uint16 x = _penX + kScreenLeft; @@ -1003,27 +1006,30 @@ void ImmortalEngine::fixPause() { // This is a nasty bit of code isn't it? It's accurate to the source though :D switch (_playing) { - case kSongText: - case kSongMaze: - if (_themePaused) { - musicUnPause(_themeID); - break; - } - default: - musicPause(_themeID); + case kSongText: + // fall through + case kSongMaze: + if (_themePaused) { + musicUnPause(_themeID); break; + } + // fall through + default: + musicPause(_themeID); + break; } // Strictly speaking this should probably be a single function called twice, but the source writes out both so I will too switch (_playing) { - case kSongCombat: - if (_themePaused) { - musicUnPause(_combatID); - break; - } - default: - musicPause(_combatID); + case kSongCombat: + if (_themePaused) { + musicUnPause(_combatID); break; + } + // fall through + default: + musicPause(_combatID); + break; } } diff --git a/engines/immortal/logic.cpp b/engines/immortal/logic.cpp index 6a7b5349d232..21d8f0a2fb00 100644 --- a/engines/immortal/logic.cpp +++ b/engines/immortal/logic.cpp @@ -150,16 +150,17 @@ void ImmortalEngine::trapKeys() { */ getInput(); switch (_pressedAction) { - case kActionDBGStep: - _singleStep = true; - break; - case kActionRestart: - gameOver(); - break; - case kActionSound: - toggleSound(); - default: - break; + case kActionDBGStep: + _singleStep = true; + break; + case kActionRestart: + gameOver(); + break; + case kActionSound: + toggleSound(); + // fall through + default: + break; } } @@ -170,13 +171,16 @@ int ImmortalEngine::keyOrButton() { while (button == 0) { getInput(); switch (_pressedAction) { - case kActionKey: - button = _pressedAction; - case kActionFire: - case kActionButton: - button = 13; - default: - break; + case kActionKey: + button = _pressedAction; + break; + case kActionFire: + // fall through + case kActionButton: + button = 13; + // fall through + default: + break; } } return button; @@ -348,43 +352,43 @@ bool ImmortalEngine::fromOldGame() { // This would have been much more clean as a set of tables instead of a long branching tree switch (_certificate[kCertLevel]) { - case 1: - if ((certInv & 2) != 0) { - //room.makeObject(3, 0, kSporesFrame, sporesType); - } - - if ((certInv & 4) != 0) { - //room.makeObject(3, 0, kSporesFrame, wowCharmType); - } + case 1: + if ((certInv & 2) != 0) { + //room.makeObject(3, 0, kSporesFrame, sporesType); + } - break; - case 4: - if ((certInv & 2) != 0) { - //room.makeObject(3, kIsInvisible, kSporesFrame, coffeeType); - } + if ((certInv & 4) != 0) { + //room.makeObject(3, 0, kSporesFrame, wowCharmType); + } - break; - case 3: - if ((certInv & 1) != 0) { - //room.makeObject(3, kIsRunning, kRingFrame, faceRingType); - } + break; + case 4: + if ((certInv & 2) != 0) { + //room.makeObject(3, kIsInvisible, kSporesFrame, coffeeType); + } - break; - case 7: - if ((certInv & 1) != 0) { - //room.makeObject(6, kUsesFireButton, kSporesFrame, bronzeType); - } + break; + case 3: + if ((certInv & 1) != 0) { + //room.makeObject(3, kIsRunning, kRingFrame, faceRingType); + } - if ((certInv & 2) != 0) { - //room.makeObject(3, 0, kSporesFrame, tractorType); - } + break; + case 7: + if ((certInv & 1) != 0) { + //room.makeObject(6, kUsesFireButton, kSporesFrame, bronzeType); + } - if ((certInv & 4) != 0) { - //room.makeObject(3, 0, kSporesFrame, antiType); - } + if ((certInv & 2) != 0) { + //room.makeObject(3, 0, kSporesFrame, tractorType); + } - default: - break; + if ((certInv & 4) != 0) { + //room.makeObject(3, 0, kSporesFrame, antiType); + } + // fall through + default: + break; } levelNew(_level); return true; @@ -434,46 +438,46 @@ void ImmortalEngine::makeCertificate() { // The lo byte of the inventory is used for items that only exist on a specific level, and are removed after switch (_certificate[kCertLevel]) { - case 1: - if (true/*room.monster[kPlayerID].hasObject(sporesType)*/) { - _certificate[kCertInvLo] |= 2; - } - - if (true/*room.monster[kPlayerID].hasObject(wowCharmType)*/) { - _certificate[kCertInvLo] |= 4; - } - - case 3: - if (true/*room.monster[kPlayerID].hasObject(faceRingType)*/) { - _certificate[kCertInvLo] |= 1; - } - - case 4: - if (true/*room.monster[kPlayerID].hasObject(coffeeType)*/) { - _certificate[kCertInvLo] |= 2; - } - - case 7: - if (true/*room.monster[kPlayerID].hasObject(bronzeType)*/) { - _certificate[kCertInvLo] |= 1; - } + case 1: + if (true/*room.monster[kPlayerID].hasObject(sporesType)*/) { + _certificate[kCertInvLo] |= 2; + } - if (true/*room.monster[kPlayerID].hasObject(tractorType)*/) { - _certificate[kCertInvLo] |= 2; - } + if (true/*room.monster[kPlayerID].hasObject(wowCharmType)*/) { + _certificate[kCertInvLo] |= 4; + } + // fall through + case 3: + if (true/*room.monster[kPlayerID].hasObject(faceRingType)*/) { + _certificate[kCertInvLo] |= 1; + } + // fall through + case 4: + if (true/*room.monster[kPlayerID].hasObject(coffeeType)*/) { + _certificate[kCertInvLo] |= 2; + } + // fall through + case 7: + if (true/*room.monster[kPlayerID].hasObject(bronzeType)*/) { + _certificate[kCertInvLo] |= 1; + } - if (true/*room.monster[kPlayerID].hasObject(antiType)*/) { - _certificate[kCertInvLo] |= 4; - } + if (true/*room.monster[kPlayerID].hasObject(tractorType)*/) { + _certificate[kCertInvLo] |= 2; + } - default: - _lastCertLen = 13; - uint8 checksum[4]; - calcCheckSum(_lastCertLen, checksum); - _certificate[0] = checksum[0]; - _certificate[1] = checksum[1]; - _certificate[2] = checksum[2]; - _certificate[3] = checksum[3]; + if (true/*room.monster[kPlayerID].hasObject(antiType)*/) { + _certificate[kCertInvLo] |= 4; + } + // fall through + default: + _lastCertLen = 13; + uint8 checksum[4]; + calcCheckSum(_lastCertLen, checksum); + _certificate[0] = checksum[0]; + _certificate[1] = checksum[1]; + _certificate[2] = checksum[2]; + _certificate[3] = checksum[3]; } } diff --git a/engines/immortal/misc.cpp b/engines/immortal/misc.cpp index 6a10b596c46d..938488fb84f6 100644 --- a/engines/immortal/misc.cpp +++ b/engines/immortal/misc.cpp @@ -93,104 +93,108 @@ bool ImmortalEngine::textSub(Str s, FadeType f, int n) { while (done == false) { switch (text[index]) { - case '@': - case '=': - case char(0): - done = true; - // This is so the while loop can be a little cleaner - index--; - break; - case '&': - textCR(); - break; - case '$': - printByte(n); + case '@': + case '=': + case char(0): + done = true; + // This is so the while loop can be a little cleaner + index--; + break; + case '&': + textCR(); + break; + case '$': + printByte(n); + copyToScreen(); + break; + case '_': + myFadeIn(); + _slowText = 1; + break; + case '<': + _slowText = 0; + break; + case '>': + _formatted = 0; + break; + case '\\': + normalFadeOut(); + break; + case '/': + slowFadeOut(); + break; + case '|': + normalFadeIn(); + break; + case '}': + _formatted = 1; + break; + case ']': + myDelay(40); + break; + case '{': + index++; + myDelay(text[index]); + break; + case '*': + textPageBreak(text, index); + break; + case '[': + textAutoPageBreak(); + break; + case '#': + index++; + drawIcon(text[index]); + break; + case '~': + text = _strPtrs[(int)text[index + 1]]; + index = -1; + break; + case '^': + center(); + break; + case '%': + return yesNo(); + case '+': + chr = 0x27; + break; + case '(': + chr = 0x60; + break; + default: + chr = text[index]; + _collumn++; + if (chr == ' ') { + if (text[index + 1] == '~') { + text = _strPtrs[(int)text[index + 2]]; + index = -1; + } + textDoSpace(text, index); + + } else { + printChr(chr); + // We need this to show up now, not when the frame ends, so we have to update the screen here copyToScreen(); - break; - case '_': - myFadeIn(); - _slowText = 1; - break; - case '<': - _slowText = 0; - break; - case '>': - _formatted = 0; - break; - case '\\': - normalFadeOut(); - break; - case '/': - slowFadeOut(); - break; - case '|': - normalFadeIn(); - break; - case '}': - _formatted = 1; - break; - case ']': - myDelay(40); - break; - case '{': - index++; - myDelay(text[index]); - break; - case '*': - textPageBreak(text, index); - break; - case '[': - textAutoPageBreak(); - break; - case '#': - index++; - drawIcon(text[index]); - break; - case '~': - text = _strPtrs[(int)text[index + 1]]; - index = -1; - break; - case '^': - center(); - break; - case '%': - return yesNo(); - case '+': - chr = 0x27; - break; - case '(': - chr = 0x60; - break; - default: - chr = text[index]; - _collumn++; - if (chr == ' ') { - if (text[index + 1] == '~') { - text = _strPtrs[(int)text[index + 2]]; - index = -1; - } - textDoSpace(text, index); - - } else { - printChr(chr); - // We need this to show up now, not when the frame ends, so we have to update the screen here - copyToScreen(); - if (_slowText != 0) { - myDelay(5); - switch (chr) { - case '?': - case ':': - myDelay(13); - case '.': - myDelay(13); - case ',': - myDelay(13); - default: - break; - } + if (_slowText != 0) { + myDelay(5); + switch (chr) { + case '?': + // fall through + case ':': + myDelay(13); + // fall through + case '.': + myDelay(13); + // fall through + case ',': + myDelay(13); + // fall through + default: + break; } } - break; + } + break; } if (index == 0xFF) { debug("String too long!"); @@ -272,14 +276,19 @@ void ImmortalEngine::textDoSpace(Common::String s, int index) { while (foundEnd == false) { index++; switch (s[index]) { - case '=': - case '@': - case '%': - case '[': - case ' ': - foundEnd = true; - default: - break; + case '=': + // fall through + case '@': + // fall through + case '%': + // fall through + case '[': + // fall through + case ' ': + foundEnd = true; + // fall through + default: + break; } } if (((index - start) + _collumn) >= kMaxCollumns) { @@ -383,14 +392,16 @@ void ImmortalEngine::myDelay(int j) { // Otherwise, we delay by different amounts based on what's held down switch (type) { - case 1: - Utilities::delay4(1); - break; - case 0: - Utilities::delay(1); - case 2: - default: - break; + case 1: + Utilities::delay4(1); + break; + case 0: + Utilities::delay(1); + // fall through + case 2: + // fall through + default: + break; } j--; From 7e0c5b39abc444aa88d9e32bdf655b32d7f7da9b Mon Sep 17 00:00:00 2001 From: Quote58 Date: Sun, 22 Jan 2023 16:29:08 -0500 Subject: [PATCH 367/412] IMMORTAL: Fix formatting for casting --- engines/immortal/kernal.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engines/immortal/kernal.cpp b/engines/immortal/kernal.cpp index 6c565fae9ffd..7677cafab601 100644 --- a/engines/immortal/kernal.cpp +++ b/engines/immortal/kernal.cpp @@ -486,7 +486,7 @@ int ImmortalEngine::loadUniv(char mazeNum) { debug("Size of maze CNM: %ld", mazeCNM->size()); // The logical CNM contains the contents of mazeN.CNM, with every entry being bitshifted left once - _logicalCNM = (uint16 *) malloc(mazeCNM->size()); + _logicalCNM = (uint16 *)malloc(mazeCNM->size()); mazeCNM->seek(0); mazeCNM->read(_logicalCNM, mazeCNM->size()); for (int i = 0; i < (mazeCNM->size()); i++) { From 8a1c1764afb84ec3bcd4960c9c4e70c9c5402a58 Mon Sep 17 00:00:00 2001 From: Quote58 Date: Sun, 22 Jan 2023 16:40:20 -0500 Subject: [PATCH 368/412] IMMORTAL: Add TODO comments for unimplemented methods --- engines/immortal/door.cpp | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/engines/immortal/door.cpp b/engines/immortal/door.cpp index f93487620b4b..187268dab316 100644 --- a/engines/immortal/door.cpp +++ b/engines/immortal/door.cpp @@ -60,40 +60,65 @@ void ImmortalEngine::doorNew(SDoor door) { _doors.push_back(d); } - +/* TODO + * Not implemented yet + */ int ImmortalEngine::findDoorTop(int x, int y) { return 0; } +/* TODO + * Not implemented yet + */ int ImmortalEngine::findDoor(int x, int y) { return 0; } +/* TODO + * Not implemented yet + */ bool ImmortalEngine::doLockStuff(int d, MonsterID m, int top) { return true; } +/* TODO + * Not implemented yet + */ bool ImmortalEngine::inDoorTop(int x, int y, MonsterID m) { return true; } +/* TODO + * Not implemented yet + */ bool ImmortalEngine::inDoor(int x, int y, MonsterID m) { return true; } +/* TODO + * Not implemented yet + */ int ImmortalEngine::doorDoStep(MonsterID m, int d, int index) { return 0; } +/* TODO + * Not implemented yet + */ int ImmortalEngine::doorSetOn(int d) { return 0; } +/* TODO + * Not implemented yet + */ int ImmortalEngine::doorComeOut(MonsterID m) { return 0; } -// These functions are not yet implemented +/* TODO + * These functions are not yet implemented + */ void ImmortalEngine::doorSetLadders(MonsterID m) {} void ImmortalEngine::doorDrawAll() {} void ImmortalEngine::doorOnDoorMat() {} From 9c2e1a55a8c00abdd14d8a42a1f7bf4f2d55c554 Mon Sep 17 00:00:00 2001 From: Quote58 Date: Sun, 22 Jan 2023 16:41:22 -0500 Subject: [PATCH 369/412] IMMORTAL: Remove unused debug console channel method --- engines/immortal/detection.cpp | 5 ----- engines/immortal/detection.h | 3 --- 2 files changed, 8 deletions(-) diff --git a/engines/immortal/detection.cpp b/engines/immortal/detection.cpp index 3f3615cfe766..ce19d7f2b7d1 100644 --- a/engines/immortal/detection.cpp +++ b/engines/immortal/detection.cpp @@ -33,11 +33,6 @@ #include "immortal/detection.h" #include "immortal/detection_tables.h" -const DebugChannelDef ImmortalMetaEngineDetection::debugFlagList[] = { - { Immortal::kDebugTest, "Test", "Test debug channel" }, - DEBUG_CHANNEL_END -}; - ImmortalMetaEngineDetection::ImmortalMetaEngineDetection() : AdvancedMetaEngineDetection(Immortal::gameDescriptions, sizeof(ADGameDescription), Immortal::immortalGames) { } diff --git a/engines/immortal/detection.h b/engines/immortal/detection.h index fa4c3fcbf9a8..69699995ce4e 100644 --- a/engines/immortal/detection.h +++ b/engines/immortal/detection.h @@ -54,9 +54,6 @@ class ImmortalMetaEngineDetection : public AdvancedMetaEngineDetection { return "(c)1990 Will Harvey & Electronic Arts"; } - const DebugChannelDef *getDebugChannels() const override { - return debugFlagList; - } }; #endif From deb379462670a49dd76d12d6fe8d5d31a821ef52 Mon Sep 17 00:00:00 2001 From: Quote58 Date: Mon, 30 Jan 2023 21:01:19 -0500 Subject: [PATCH 370/412] IMMORTAL: Use AStyle to fix indentation and format issues across all files --- engines/immortal/compression.cpp | 40 +-- engines/immortal/cycle.cpp | 6 +- engines/immortal/disk.cpp | 32 +-- engines/immortal/disk.h | 106 ++++---- engines/immortal/flameSet.cpp | 12 +- engines/immortal/immortal.cpp | 36 +-- engines/immortal/immortal.h | 429 ++++++++++++++++--------------- engines/immortal/kernal.cpp | 143 ++++++----- engines/immortal/level.cpp | 2 +- engines/immortal/logic.cpp | 56 ++-- engines/immortal/metaengine.cpp | 12 +- engines/immortal/misc.cpp | 52 ++-- engines/immortal/room.h | 26 +- engines/immortal/sprite_list.h | 6 +- engines/immortal/sprites.cpp | 16 +- engines/immortal/story.cpp | 386 +++++++++++++-------------- engines/immortal/story.h | 92 +++---- engines/immortal/utilities.cpp | 2 +- 18 files changed, 733 insertions(+), 721 deletions(-) diff --git a/engines/immortal/compression.cpp b/engines/immortal/compression.cpp index 696a635b7db9..08d7055149e0 100644 --- a/engines/immortal/compression.cpp +++ b/engines/immortal/compression.cpp @@ -48,8 +48,8 @@ Common::SeekableReadStream *ImmortalEngine::unCompress(Common::File *src, int sr // The 20k bytes of memory that compression gets allocated to work with for the dictionary and the stack of chars uint16 start[0x4000]; // Really needs a better name, remember to do this future me - uint16 ptk[0x4000]; // Pointer To Keys? Also needs a better name - byte stack[0x4000]; // Stack of chars to be stored + uint16 ptk[0x4000]; // Pointer To Keys? Also needs a better name + byte stack[0x4000]; // Stack of chars to be stored // These are the main variables we'll need for this uint16 findEmpty; @@ -73,8 +73,8 @@ Common::SeekableReadStream *ImmortalEngine::unCompress(Common::File *src, int sr } finalChar = code; - oldCode = code; - myCode = code; + oldCode = code; + myCode = code; outByte = code & kMaskLow; dstW.writeByte(outByte); // Take just the lower byte and write it the output @@ -85,17 +85,17 @@ Common::SeekableReadStream *ImmortalEngine::unCompress(Common::File *src, int sr code = getInputCode(carry, src, srcLen, evenOdd); // Get the next code if (carry == true) { - index = code << 1; + index = code << 1; inputCode = code; - myCode = code; - + myCode = code; + // Split up the conditional statement to be easier to follow uint16 cond; cond = start[index] & kMaskLast; cond |= ptk[index]; if ((cond & kMaskHigh) == 0) { // Empty code - index = topStack; + index = topStack; outByte = finalChar & kMaskLow; stack[index] = outByte; topStack++; @@ -105,9 +105,9 @@ Common::SeekableReadStream *ImmortalEngine::unCompress(Common::File *src, int sr // :nextsymbol index = myCode << 1; while (index >= 0x200) { - myCode = start[index] & kMask12Bit; + myCode = start[index] & kMask12Bit; outByte = ptk[index] & kMaskLow; - index = topStack; + index = topStack; stack[index] = outByte; topStack++; index = myCode << 1; @@ -115,7 +115,7 @@ Common::SeekableReadStream *ImmortalEngine::unCompress(Common::File *src, int sr // :singlechar finalChar = (myCode >> 1); - outByte = finalChar & kMaskLow; + outByte = finalChar & kMaskLow; dstW.writeByte(outByte); // :dump @@ -126,8 +126,8 @@ Common::SeekableReadStream *ImmortalEngine::unCompress(Common::File *src, int sr } topStack = 0; - code = getMember(oldCode, finalChar, findEmpty, start, ptk); - oldCode = inputCode; + code = getMember(oldCode, finalChar, findEmpty, start, ptk); + oldCode = inputCode; } } @@ -142,12 +142,12 @@ void ImmortalEngine::setupDictionary(uint16 start[], uint16 ptk[], uint16 &findE // Clear the whole dictionary for (int i = 0x3FFF; i >= 0; i--) { start[i] = 0; - ptk[i] = 0; + ptk[i] = 0; } // Set the initial 256 bytes to be value 256, these are the characters without extensions for (int i = 255; i >= 0; i--) { - ptk[i] = 256; + ptk[i] = 256; } // This shouldn't really be done inside the function, but for the sake of consistency with the source, we will @@ -177,7 +177,7 @@ int ImmortalEngine::getInputCode(bool &carry, Common::File *src, int &srcLen, ui uint16 ImmortalEngine::getMember(uint16 codeW, uint16 k, uint16 &findEmpty, uint16 start[], uint16 ptk[]) { // This function is effectively void, as the return value is only used in compression - + // k and codeW are local variables with the value of oldCode and finalChar uint16 hash; @@ -194,7 +194,7 @@ uint16 ImmortalEngine::getMember(uint16 codeW, uint16 k, uint16 &findEmpty, uint uint16 b = ptk[hash] & kMaskHigh; if (a | b) { start[hash] = codeW; - ptk[hash] = k | 0x100; + ptk[hash] = k | 0x100; return ptk[hash]; } @@ -228,7 +228,7 @@ void ImmortalEngine::appendList(uint16 codeW, uint16 k, uint16 &hash, uint16 &fi prev = hash; if (hash >= 0x200) { setupDictionary(start, ptk, findEmpty); - + } else { bool found = false; while (found == false) { @@ -244,9 +244,9 @@ void ImmortalEngine::appendList(uint16 codeW, uint16 k, uint16 &hash, uint16 &fi cond |= ptk[hash]; if ((cond & kMaskHigh) == 0) { - findEmpty = hash; + findEmpty = hash; start[hash] = codeW; - ptk[hash] = k | 0x100; + ptk[hash] = k | 0x100; link = hash >> 1; diff --git a/engines/immortal/cycle.cpp b/engines/immortal/cycle.cpp index 83d5cda2177c..8441e1cd7b7a 100644 --- a/engines/immortal/cycle.cpp +++ b/engines/immortal/cycle.cpp @@ -34,9 +34,9 @@ * Usually used as an index into the frame array by subtracting the frame enum first. * Here's the movement of data from ROM to RAM: * list of Cycles on heap (cyc) - * | + * | * list of word pointers in wram to Cycles (cycPtrs) - * | + * | * list of lexical pointers as byte indexes into word pointers (cycID -> cyclist) */ @@ -89,7 +89,7 @@ int Room::cycleGetFrame(int c) { * STA DP : LDA (DP) */ return g_immortal->_cycPtrs[g_immortal->_cycles[c]._cycList]._frames[g_immortal->_cycles[c]._index]; - } +} int Room::cycleGetNumFrames(int c) { // For whatever reason, this is not a property of the cycle, so it has to be re-calculated each time diff --git a/engines/immortal/disk.cpp b/engines/immortal/disk.cpp index e52a96c390c2..5767aefac6c4 100644 --- a/engines/immortal/disk.cpp +++ b/engines/immortal/disk.cpp @@ -29,13 +29,13 @@ namespace Immortal { // --- ProDOSFile methods --- ProDOSFile::ProDOSFile(char name[15], uint8 type, uint16 tBlk, uint32 eof, uint16 bPtr, Common::File *disk) - : _type(type) - , _totalBlocks(tBlk) - , _eof(eof) - , _blockPtr(bPtr) - , _disk(disk) { - strncpy(_name, name, 15); - } + : _type(type) + , _totalBlocks(tBlk) + , _eof(eof) + , _blockPtr(bPtr) + , _disk(disk) { + strncpy(_name, name, 15); +} /* For debugging purposes, this prints the meta data of a file */ @@ -81,7 +81,7 @@ int ProDOSFile::parseIndexBlock(byte *memOffset, int blockNum, int rem) const { for (int i = 0; i < blockNum; i++) { dataSize = (i == (blockNum - 1)) ? rem : ProDOSDisk::kBlockSize; dataOffset = _disk->readByte(); // Low byte is first - + /* The cursor needs to know where to get the next pointer from in the index block, * but it also needs to jump to the offset of data to read it, so we need to preserve * the position in the index block it was in before. @@ -93,7 +93,7 @@ int ProDOSFile::parseIndexBlock(byte *memOffset, int blockNum, int rem) const { getDataBlock(memOffset + readSize, dataOffset, dataSize); readSize += dataSize; - + // And now we resume the position before this call _disk->seek(diskPos); } @@ -129,7 +129,7 @@ Common::SeekableReadStream *ProDOSFile::createReadStream() const { } else if (_type == kFileTypeSapling) { _disk->seek(indexBlock); parseIndexBlock(finalData, _totalBlocks - 1, remainder); - + } else { // If it's not a seed and not a sapling, it's a tree. _disk->seek(indexBlock); @@ -222,7 +222,7 @@ void ProDOSDisk::getDirectoryHeader(DirHeader *h) { getHeader(h); h->_parentBlockPtr = _disk.readUint16LE(); h->_parentEntryIndex = _disk.readByte(); - h->_parentEntryLen = _disk.readUint16LE(); + h->_parentEntryLen = _disk.readUint16LE(); } /* This is a little sneaky, but since the bulk of the header is the same, we're just going to pretend the volume header @@ -233,7 +233,7 @@ void ProDOSDisk::getVolumeHeader(VolHeader *h) { getHeader((DirHeader *)h); h->_bitmapPtr = _disk.readUint16LE(); h->_volBlocks = _disk.readUint16LE(); - _volBlocks = h->_volBlocks; + _volBlocks = h->_volBlocks; } /* Getting a file entry header is very similar to getting a header, but with different data. */ @@ -280,7 +280,7 @@ void ProDOSDisk::searchDirectory(DirHeader *h, uint16 p, uint16 n, Common::Strin for (int i = 0; i < h->_fileCount; i++) { // When we have read all the files for a given block (_entriesPerBlock), we need to change to the next block of the directory if (parsedFiles == h->_entriesPerBlock) { - parsedFiles = 0; + parsedFiles = 0; _disk.seek(n * kBlockSize); p = _disk.readUint16LE(); n = _disk.readUint16LE(); @@ -300,8 +300,8 @@ void ProDOSDisk::searchDirectory(DirHeader *h, uint16 p, uint16 n, Common::Strin _files.setVal(fileName, Common::SharedPtr(currFile)); _disk.seek(currPos); - - // Otherwise, if it is a subdirectory, we want to explore that subdirectory + + // Otherwise, if it is a subdirectory, we want to explore that subdirectory } else if (fileEntry._type == kFileTypeSubDir) { _disk.seek(fileEntry._blockPtr * kBlockSize); @@ -371,7 +371,7 @@ bool ProDOSDisk::open(const Common::String filename) { ProDOSDisk::ProDOSDisk(const Common::String filename) { if (open(filename)) { - debug ("%s has been loaded", filename.c_str()); + debug("%s has been loaded", filename.c_str()); } } diff --git a/engines/immortal/disk.h b/engines/immortal/disk.h index 41292574db57..284e0f794a0b 100644 --- a/engines/immortal/disk.h +++ b/engines/immortal/disk.h @@ -83,7 +83,7 @@ enum FileExt { class ProDOSFile : public Common::ArchiveMember { public: ProDOSFile(char name[16], uint8 type, uint16 tBlk, uint32 eof, uint16 bPtr, Common::File *disk); - ~ProDOSFile() {}; // File does not need a destructor, because the file it reads from is a pointer to Disk, and Disk has a destructor + ~ProDOSFile() {}; // File does not need a destructor, because the file it reads from is a pointer to Disk, and Disk has a destructor // -- These are the Common::ArchiveMember related functions -- Common::String getName() const override; // Returns _name @@ -95,12 +95,12 @@ class ProDOSFile : public Common::ArchiveMember { void printInfo(); private: - char _name[16]; - uint8 _type; // As defined by enum FileType - uint16 _blockPtr; // Block index in volume of index block or data + char _name[16]; + uint8 _type; // As defined by enum FileType + uint16 _blockPtr; // Block index in volume of index block or data uint16 _totalBlocks; - uint32 _eof; // End Of File, used generally as size (exception being sparse files) - Common::File *_disk; // This is a pointer because it is the same _disk as in ProDosDisk, passed to the file object + uint32 _eof; // End Of File, used generally as size (exception being sparse files) + Common::File *_disk; // This is a pointer because it is the same _disk as in ProDosDisk, passed to the file object }; /* This class defines the entire disk volume. Upon using the open() method, @@ -126,76 +126,76 @@ class ProDOSDisk : public Common::Archive { Common::SeekableReadStream *createReadStreamForMember(const Common::Path &path) const override; private: - byte _loader1[kBlockSize]; // There's not much reason for these to be needed, but I included them just in case - byte _loader2[kBlockSize]; -Common::String _name; // Name of volume - Common::File _disk; // The volume file itself - int _volBlocks; // Total blocks in volume - byte *_volBitmap; // This can determine if the volume is corrupt as it contains a bit for every block, where 0 = unused, 1 = used -Common::HashMap> _files; // Hashmap of files in the volume, where key=Path, Value=ProDOSFile + byte _loader1[kBlockSize]; // There's not much reason for these to be needed, but I included them just in case + byte _loader2[kBlockSize]; + Common::String _name; // Name of volume + Common::File _disk; // The volume file itself + int _volBlocks; // Total blocks in volume + byte *_volBitmap; // This can determine if the volume is corrupt as it contains a bit for every block, where 0 = unused, 1 = used + Common::HashMap> _files; // Hashmap of files in the volume, where key=Path, Value=ProDOSFile struct Date { - uint8 _day; - uint8 _month; - uint8 _year; + uint8 _day; + uint8 _month; + uint8 _year; }; struct Time { - uint8 _hour; - uint8 _minute; + uint8 _hour; + uint8 _minute; }; struct VolHeader { - uint8 _type; // Not really important for a volume header, as this will always be F - uint8 _nameLen; - char _name[16]; - byte _reserved[8]; // Extra space reserved for possible future uses, not important - Date _date; - Time _time; - uint8 _ver; - uint8 _minVer; // Should pretty much always be 0 as far as I know - uint8 _access; // If this ends up useful, there should be an enum for the access values - uint8 _entryLen; // Always 27 in ProDOS 1.0 - uint8 _entriesPerBlock; // Always 0D in ProDOS 1.0 + uint8 _type; // Not really important for a volume header, as this will always be F + uint8 _nameLen; + char _name[16]; + byte _reserved[8]; // Extra space reserved for possible future uses, not important + Date _date; + Time _time; + uint8 _ver; + uint8 _minVer; // Should pretty much always be 0 as far as I know + uint8 _access; // If this ends up useful, there should be an enum for the access values + uint8 _entryLen; // Always 27 in ProDOS 1.0 + uint8 _entriesPerBlock; // Always 0D in ProDOS 1.0 uint16 _fileCount; // Number of files across all data blocks in this directory uint16 _bitmapPtr; // Block pointer to the keyblock of the bitmap for the entire volume uint16 _volBlocks; // Blocks in entire volume }; struct DirHeader { - uint8 _type; - uint8 _nameLen; - char _name[16]; - byte _reserved[8]; - Date _date; - Time _time; - uint8 _ver; - uint8 _minVer; - uint8 _access; - uint8 _entryLen; - uint8 _entriesPerBlock; + uint8 _type; + uint8 _nameLen; + char _name[16]; + byte _reserved[8]; + Date _date; + Time _time; + uint8 _ver; + uint8 _minVer; + uint8 _access; + uint8 _entryLen; + uint8 _entriesPerBlock; uint16 _fileCount; uint16 _parentBlockPtr; // These values allow ProDOS to navigate back out of a directory, but they aren't really needed by the class to navigate - uint8 _parentEntryIndex; // Index in the current directory - uint8 _parentEntryLen; // This is always 27 in ProDOS 1.0 + uint8 _parentEntryIndex; // Index in the current directory + uint8 _parentEntryLen; // This is always 27 in ProDOS 1.0 }; struct FileEntry { - uint8 _type; // 0 = inactive, 1-3 = file, 4 = pascal area, 14 = subdirectory, 15 = volume directory - uint8 _nameLen; - char _name[16]; - uint8 _ext; // File extension, uses the enum FileExt + uint8 _type; // 0 = inactive, 1-3 = file, 4 = pascal area, 14 = subdirectory, 15 = volume directory + uint8 _nameLen; + char _name[16]; + uint8 _ext; // File extension, uses the enum FileExt uint16 _blockPtr; // Block pointer to data for seedling, index block for sapling, or master block for tree uint16 _totalBlocks; // Really important to remember this is the total *including* the index block uint32 _eof; // This is a long (3 bytes, read low to high) value representing the total readable data in a file (unless it's a sparse file, be careful!) - Date _date; - Time _time; - uint8 _ver; - uint8 _minVer; - uint8 _access; + Date _date; + Time _time; + uint8 _ver; + uint8 _minVer; + uint8 _access; uint16 _varUse; - Date _modDate; - Time _modTime; + Date _modDate; + Time _modTime; uint16 _dirHeadPtr; // Pointer to the key block of the directory that contains this file entry }; diff --git a/engines/immortal/flameSet.cpp b/engines/immortal/flameSet.cpp index dcb4c9f4307d..f9a7964f8d31 100644 --- a/engines/immortal/flameSet.cpp +++ b/engines/immortal/flameSet.cpp @@ -111,12 +111,14 @@ int Room::flameGetCyc(Flame *f, int first) { * This gives us a random entry within the array to start at. */ CycID flamePatA[] = {kCycFNormal0, kCycFNormal1, kCycFNormal2, - kCycFNormal0, kCycFNormal1, kCycFNormal2, - kCycFNormal0, kCycFNormal1, kCycFNormal2, - kCycFNormal0, kCycFNormal1, kCycFNormal2}; + kCycFNormal0, kCycFNormal1, kCycFNormal2, + kCycFNormal0, kCycFNormal1, kCycFNormal2, + kCycFNormal0, kCycFNormal1, kCycFNormal2 + }; CycID flamePatB[] = {kCycFCandleBurst, kCycFCandleSway, kCycFCandleJump, - kCycFCandleLeap, kCycFCandleFlicker, - kCycFCandleFlicker, kCycFCandleFlicker, kCycFCandleFlicker}; + kCycFCandleLeap, kCycFCandleFlicker, + kCycFCandleFlicker, kCycFCandleFlicker, kCycFCandleFlicker + }; CycID flamePatC[] = {kCycFOff}; CycID flamePatD[] = {kCycFFlicker0, kCycFFlicker1, kCycFFlicker2}; diff --git a/engines/immortal/immortal.cpp b/engines/immortal/immortal.cpp index a47301a3cf25..e7c5ca7913b1 100644 --- a/engines/immortal/immortal.cpp +++ b/engines/immortal/immortal.cpp @@ -89,7 +89,7 @@ uint16 ImmortalEngine::mult16(uint16 a, uint16 b) { /* We aren't using the game's multiplication function (mult16), but we do want * to retain the ability to drop the second word, without doing (uint16) every time */ - return (uint16) (a * b); + return (uint16)(a * b); } // ----------------------------------------------------- @@ -141,7 +141,7 @@ Common::Error ImmortalEngine::run() { _mainSurface = new Graphics::Surface(); _mainSurface->create(kResH, kResV, Graphics::PixelFormat::createFormatCLUT8()); - + _screenBuff = new byte[kScreenSize]; if (initDisks() != Common::kNoError) { @@ -156,33 +156,33 @@ Common::Error ImmortalEngine::run() { _penY = 7; _penX = 1; - initStoryStatic(); // Init the arrays of static story elements (done at compile time in the source) - loadPalette(); // We need to grab the palette from the disk first + initStoryStatic(); // Init the arrays of static story elements (done at compile time in the source) + loadPalette(); // We need to grab the palette from the disk first // This is the equivalent of Main->InitGraphics->MyClearScreen in Driver - useNormal(); // The first palette will be the default - - loadFont(); // Load the font sprites - loadWindow(); // Load the window background - loadSingles("Song A"); // Music - loadSprites(); // Get all the sprite data into memory + useNormal(); // The first palette will be the default + + loadFont(); // Load the font sprites + loadWindow(); // Load the window background + loadSingles("Song A"); // Music + loadSprites(); // Get all the sprite data into memory _playing = kSongNothing; _themePaused = 0; - clearSprites(); // Clear the sprites before we start + clearSprites(); // Clear the sprites before we start // This is where the request play disk would happen, but that's not needed here - logicInit(); // Init the game logic + logicInit(); // Init the game logic _err = Common::kNoError; while (!shouldQuit()) { - /* The game loop runs at 60fps, which is 16 milliseconds per frame. - * This loop keeps that time by getting the time in milliseconds at the start of the loop, - * then again at the end, and the difference between them is the remainder - * of the frame budget. If that remainder is within the 16 millisecond budget, - * then it delays ScummVM for the remainder. If it is 0 or negative, then it continues. - */ + /* The game loop runs at 60fps, which is 16 milliseconds per frame. + * This loop keeps that time by getting the time in milliseconds at the start of the loop, + * then again at the end, and the difference between them is the remainder + * of the frame budget. If that remainder is within the 16 millisecond budget, + * then it delays ScummVM for the remainder. If it is 0 or negative, then it continues. + */ int64 loopStart = g_system->getMillis(); // Main diff --git a/engines/immortal/immortal.h b/engines/immortal/immortal.h index 7b40f084f6ee..2e2b520b4901 100644 --- a/engines/immortal/immortal.h +++ b/engines/immortal/immortal.h @@ -70,11 +70,11 @@ namespace Immortal { enum InputAction { kActionNothing, kActionKey, - kActionRestart, // Key "R" <-- Debug? + kActionRestart, // Key "R" <-- Debug? kActionSound, kActionFire, - kActionButton, // Does this just refer to whatever is not the fire button? - kActionDBGStep // Debug key for moving engine forward one frame at a time + kActionButton, // Does this just refer to whatever is not the fire button? + kActionDBGStep // Debug key for moving engine forward one frame at a time }; enum ButtonHeldMask { @@ -154,18 +154,18 @@ struct GenericSprite { // Doors are a property of the level, not the room, they define the connections between rooms struct Door { - uint8 _x = 0; - uint8 _y = 0; - uint8 _fromRoom = 0; - uint8 _toRoom = 0; + uint8 _x = 0; + uint8 _y = 0; + uint8 _fromRoom = 0; + uint8 _toRoom = 0; uint8 _busyOnRight = 0; - uint8 _on = 0; + uint8 _on = 0; }; // Universe is a set of properties for the entire level, nor just the room struct Univ { - uint16 _rectX = 0; - uint16 _rectY = 0; + uint16 _rectX = 0; + uint16 _rectY = 0; uint16 _numAnims = 0; uint16 _numCols = 0; uint16 _numRows = 0; @@ -199,10 +199,10 @@ class ImmortalEngine : public Engine { /* Terrible functions because C doesn't like * bit manipulation enough */ - uint16 xba(uint16 ab); // This just replicates the XBA command from the 65816, because flipping the byte order is somehow not a common library function??? - uint16 rol(uint16 ab, int n); // Rotate bits left by n - uint16 ror(uint16 ab, int n); // Rotate bits right by n - uint16 mult16(uint16 a, uint16 b); // Just avoids using (uint16) everywhere, and is slightly closer to the original + uint16 xba(uint16 ab); // This just replicates the XBA command from the 65816, because flipping the byte order is somehow not a common library function??? + uint16 rol(uint16 ab, int n); // Rotate bits left by n + uint16 ror(uint16 ab, int n); // Rotate bits right by n + uint16 mult16(uint16 a, uint16 b); // Just avoids using (uint16) everywhere, and is slightly closer to the original /* * --- Members --- @@ -219,239 +219,244 @@ class ImmortalEngine : public Engine { const int kMaxCertificate = 16; // Screen constants - const int kScreenW__ = 128; // ??? labeled in source as SCREENWIDTH - const int kScreenH__ = 128; // ??? + const int kScreenW__ = 128; // ??? labeled in source as SCREENWIDTH + const int kScreenH__ = 128; // ??? const int kViewPortW = 256; const int kViewPortH = 128; - const int kScreenSize = (kResH * kResV) * 2; // The size of the screen buffer is (320x200) * 2 byte words + const int kScreenSize = (kResH *kResV) * 2; // The size of the screen buffer is (320x200) * 2 byte words const uint16 kScreenLeft = 32; const uint16 kScreenTop = 20; const uint8 kTextLeft = 8; const uint8 kTextTop = 4; const uint8 kGaugeX = 0; - const uint8 kGaugeY = -13; // ??? - const uint16 kScreenBMW = 160; // Screen BitMap Width? - const uint16 kChrW = 64; + const uint8 kGaugeY = -13; // ??? + const uint16 kScreenBMW = 160; // Screen BitMap Width? + const uint16 kChrW = 64; const uint16 kChrH = 32; const uint16 kChrH2 = kChrH * 2; const uint16 kChrH3 = kChrH * 3; - const uint16 kChrLen = (kChrW / 2) * kChrH; - const uint16 kChrBMW = kChrW / 2; + const uint16 kChrLen = (kChrW / 2) * kChrH; + const uint16 kChrBMW = kChrW / 2; const uint16 kLCutaway = 4; const uint16 kLDrawSolid = 32 * ((3 * 16) + 5); const uint16 kChrDy[19] = {kChr0, kChrH, kChrH2, kChrH, kChrH2, - kChrH2, kChrH, kChrH2, kChrH2, kChr0, - kChr0, kChrH2, kChrH, kChrH2, kChrH2, - kChrH2, kChrH, kChrH2, kChrH2}; + kChrH2, kChrH, kChrH2, kChrH2, kChr0, + kChr0, kChrH2, kChrH, kChrH2, kChrH2, + kChrH2, kChrH, kChrH2, kChrH2 + }; const uint16 kChrMask[19] = {kChr0, kChr0, kChr0, kChr0, - kChrR, kChrL, kChr0, kChrL, - kChrR, kChr0, kChr0, kChrLD, - kChr0, kChrR, kChrLD, kChrRD, - kChr0, kChrRD, kChrL}; + kChrR, kChrL, kChr0, kChrL, + kChrR, kChr0, kChr0, kChrLD, + kChr0, kChrR, kChrLD, kChrRD, + kChr0, kChrRD, kChrL + }; const uint16 kIsBackground[36] = {1, 0, 0, 0, 0, 0, - 0, 0, 0, 1, 1, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0}; + 0, 0, 0, 1, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0 + }; const uint16 kTBlisterCorners[60] = {7, 1, 1, 1, 1, 1, 5, 3, 1, 1, 1, 1, 1, 3, 5, 3, 5, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 8, 8, 16, 16, 16, 16, 8, - 8, 8, 8, 16, 16, 16, 16, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 8, 8, 16, 16, 16, 16, 8, + 8, 8, 8, 16, 16, 16, 16, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 + }; const uint16 kTLogicalCorners[19] = {1, 1, 1, 1, 16, 8, 1, 8, - 16, 1, 1, 8, 1, 16, 8, 16, - 1, 16, 8}; + 16, 1, 1, 8, 1, 16, 8, 16, + 1, 16, 8 + }; // Disk offsets - const int kPaletteOffset = 21205; // This is the byte position of the palette data in the disk + const int kPaletteOffset = 21205; // This is the byte position of the palette data in the disk // Sprite constants - const uint16 kMaxSpriteW = 64; - const uint16 kMaxSpriteH = 64; - const uint16 kSpriteDY = 32; - const uint16 kVSX = kMaxSpriteW; - const uint16 kVSY = kSpriteDY; - const uint16 kVSBMW = (kViewPortW + kMaxSpriteW) / 2; - const uint16 kVSLen = kVSBMW * (kViewPortH + kMaxSpriteH); - const uint16 kVSDY = 32; // difference from top of screen to top of viewport in the virtual screen buffer + const uint16 kMaxSpriteW = 64; + const uint16 kMaxSpriteH = 64; + const uint16 kSpriteDY = 32; + const uint16 kVSX = kMaxSpriteW; + const uint16 kVSY = kSpriteDY; + const uint16 kVSBMW = (kViewPortW + kMaxSpriteW) / 2; + const uint16 kVSLen = kVSBMW * (kViewPortH + kMaxSpriteH); + const uint16 kVSDY = 32; // difference from top of screen to top of viewport in the virtual screen buffer const uint16 kMySuperBottom = kVSDY + kViewPortH; - const uint16 kSuperBottom = 200; - const uint16 kMySuperTop = kVSDY; - const uint16 kSuperTop = 0; - const uint16 kViewPortSpX = 32; - const uint16 kViewPortSpY = 0; - const uint16 kWizardX = 28; // Common sprite center for some reason - const uint16 kWizardY = 37; - const uint16 kObjectY = 24; - const uint16 kObjectX = 32; + const uint16 kSuperBottom = 200; + const uint16 kMySuperTop = kVSDY; + const uint16 kSuperTop = 0; + const uint16 kViewPortSpX = 32; + const uint16 kViewPortSpY = 0; + const uint16 kWizardX = 28; // Common sprite center for some reason + const uint16 kWizardY = 37; + const uint16 kObjectY = 24; + const uint16 kObjectX = 32; const uint16 kObjectHeight = 48; - const uint16 kObjectWidth = 64; + const uint16 kObjectWidth = 64; // Text constants - const uint8 kMaxRows = 5; - const uint8 kMaxCollumns = 26; + const uint8 kMaxRows = 5; + const uint8 kMaxCollumns = 26; - const uint16 kYesNoY = 88; - const uint16 kYesNoX1 = 8; - const uint16 kYesNoX2 = 182; + const uint16 kYesNoY = 88; + const uint16 kYesNoX1 = 8; + const uint16 kYesNoX2 = 182; // Asset constants - const char kGaugeOn = 1; // On uses the sprite at index 1 of the font spriteset - const char kGaugeOff = 0; // Off uses the sprite at index 0 of the font spriteset - const char kGaugeStop = 1; // Literally just means the final kGaugeOn char to draw - const char kGaugeStart = 1; // First kGaugeOn char to draw + const char kGaugeOn = 1; // On uses the sprite at index 1 of the font spriteset + const char kGaugeOff = 0; // Off uses the sprite at index 0 of the font spriteset + const char kGaugeStop = 1; // Literally just means the final kGaugeOn char to draw + const char kGaugeStart = 1; // First kGaugeOn char to draw // Level constants - const int kStoryNull = 5; + const int kStoryNull = 5; const int kMaxFilesPerLevel = 16; const int kMaxPartInstances = 4; - const int kLevelToMaze[8] = {0,0,1,1,2,2,2,3}; + const int kLevelToMaze[8] = {0, 0, 1, 1, 2, 2, 2, 3}; - /* + /* * 'global' members */ // Misc - Common::ErrorCode _err; // If this is not kNoError at any point, the engine will stop - uint8 _certificate[16]; // The certificate (password) is basically the inventory/equipment array - uint8 _lastCertLen = 0; - bool _draw = 0; // Whether the screen should draw this frame - int _zero = 0; // No idea what this is yet - bool _gameOverFlag = false; - uint8 _gameFlags = 0; // Bitflag array of event flags, but only two were used (saving ana and saving the king) <-- why is gameOverFlag not in this? Lol - bool _themePaused = false; // In the source, this is actually considered a bit flag array of 2 bits (b0 and b1). However, it only ever checks for non-zero, so it's effectively only 1 bit. - int _titlesShown = 0; - int _time = 0; - int _promoting = 0; // I think promoting means the title stuff - bool _restart = false; + Common::ErrorCode _err; // If this is not kNoError at any point, the engine will stop + uint8 _certificate[16]; // The certificate (password) is basically the inventory/equipment array + uint8 _lastCertLen = 0; + bool _draw = 0; // Whether the screen should draw this frame + int _zero = 0; // No idea what this is yet + bool _gameOverFlag = false; + uint8 _gameFlags = 0; // Bitflag array of event flags, but only two were used (saving ana and saving the king) <-- why is gameOverFlag not in this? Lol + bool _themePaused = false; // In the source, this is actually considered a bit flag array of 2 bits (b0 and b1). However, it only ever checks for non-zero, so it's effectively only 1 bit. + int _titlesShown = 0; + int _time = 0; + int _promoting = 0; // I think promoting means the title stuff + bool _restart = false; // Story members Story _stories[8]; // Level members - int _maxLevels = 0; // This is determined when loading in story files - int _level = 0; - bool _levelOver = false; - int _count = 0; - int _lastLevelLoaded = 0; - int _lastSongLoaded = 0; - int _storyLevel = 0; - int _storyX = 0; - int _loadA = 0; - int _loadY = 0; - uint16 _initialX = 0; - uint16 _initialY = 0; - int _initialBX = 0; - int _initialBY = 0; - int _dRoomNum = 0; - int _initialRoom = 0; - int _currentRoom = 0; - int _lastType = 0; - int _roomCellX = 0; - int _roomCellY = 0; - Room *_rooms[kMaxRooms]; // Rooms within the level - Common::Array _allFlames[kMaxRooms]; // The level needs it's own set of flames so that the flames can be turned on/off permenantly. This is technically more like a hashmap in the source, but it could also be seen as a 2d array, just hashed together in the source + int _maxLevels = 0; // This is determined when loading in story files + int _level = 0; + bool _levelOver = false; + int _count = 0; + int _lastLevelLoaded = 0; + int _lastSongLoaded = 0; + int _storyLevel = 0; + int _storyX = 0; + int _loadA = 0; + int _loadY = 0; + uint16 _initialX = 0; + uint16 _initialY = 0; + int _initialBX = 0; + int _initialBY = 0; + int _dRoomNum = 0; + int _initialRoom = 0; + int _currentRoom = 0; + int _lastType = 0; + int _roomCellX = 0; + int _roomCellY = 0; + Room *_rooms[kMaxRooms]; // Rooms within the level + Common::Array _allFlames[kMaxRooms]; // The level needs it's own set of flames so that the flames can be turned on/off permenantly. This is technically more like a hashmap in the source, but it could also be seen as a 2d array, just hashed together in the source // Door members Common::Array _doors; - uint8 _numDoors = 0; - uint8 _doorRoom = 0; + uint8 _numDoors = 0; + uint8 _doorRoom = 0; uint8 _doorToNextLevel = 0; uint8 _doorCameInFrom = 0; - uint8 _ladders = 0; - uint8 _numLadders = 0; - uint8 _ladderInUse = 0; + uint8 _ladders = 0; + uint8 _numLadders = 0; + uint8 _ladderInUse = 0; uint8 _secretLadder = 0; uint8 _secretCount = 0; uint8 _secretDelta = 0; // Debug members - bool _singleStep = false; // Flag for _singleStep mode + bool _singleStep = false; // Flag for _singleStep mode // Input members - int _pressedAction = 0; - int _heldAction = 0; + int _pressedAction = 0; + int _heldAction = 0; int _pressedDirection = 0; - int _heldDirection = 0; + int _heldDirection = 0; // Text printing members uint8 _slowText = 0; uint8 _formatted = 0; - uint8 _collumn = 0; - uint8 _row = 0; - uint8 _myButton = 0; - uint8 _lastYes = 0; + uint8 _collumn = 0; + uint8 _row = 0; + uint8 _myButton = 0; + uint8 _lastYes = 0; // Music members - Song _playing; // Currently playing song - int _themeID = 0; // Not sure yet tbh + Song _playing; // Currently playing song + int _themeID = 0; // Not sure yet tbh int _combatID = 0; // Asset members - int _numSprites = 0; // This is more accurately actually the index within the sprite array, so _numSprites + 1 is the current number of sprites - DataSprite _dataSprites[kFont + 1]; // All the sprite data, indexed by SpriteName - Sprite _sprites[kMaxSprites]; // All the sprites shown on screen - Cycle _cycles[kMaxCycles]; - Common::Array _strPtrs; // Str should really be a char array, but inserting frame values will be stupid so it's just a string instead + int _numSprites = 0; // This is more accurately actually the index within the sprite array, so _numSprites + 1 is the current number of sprites + DataSprite _dataSprites[kFont + 1]; // All the sprite data, indexed by SpriteName + Sprite _sprites[kMaxSprites]; // All the sprites shown on screen + Cycle _cycles[kMaxCycles]; + Common::Array _strPtrs; // Str should really be a char array, but inserting frame values will be stupid so it's just a string instead Common::Array _motivePtrs; Common::Array _damagePtrs; - Common::Array _usePtrs; + Common::Array _usePtrs; Common::Array _pickupPtrs; - Common::Array _cycPtrs; // This is not actually a set of pointers, but it is serving the function of what was called cycPtrs in the source - CArray2D _programPtrs; + Common::Array _cycPtrs; // This is not actually a set of pointers, but it is serving the function of what was called cycPtrs in the source + CArray2D _programPtrs; Common::Array _objTypePtrs; // Universe members in order of their original memory layout - uint16 *_logicalCNM; // As confusing as this is, we get Logical CNM from the .CNM file, and we get the CNM from the .UNV file + uint16 *_logicalCNM; // As confusing as this is, we get Logical CNM from the .CNM file, and we get the CNM from the .UNV file uint16 *_modCNM; uint16 *_modLogicalCNM; - Univ *_univ; // Pointer to the struct that contains the universe properties - Common::SeekableReadStream *_dataBuffer; // This contains the CNM and the CBM - uint16 *_CNM; // Stands for CHARACTER NUMBER MAP - byte *_CBM; // Stands for CHARACTER BIT MAP (?) - byte *_oldCBM; + Univ *_univ; // Pointer to the struct that contains the universe properties + Common::SeekableReadStream *_dataBuffer; // This contains the CNM and the CBM + uint16 *_CNM; // Stands for CHARACTER NUMBER MAP + byte *_CBM; // Stands for CHARACTER BIT MAP (?) + byte *_oldCBM; uint16 _myCNM[(kViewPortCW + 1)][(kViewPortCH + 1)]; uint16 _myModCNM[(kViewPortCW + 1)][(kViewPortCH + 1)]; uint16 _myModLCNM[(kViewPortCW + 1)][(kViewPortCH + 1)]; // Screen members - byte *_screenBuff; // The final buffer that will transfer to the screen + byte *_screenBuff; // The final buffer that will transfer to the screen uint16 _columnX[kViewPortCW + 1]; uint16 _columnTop[kViewPortCW + 1]; - uint16 _columnIndex[kViewPortCW + 1]; // Why the heck is this an entire array, when it's just an index that gets zeroed before it gets used anyway... + uint16 _columnIndex[kViewPortCW + 1]; // Why the heck is this an entire array, when it's just an index that gets zeroed before it gets used anyway... uint16 _tIndex[kMaxDrawItems]; uint16 _tPriority[kMaxDrawItems]; - uint16 _viewPortX = 0; - uint16 _viewPortY = 0; - uint16 _myViewPortX = 0; // Probably mirror of viewportX + uint16 _viewPortX = 0; + uint16 _viewPortY = 0; + uint16 _myViewPortX = 0; // Probably mirror of viewportX uint16 _myViewPortY = 0; - int _lastGauge = 0; // Mirror for player health, used to update health gauge display - uint16 _lastBMW = 0; // Mirrors used to determine where bitmap width needs to be re-calculated - uint16 _lastY = 0; - uint16 _lastPoint = 0; - uint16 _penX = 0; // Basically where in the screen we are currently drawing - uint16 _penY = 0; + int _lastGauge = 0; // Mirror for player health, used to update health gauge display + uint16 _lastBMW = 0; // Mirrors used to determine where bitmap width needs to be re-calculated + uint16 _lastY = 0; + uint16 _lastPoint = 0; + uint16 _penX = 0; // Basically where in the screen we are currently drawing + uint16 _penY = 0; uint16 _myUnivPointX = 0; uint16 _myUnivPointY = 0; - int _num2DrawItems = 0; + int _num2DrawItems = 0; Graphics::Surface *_mainSurface; -GenericSprite _genSprites[6]; + GenericSprite _genSprites[6]; // Palette members - int _dontResetColors = 0; // Not sure yet - bool _usingNormal = 0; // Whether the palette is using normal - bool _dim = 0; // Whether the palette is dim + int _dontResetColors = 0; // Not sure yet + bool _usingNormal = 0; // Whether the palette is using normal + bool _dim = 0; // Whether the palette is dim uint16 _palUniv[16]; uint16 _palDefault[16]; uint16 _palWhite[16]; uint16 _palBlack[16]; uint16 _palDim[16]; - byte _palRGB[48]; // Palette that ScummVM actually uses, which is an RGB conversion of the original + byte _palRGB[48]; // Palette that ScummVM actually uses, which is an RGB conversion of the original /* @@ -464,34 +469,34 @@ GenericSprite _genSprites[6]; */ // Screen - void clearScreen(); // Draws a black rectangle on the screen buffer but only inside the frame - void whiteScreen(); // Draws a white rectanlge on the screen buffer (but does not do anything with resetColors) - void rect(int x, int y, int w, int h); // Draws a solid rectangle at x,y with size w,h. Also shadows for blit? - void backspace(); // Moves draw position back and draws empty rect in place of char + void clearScreen(); // Draws a black rectangle on the screen buffer but only inside the frame + void whiteScreen(); // Draws a white rectanlge on the screen buffer (but does not do anything with resetColors) + void rect(int x, int y, int w, int h); // Draws a solid rectangle at x,y with size w,h. Also shadows for blit? + void backspace(); // Moves draw position back and draws empty rect in place of char void printByte(int b); void printChr(char c); - void loadWindow(); // Gets the window.bm file - void drawUniv(); // Draw the background, add the sprites, determine draw order, draw the sprites - void copyToScreen(); // If draw is 0, just check input, otherwise also copy the screen buffer to the scummvm surface and update screen - void mungeBM(); // Put together final bitmap? - void blit(); // Will probably want this to be it's own function - void blit40(); // Uses macro blit 40 times + void loadWindow(); // Gets the window.bm file + void drawUniv(); // Draw the background, add the sprites, determine draw order, draw the sprites + void copyToScreen(); // If draw is 0, just check input, otherwise also copy the screen buffer to the scummvm surface and update screen + void mungeBM(); // Put together final bitmap? + void blit(); // Will probably want this to be it's own function + void blit40(); // Uses macro blit 40 times void sBlit(); void scroll(); - void makeMyCNM(); // ? - void drawBGRND(); // Draw floor parts of leftmask rightmask and maskers - void addRows(); // Add rows to drawitem array + void makeMyCNM(); // ? + void drawBGRND(); // Draw floor parts of leftmask rightmask and maskers + void addRows(); // Add rows to drawitem array void addSprite(uint16 vpX, uint16 vpY, SpriteName s, int img, uint16 x, uint16 y, uint16 p); - void addSprites(); // Add all active sprites that are in the viewport, into a list that will be sorted by priority - void sortDrawItems(); // Sort said items - void drawItems(); // Draw the items over the background + void addSprites(); // Add all active sprites that are in the viewport, into a list that will be sorted by priority + void sortDrawItems(); // Sort said items + void drawItems(); // Draw the items over the background void drawIcon(int img); - void setPen(uint16 penX, uint16 penY); // Sets the 'pen' x and y positions, including making y negative if above a certain point + void setPen(uint16 penX, uint16 penY); // Sets the 'pen' x and y positions, including making y negative if above a certain point void center(); void carriageReturn(); // Music - void toggleSound(); // Actually pauses the sound, doesn't just turn it off/mute + void toggleSound(); // Actually pauses the sound, doesn't just turn it off/mute void fixPause(); Song getPlaying(); void playMazeSong(); @@ -501,46 +506,46 @@ GenericSprite _genSprites[6]; void stopMusic(); void musicPause(int sID); void musicUnPause(int sID); - void loadSingles(Common::String songName); // Loads and then parse the maze song + void loadSingles(Common::String songName); // Loads and then parse the maze song void standardBeep(); // Palette - void loadPalette(); // Get the static palette data from the disk - void setColors(uint16 pal[]); // Applies the current palette to the ScummVM surface palette - void fixColors(); // Determine whether the screen should be dim or normal + void loadPalette(); // Get the static palette data from the disk + void setColors(uint16 pal[]); // Applies the current palette to the ScummVM surface palette + void fixColors(); // Determine whether the screen should be dim or normal void useNormal(); void useDim(); void useBlack(); void useWhite(); - void pump(); // Alternates between white and black with delays in between (flashes screen) + void pump(); // Alternates between white and black with delays in between (flashes screen) void fadePal(uint16 pal[], int count, uint16 target[]); // Fades the palette except the frame - void fade(uint16 pal[], int dir, int delay); // Calls fadePal() by a given delay each iteration - void fadeOut(int j); // Calls Fade with a delay of j jiffies and direction 1 - void fadeIn(int j); // || and direction 0 + void fade(uint16 pal[], int dir, int delay); // Calls fadePal() by a given delay each iteration + void fadeOut(int j); // Calls Fade with a delay of j jiffies and direction 1 + void fadeIn(int j); // || and direction 0 void normalFadeOut(); void slowFadeOut(); void normalFadeIn(); // Assets Common::SeekableReadStream *loadIFF(Common::String fileName); // Loads a file and uncompresses if it is compressed - void initStoryStatic(); // Sets up all of the global static story elements - int loadUniv(char mazeNum); // Unpacks the .CNM and .UNV files into all the CNM stuff, returns the total length of everything - void loadMazeGraphics(int m); // Creates a universe with a maze - void makeBlisters(int povX, int povY); // Turns the unmodified CNM/CBM/LCNM etc into the modified ones to actually be used for drawing the game - void loadFont(); // Gets the font.spr file, and centers the sprite - void clearSprites(); // Clears all sprites before drawing the current frame - void loadSprites(); // Loads all the sprite files and centers their sprites (in spritelist, but called from kernal) + void initStoryStatic(); // Sets up all of the global static story elements + int loadUniv(char mazeNum); // Unpacks the .CNM and .UNV files into all the CNM stuff, returns the total length of everything + void loadMazeGraphics(int m); // Creates a universe with a maze + void makeBlisters(int povX, int povY); // Turns the unmodified CNM/CBM/LCNM etc into the modified ones to actually be used for drawing the game + void loadFont(); // Gets the font.spr file, and centers the sprite + void clearSprites(); // Clears all sprites before drawing the current frame + void loadSprites(); // Loads all the sprite files and centers their sprites (in spritelist, but called from kernal) // Input - void userIO(); // Get input - void pollKeys(); // Buffer input - void noNetwork(); // Setup input mirrors - void waitKey(); // Waits until a key is pressed (until getInput() returns true) - void waitClick(); // Waits until one of the two buttons is pressed - void blit8(); // This is actually just input, but it is called blit because it does a 'paddle blit' 8 times + void userIO(); // Get input + void pollKeys(); // Buffer input + void noNetwork(); // Setup input mirrors + void waitKey(); // Waits until a key is pressed (until getInput() returns true) + void waitClick(); // Waits until one of the two buttons is pressed + void blit8(); // This is actually just input, but it is called blit because it does a 'paddle blit' 8 times // These will replace the myriad of hardware input handling from the source - bool getInput(); // True if there was input, false if not + bool getInput(); // True if there was input, false if not void addKeyBuffer(); void clearKeyBuff(); @@ -564,24 +569,24 @@ GenericSprite _genSprites[6]; void drawLRHC(int chr, int x, int y); - /* + /* * [Logic.cpp] Functions from Logic.GS */ // Debug - void doSingleStep(); // Let the user advance the engine one frame at a time + void doSingleStep(); // Let the user advance the engine one frame at a time // Main - void trapKeys(); // Poorly named, this checks if the player wants to restart/pause music/use debug step - int keyOrButton(); // Returns value based on whether it was a keyboard key or a button press + void trapKeys(); // Poorly named, this checks if the player wants to restart/pause music/use debug step + int keyOrButton(); // Returns value based on whether it was a keyboard key or a button press void logicInit(); - void logic(); // Keeps time, handles win and lose conditions, then general logic - void restartLogic(); // This is the actual logic init - int logicFreeze(); // Overcomplicated way to check if game over or level over + void logic(); // Keeps time, handles win and lose conditions, then general logic + void restartLogic(); // This is the actual logic init + int logicFreeze(); // Overcomplicated way to check if game over or level over void updateHitGauge(); void drawGauge(int h); void makeCertificate(); - void calcCheckSum(int l, uint8 checksum[]); // Checksum is one word, but the source called it CheckSum + void calcCheckSum(int l, uint8 checksum[]); // Checksum is one word, but the source called it CheckSum bool getCertificate(); void printCertificate(); @@ -594,7 +599,7 @@ GenericSprite _genSprites[6]; bool isSavedKing(); void setSavedAna(); bool isSavedAna(); - int getLevel(); // Literally just return _level... + int getLevel(); // Literally just return _level... void gameOverDisplay(); void gameOver(); void levelOver(); @@ -662,7 +667,7 @@ GenericSprite _genSprites[6]; */ // Misc - void cycleFreeAll(); // Delete all cycles + void cycleFreeAll(); // Delete all cycles /* @@ -678,7 +683,7 @@ GenericSprite _genSprites[6]; // Init void initDataSprite(Common::SeekableReadStream *f, DataSprite *d, int index, uint16 cenX, uint16 cenY); // Initializes the data sprite - + // Main void superSprite(DataSprite *dSprite, uint16 x, uint16 y, int img, uint16 bmw, byte *dst, uint16 superTop, uint16 superBottom); bool clipSprite(uint16 &height, uint16 &pointIndex, uint16 &skipY, DataSprite *dSprite, uint16 &pointX, uint16 &pointY, int img, uint16 bmw, uint16 superTop, uint16 superBottom); @@ -702,7 +707,7 @@ GenericSprite _genSprites[6]; * [door.cpp] Functions from Door.GS */ - void roomTransfer(int r, int x, int y); // Transfers the player from the current room to a new room at x,y + void roomTransfer(int r, int x, int y); // Transfers the player from the current room to a new room at x,y void doorOpenSecret(); void doorCloseSecret(); //void doorToNextLevel(); @@ -711,7 +716,7 @@ GenericSprite _genSprites[6]; void doorNew(SDoor door); void doorDrawAll(); void doorOnDoorMat(); - //void doorEnter(); // <-- this is actually a method of Player Monster, should probably move it there later + //void doorEnter(); // <-- this is actually a method of Player Monster, should probably move it there later int findDoorTop(int x, int y); int findDoor(int x, int y); bool doLockStuff(int d, MonsterID m, int top); @@ -735,9 +740,9 @@ GenericSprite _genSprites[6]; * */ - Common::ErrorCode initDisks(); // Opens and parses IMMORTAL.dsk and IMMORTAL_GFX.dsk - uint32 getFeatures() const; // Returns the game description flags - Common::String getGameId() const; // Returns the game Id + Common::ErrorCode initDisks(); // Opens and parses IMMORTAL.dsk and IMMORTAL_GFX.dsk + uint32 getFeatures() const; // Returns the game description flags + Common::String getGameId() const; // Returns the game Id /* Gets a random number */ @@ -747,9 +752,9 @@ GenericSprite _genSprites[6]; bool hasFeature(EngineFeature f) const override { return - (f == kSupportsLoadingDuringRuntime) || - (f == kSupportsSavingDuringRuntime) || - (f == kSupportsReturnToLauncher); + (f == kSupportsLoadingDuringRuntime) || + (f == kSupportsSavingDuringRuntime) || + (f == kSupportsReturnToLauncher); }; bool canLoadGameStateCurrently() override { @@ -765,13 +770,13 @@ GenericSprite _genSprites[6]; Common::Error syncGame(Common::Serializer &s); /* Common::Error saveGameStream(Common::WriteStream *stream, bool isAutosave = false) { - Common::Serializer s(nullptr, stream); - return syncGame(s); + Common::Serializer s(nullptr, stream); + return syncGame(s); } Common::Error loadGameStream(Common::SeekableReadStream *stream) { - Common::Serializer s(stream, nullptr); - return syncGame(s); + Common::Serializer s(stream, nullptr); + return syncGame(s); } */ }; diff --git a/engines/immortal/kernal.cpp b/engines/immortal/kernal.cpp index 7677cafab601..00f0d27ed3d7 100644 --- a/engines/immortal/kernal.cpp +++ b/engines/immortal/kernal.cpp @@ -30,7 +30,7 @@ namespace Immortal { -/* +/* * * ----- ----- * ----- Screen Drawing Functions ----- @@ -49,11 +49,11 @@ void ImmortalEngine::drawUniv() { _myUnivPointY = !(_myViewPortY & (kChrH - 1)) + kViewPortSpY; //makeMyCNM(); - //drawBGRND(); // Draw floor parts of leftmask rightmask and maskers - //addRows(); // Add rows to drawitem array - //addSprites(); // Add all active sprites that are in the viewport, into a list that will be sorted by priority - //sortDrawItems(); // Sort said items - //drawItems(); // Draw the items over the background + //drawBGRND(); // Draw floor parts of leftmask rightmask and maskers + //addRows(); // Add rows to drawitem array + //addSprites(); // Add all active sprites that are in the viewport, into a list that will be sorted by priority + //sortDrawItems(); // Sort said items + //drawItems(); // Draw the items over the background } void ImmortalEngine::copyToScreen() { @@ -79,7 +79,7 @@ void ImmortalEngine::clearScreen() { _screenBuff[((y + 20) * kResH) + (x + 32)] = 0; } } - + _penX = kTextLeft; _penY = kTextTop; @@ -109,8 +109,8 @@ void ImmortalEngine::addRows() { // I'm not really sure how this works yet int i = _num2DrawItems; _tPriority[i] = !(!(_myViewPortY & (kChrH - 1)) + _myViewPortY); - - for (int j = 0; j != kViewPortCH+4; j++, i++) { + + for (int j = 0; j != kViewPortCH + 4; j++, i++) { _tIndex[i] = (j << 5) | 0x8000; _tPriority[i] = _tPriority[i] - kChrH; } @@ -123,13 +123,13 @@ void ImmortalEngine::addSprite(uint16 vpX, uint16 vpY, SpriteName s, int img, ui if (x >= (kResH + kMaxSpriteLeft)) { x |= kMaskHigh; // Make it negative } - + _sprites[_numSprites]._X = (x << 1) + vpX; - + if (y >= (kMaxSpriteAbove + kResV)) { y |= kMaskHigh; } - + _sprites[_numSprites]._Y = (y << 1) + vpY; if (p >= 0x80) { @@ -137,7 +137,7 @@ void ImmortalEngine::addSprite(uint16 vpX, uint16 vpY, SpriteName s, int img, ui } _sprites[_numSprites]._priority = ((p + y) ^ 0xFFFF) + 1; - + _sprites[_numSprites]._image = img; _sprites[_numSprites]._dSprite = &_dataSprites[s]; _sprites[_numSprites]._on = 1; @@ -153,7 +153,9 @@ void ImmortalEngine::addSprites() { int tmpNum = _num2DrawItems; for (int i = 0; i < kMaxSprites; i++) { // If the sprite is active - // This is commented out for testing until the issue with the function is resolved + /* TODO + * This is commented out for testing until the issue with the function is resolved + */ if (/*_sprites[i]._on*/0 == 1) { // If sprite X is an odd number??? if ((_sprites[i]._X & 1) != 0) { @@ -185,7 +187,7 @@ void ImmortalEngine::addSprites() { int sx = ((_sprites[i]._X + tempImg->_deltaX) - tempD->_cenX) - _myViewPortX; int sy = ((_sprites[i]._Y + tempImg->_deltaY) - tempD->_cenY) - _myViewPortY; - if (sx >= 0 ) { + if (sx >= 0) { if (sx >= kViewPortW) { continue; } @@ -193,7 +195,7 @@ void ImmortalEngine::addSprites() { continue; } - if (sy >= 0 ) { + if (sy >= 0) { if (sy >= kViewPortH) { continue; } @@ -226,10 +228,10 @@ void ImmortalEngine::sortDrawItems() { // Assume that the list is sorted bailout = true; for (int i = 1; i < top; i++) { - if (_tPriority[i] > _tPriority[i-1]) { + if (_tPriority[i] > _tPriority[i - 1]) { uint16 tmp = _tPriority[i]; - _tPriority[i] = _tPriority[i-1]; - _tPriority[i-1] = tmp; + _tPriority[i] = _tPriority[i - 1]; + _tPriority[i - 1] = tmp; // List was not sorted yet, therefor we need to check it again bailout = false; @@ -264,9 +266,9 @@ void ImmortalEngine::drawBGRND() { // Left Mask, draw upper right hand corner (UPHC) of floor drawURHC(_myCNM[y2][x], pointX, pointY); } - pointX += kChrW; // This (and the H version) could be added to the for loop iterator arugment + pointX += kChrW; // This (and the H version) could be added to the for loop iterator arugment } - pointX -= (kChrW * (kViewPortCW + 1)); // They could have also just done pointX = _myUnivPointX + pointX -= (kChrW * (kViewPortCW + 1)); // They could have also just done pointX = _myUnivPointX pointY += kChrH; } } @@ -290,7 +292,7 @@ void ImmortalEngine::drawItems() { uint16 rowY = 0; do { uint16 index = _tIndex[n]; - if (index >= 0x8000) { // If negative, it's a row to draw + if (index >= 0x8000) { // If negative, it's a row to draw // rowY is (I think) the position of the start of the scroll window within the tile data rowY = (index & 0x7FFF) + _myUnivPointY; @@ -376,10 +378,10 @@ void ImmortalEngine::printByte(int b) { void ImmortalEngine::printChr(char c) { // This draws a character from the font sprite table, indexed as an ascii char, using superSprite - c &= kMaskASCII; // Grab just the non-extended ascii part + c &= kMaskASCII; // Grab just the non-extended ascii part if (c == ' ') { - _penX += 8; // A space just moves the position on the screen to draw ahead by the size of a space + _penX += 8; // A space just moves the position on the screen to draw ahead by the size of a space return; } @@ -394,7 +396,7 @@ void ImmortalEngine::printChr(char c) { case 'M': case 'W': _penX += 8; - // fall through + // fall through default: break; } @@ -408,13 +410,13 @@ void ImmortalEngine::printChr(char c) { _penX -= 3; break; case 'j': - // fall through + // fall through case 't': _penX -= 2; break; case 'l': _penX -= 4; - // fall through + // fall through default: break; } @@ -517,13 +519,13 @@ int ImmortalEngine::loadUniv(char mazeNum) { // The view port of the level is longer than it is wide, so there are more columns than rows // numCols = rectX / 64 (charW) - _univ->_rectX = mazeUNV->readUint16LE() << 1; + _univ->_rectX = mazeUNV->readUint16LE() << 1; _univ->_numCols = _univ->_rectX >> 6; _univ->_num2Cols = _univ->_numCols << 1; // univRectY is mazeUNV[22] // numRows = rectY / 32 (charH) - _univ->_rectY = mazeUNV->readUint16LE(); + _univ->_rectY = mazeUNV->readUint16LE(); _univ->_numRows = _univ->_rectY >> 5; _univ->_num2Rows = _univ->_numRows << 1; @@ -557,7 +559,7 @@ int ImmortalEngine::loadUniv(char mazeNum) { } _dataBuffer->seek(0); - _univ->_numChrs++; // Inc one more time being 0 counts + _univ->_numChrs++; // Inc one more time being 0 counts _univ->_num2Chrs = _univ->_numChrs << 1; //int lCNMCBM = mungeCBM(_univ->_num2Chrs); @@ -591,37 +593,39 @@ void ImmortalEngine::loadSprites() { */ Common::String spriteNames[] = {"MORESPRITES.SPR", "NORLAC.SPR", "POWWOW.SPR", "TURRETS.SPR", - "WORM.SPR", "IANSPRITES.SPR", "LAST.SPR", "DOORSPRITES.SPR", - "GENSPRITES.SPR", "DRAGON.SPR", "MORDAMIR.SPR", "FLAMES.SPR", - "ROPE.SPR", "RESCUE.SPR", "TROLL.SPR", "GOBLIN.SPR", "WIZARDA.SPR", - "WIZARDB.SPR", "ULINDOR.SPR", "SPIDER.SPR", "DRAG.SPR"}; + "WORM.SPR", "IANSPRITES.SPR", "LAST.SPR", "DOORSPRITES.SPR", + "GENSPRITES.SPR", "DRAGON.SPR", "MORDAMIR.SPR", "FLAMES.SPR", + "ROPE.SPR", "RESCUE.SPR", "TROLL.SPR", "GOBLIN.SPR", "WIZARDA.SPR", + "WIZARDB.SPR", "ULINDOR.SPR", "SPIDER.SPR", "DRAG.SPR" + }; // Number of sprites in each file int spriteNum[] = {10, 5, 7, 10, 4, 6, 3, 10, 5, 3, 2, 1, 3, 2, 9, 10, 8, 3, 9, 10, 9}; // Pairs of (x,y) for each sprite // Should probably have made this a 2d array, oops - uint16 centerXY[] = {16,56, 16,32, 27,39, 16,16, 32,16, 34,83, 28,37, 8,12, 8,19, 24,37, - /* Norlac */ 46,18, 40,0, 8,13, 32,48, 32,40, - /* Powwow */ 53,43, 28,37, 27,37, 26,30, 26,30, 26,29, 28,25, - /* Turrets */ 34,42, 28,37, 24,32, 32,56, 26,56, 8,48, 8,32, 8,14, 8,24, 32,44, - /* Worm */ 20,65, 25,46, 9,56, 20,53, - /* Iansprites */ 24,50, 32,52, 32,53, 32,52, 40,16, 40,16, - /* Last */ 32,56, 24,32, 24,36, - /* Doorsprites */ 0,64, 4,49, 18,49, 18,56, 24,32, 24,16, 24,56, 24,32, 24,32, 36,32, - /* Gensprites */ 16,44, 16,28, 32,24, 34,45, 20,28, - /* Dragon */ 24,93, 32,48, 0,64, - /* Mordamir */ 104,104, 30,30, - /* Flames */ 64,0, - /* Rope */ 0,80, 32,52, 32,40, - /* Rescue */ 0,112, 0,112, - /* Troll */ 28,38, 28,37, 28,37, 31,38, 28,37, 25,39, 28,37, 28,37, 28,37, - /* Goblin */ 28,38, 30,38, 26,37, 30,38, 26,37, 26,37, 26,37, 26,37, 26,36, 44,32, - /* Wizarda */ 28,37, 28,37, 28,37, 28,37, 28,37, 28,37, 28,37, 28,37, - /* Wizardb */ 28,37, 28,37, 28,37, - /* Ulindor */ 42,42, 42,42, 42,42, 42,42, 42,42, 42,42, 42,42, 42,42, 42,42, - /* Spider */ 64,44, 64,44, 64,44, 64,44, 64,44, 64,44, 64,44, 64,44, 64,44, 64,44, - /* Drag */ 19,36, 19,36, 19,36, 19,36, 19,36, 19,36, 19,36, 19,36, 19,36}; + uint16 centerXY[] = {16, 56, 16, 32, 27, 39, 16, 16, 32, 16, 34, 83, 28, 37, 8, 12, 8, 19, 24, 37, + /* Norlac */ 46, 18, 40, 0, 8, 13, 32, 48, 32, 40, + /* Powwow */ 53, 43, 28, 37, 27, 37, 26, 30, 26, 30, 26, 29, 28, 25, + /* Turrets */ 34, 42, 28, 37, 24, 32, 32, 56, 26, 56, 8, 48, 8, 32, 8, 14, 8, 24, 32, 44, + /* Worm */ 20, 65, 25, 46, 9, 56, 20, 53, + /* Iansprites */ 24, 50, 32, 52, 32, 53, 32, 52, 40, 16, 40, 16, + /* Last */ 32, 56, 24, 32, 24, 36, + /* Doorsprites */ 0, 64, 4, 49, 18, 49, 18, 56, 24, 32, 24, 16, 24, 56, 24, 32, 24, 32, 36, 32, + /* Gensprites */ 16, 44, 16, 28, 32, 24, 34, 45, 20, 28, + /* Dragon */ 24, 93, 32, 48, 0, 64, + /* Mordamir */ 104, 104, 30, 30, + /* Flames */ 64, 0, + /* Rope */ 0, 80, 32, 52, 32, 40, + /* Rescue */ 0, 112, 0, 112, + /* Troll */ 28, 38, 28, 37, 28, 37, 31, 38, 28, 37, 25, 39, 28, 37, 28, 37, 28, 37, + /* Goblin */ 28, 38, 30, 38, 26, 37, 30, 38, 26, 37, 26, 37, 26, 37, 26, 37, 26, 36, 44, 32, + /* Wizarda */ 28, 37, 28, 37, 28, 37, 28, 37, 28, 37, 28, 37, 28, 37, 28, 37, + /* Wizardb */ 28, 37, 28, 37, 28, 37, + /* Ulindor */ 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, + /* Spider */ 64, 44, 64, 44, 64, 44, 64, 44, 64, 44, 64, 44, 64, 44, 64, 44, 64, 44, 64, 44, + /* Drag */ 19, 36, 19, 36, 19, 36, 19, 36, 19, 36, 19, 36, 19, 36, 19, 36, 19, 36 + }; // s = current sprite index, f = current file index, n = current number of sprites for this file int s = 0; @@ -632,7 +636,7 @@ void ImmortalEngine::loadSprites() { for (int n = 0; n < (spriteNum[f] * 2); n += 2, s++) { // For every data sprite in the file, make a datasprite and initialize it DataSprite d; - initDataSprite(file, &d, n/2, centerXY[s * 2], centerXY[(s * 2) + 1]); + initDataSprite(file, &d, n / 2, centerXY[s * 2], centerXY[(s * 2) + 1]); _dataSprites[s] = d; } } @@ -716,7 +720,7 @@ Common::SeekableReadStream *ImmortalEngine::loadIFF(Common::String fileName) { * allowing us to directly compare it with 'CMP0'. */ char compSig[] = "CMP0"; - char sig[] = "0000"; + char sig[] = "0000"; f.seek(8); @@ -726,7 +730,7 @@ Common::SeekableReadStream *ImmortalEngine::loadIFF(Common::String fileName) { if (strcmp(sig, compSig) == 0) { debug("compressed"); - + /* The size of the compressed data is stored in the header, but doesn't * account for the FORM part?? Also, **technically** this is a uint32LE, * but the engine itself actually /doesn't/ use it like that. It only @@ -775,7 +779,7 @@ void ImmortalEngine::loadPalette() { // The palettes are stored at a particular location in the disk, this just grabs them Common::File d; d.open("IMMORTAL.dsk"); - + d.seek(kPaletteOffset); d.read(_palDefault, 32); d.read(_palWhite, 32); @@ -797,8 +801,8 @@ void ImmortalEngine::setColors(uint16 pal[]) { // Blue is the first nyble of the first byte, so it needs to move left by 4 bits (000B -> 00B0) // We also need to repeat the bits so that the colour is the same proportion of 255 as it is of 15 _palRGB[(i * 3)] = ((pal[i] & kMaskRed) >> 4) | ((pal[i] & kMaskRed) >> 8); - _palRGB[(i * 3) + 1] = (pal[i] & kMaskGreen) | ((pal[i] & kMaskGreen) >> 4); - _palRGB[(i * 3) + 2] = (pal[i] & kMaskBlue) | ((pal[i] & kMaskBlue) << 4); + _palRGB[(i * 3) + 1] = (pal[i] & kMaskGreen) | ((pal[i] & kMaskGreen) >> 4); + _palRGB[(i * 3) + 2] = (pal[i] & kMaskBlue) | ((pal[i] & kMaskBlue) << 4); } } // Palette index to update first is 0, and there are 16 colours to update @@ -847,9 +851,10 @@ void ImmortalEngine::fadePal(uint16 pal[], int count, uint16 target[]) { * kept, this is a direct translation of the bit manipulation sequence. */ uint16 maskPal[16] = {0xFFFF, 0x0000, 0x0000, 0x0000, - 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, - 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, - 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF}; + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF + }; uint16 result; uint16 temp; @@ -930,7 +935,7 @@ void ImmortalEngine::useWhite() { void ImmortalEngine::useNormal() { setColors(_palDefault); - _usingNormal = 1; + _usingNormal = 1; } void ImmortalEngine::useDim() { @@ -1007,13 +1012,13 @@ void ImmortalEngine::fixPause() { // This is a nasty bit of code isn't it? It's accurate to the source though :D switch (_playing) { case kSongText: - // fall through + // fall through case kSongMaze: if (_themePaused) { musicUnPause(_themeID); break; } - // fall through + // fall through default: musicPause(_themeID); break; @@ -1026,7 +1031,7 @@ void ImmortalEngine::fixPause() { musicUnPause(_combatID); break; } - // fall through + // fall through default: musicPause(_combatID); break; @@ -1087,7 +1092,7 @@ void ImmortalEngine::center() { // Reset the X position and move the Y position down by 16 pixels void ImmortalEngine::carriageReturn() { _penY += 16; - _penX = kTextLeft; + _penX = kTextLeft; } } // namespace Immortal diff --git a/engines/immortal/level.cpp b/engines/immortal/level.cpp index 5d297ba8e70d..2010da59ca33 100644 --- a/engines/immortal/level.cpp +++ b/engines/immortal/level.cpp @@ -129,7 +129,7 @@ void ImmortalEngine::levelDrawAll() { void ImmortalEngine::levelShowRoom(int r, int bX, int bY) { _currentRoom = r; - cycleFreeAll(); // This may not be needed, or it may need to be changed slightly + cycleFreeAll(); // This may not be needed, or it may need to be changed slightly _rooms[_currentRoom]->flameSetRoom(_allFlames[r]); //univSetRoom(r, bX, bY); //fset, spark, bullet, and door get set to the current room diff --git a/engines/immortal/logic.cpp b/engines/immortal/logic.cpp index 21d8f0a2fb00..7cf5d0849796 100644 --- a/engines/immortal/logic.cpp +++ b/engines/immortal/logic.cpp @@ -48,14 +48,14 @@ void ImmortalEngine::restartLogic() { miscInit(); cycleFreeAll(); levelInit(); - //roomInit(); <-- will be run in constructor of room - //monstInit(); <-- room.initMonsters() \ - //objectInit(); <-- room.initObjects() - //doorInit(); <-- room.initDoors() |- probably all get run from room constructor - //sparkInit(); <-- room.initSparks() - //bulletInit(); <-- room.initProjectiles() / - //objectInit(); <-- again? Odd... - //genericSpriteInit(); <-- room.initGenSprites() + //roomInit(); <-- will be run in constructor of room + //monstInit(); <-- room.initMonsters() \ + //objectInit(); <-- room.initObjects() + //doorInit(); <-- room.initDoors() |- probably all get run from room constructor + //sparkInit(); <-- room.initSparks() + //bulletInit(); <-- room.initProjectiles() / + //objectInit(); <-- again? Odd... + //genericSpriteInit(); <-- room.initGenSprites() if (fromOldGame() == false) { _level = 0; @@ -65,12 +65,12 @@ void ImmortalEngine::restartLogic() { _rooms[_currentRoom]->flameInit(); if (_level != 7) { - _themePaused = true; // and #-1-2 = set both flags for themePaused + _themePaused = true; // and #-1-2 = set both flags for themePaused } } void ImmortalEngine::logic() { - trapKeys(); // First thing in any gameloop is to check if we should restart/toggle sound + trapKeys(); // First thing in any gameloop is to check if we should restart/toggle sound _time += 1; /* This is actually the main game state loop. I think the best way to translate it @@ -98,7 +98,7 @@ void ImmortalEngine::logic() { _themePaused = true; _levelOver = false; - if (_level == (_maxLevels-1)) { + if (_level == (_maxLevels - 1)) { textPrint(kStrYouWin, 0); } else { @@ -111,7 +111,7 @@ void ImmortalEngine::logic() { } else { // Here's where the gameplay sequence actually happens! - doSingleStep(); // Debug step function + doSingleStep(); // Debug step function //monstRunAll(); //objectRunAll(); //doInfiniteHallways(); @@ -158,7 +158,7 @@ void ImmortalEngine::trapKeys() { break; case kActionSound: toggleSound(); - // fall through + // fall through default: break; } @@ -175,10 +175,10 @@ int ImmortalEngine::keyOrButton() { button = _pressedAction; break; case kActionFire: - // fall through + // fall through case kActionButton: button = 13; - // fall through + // fall through default: break; } @@ -293,13 +293,13 @@ bool ImmortalEngine::fromOldGame() { _dontResetColors = 0; if (_promoting == 1) { _promoting = 0; - + } else { do { if (!textPrint(kStrOldGame, 0)) { // They choose not to load an old game - return false; + return false; } } while (getCertificate() == true); @@ -318,7 +318,7 @@ bool ImmortalEngine::fromOldGame() { //uint8 hits = _certificate[kCertHits]; //uint8 quick = _certificate[kCertQuickness]; //uint8 gold = (_certificate[kCertGoldHi] << 4) | _certificate[kCertGoldLo]; - // monstMakePlayer(hits, quick, gold); <- will become room.makePlayer(); + // monstMakePlayer(hits, quick, gold); <- will become room.makePlayer(); // Create the inventory // room.makeObject(3, kObjIsRunning, 0, goldType); @@ -326,7 +326,7 @@ bool ImmortalEngine::fromOldGame() { // Hi bits of inventory int certInv = _certificate[kCertInvHi]; - if ((certInv & 1) != 0 ) { + if ((certInv & 1) != 0) { if (_level < 2) { //room.makeObject(3, 0, 0, waterType); } @@ -386,7 +386,7 @@ bool ImmortalEngine::fromOldGame() { if ((certInv & 4) != 0) { //room.makeObject(3, 0, kSporesFrame, antiType); } - // fall through + // fall through default: break; } @@ -446,17 +446,17 @@ void ImmortalEngine::makeCertificate() { if (true/*room.monster[kPlayerID].hasObject(wowCharmType)*/) { _certificate[kCertInvLo] |= 4; } - // fall through + // fall through case 3: if (true/*room.monster[kPlayerID].hasObject(faceRingType)*/) { _certificate[kCertInvLo] |= 1; } - // fall through + // fall through case 4: if (true/*room.monster[kPlayerID].hasObject(coffeeType)*/) { _certificate[kCertInvLo] |= 2; } - // fall through + // fall through case 7: if (true/*room.monster[kPlayerID].hasObject(bronzeType)*/) { _certificate[kCertInvLo] |= 1; @@ -469,7 +469,7 @@ void ImmortalEngine::makeCertificate() { if (true/*room.monster[kPlayerID].hasObject(antiType)*/) { _certificate[kCertInvLo] |= 4; } - // fall through + // fall through default: _lastCertLen = 13; uint8 checksum[4]; @@ -515,11 +515,11 @@ bool ImmortalEngine::getCertificate() { } else if (k == 0x7f) { // The input was a backspace if (certLen != 0) { - certLen--; // Length is one smaller now - backspace(); // move the drawing position back and reprint the '-' char + certLen--; // Length is one smaller now + backspace(); // move the drawing position back and reprint the '-' char backspace(); printChr('-'); - } + } } else { // The input was a key @@ -588,7 +588,7 @@ void ImmortalEngine::printCertificate() { * but grabbing it from a table is faster and doesn't * use a lot of space (especially if it's used anywhere else) */ - char toHex[] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}; + char toHex[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; textBeginning(kStrCert, 0); for (int i = 0; i < _lastCertLen; i++) { diff --git a/engines/immortal/metaengine.cpp b/engines/immortal/metaengine.cpp index 95fcb9ece993..70d628b02b9a 100644 --- a/engines/immortal/metaengine.cpp +++ b/engines/immortal/metaengine.cpp @@ -34,12 +34,12 @@ Common::Error ImmortalMetaEngine::createInstance(OSystem *syst, Engine **engine, bool ImmortalMetaEngine::hasFeature(MetaEngineFeature f) const { return (f == kSavesUseExtendedFormat) || - (f == kSimpleSavesNames) || - (f == kSupportsListSaves) || - (f == kSupportsDeleteSave) || - (f == kSavesSupportMetaInfo) || - (f == kSavesSupportThumbnail) || - (f == kSupportsLoadingDuringStartup); + (f == kSimpleSavesNames) || + (f == kSupportsListSaves) || + (f == kSupportsDeleteSave) || + (f == kSavesSupportMetaInfo) || + (f == kSavesSupportThumbnail) || + (f == kSupportsLoadingDuringStartup); } #if PLUGIN_ENABLED_DYNAMIC(IMMORTAL) diff --git a/engines/immortal/misc.cpp b/engines/immortal/misc.cpp index 938488fb84f6..12465ac9ff8f 100644 --- a/engines/immortal/misc.cpp +++ b/engines/immortal/misc.cpp @@ -23,7 +23,7 @@ namespace Immortal { -/* +/* * * ----- ----- * ----- Main Functions ----- @@ -39,7 +39,7 @@ void ImmortalEngine::miscInit() { void ImmortalEngine::setRandomSeed() {} void ImmortalEngine::getRandom() {} -/* +/* * * ----- ----- * ----- Text Printing ----- @@ -170,7 +170,7 @@ bool ImmortalEngine::textSub(Str s, FadeType f, int n) { index = -1; } textDoSpace(text, index); - + } else { printChr(chr); // We need this to show up now, not when the frame ends, so we have to update the screen here @@ -179,16 +179,16 @@ bool ImmortalEngine::textSub(Str s, FadeType f, int n) { myDelay(5); switch (chr) { case '?': - // fall through + // fall through case ':': myDelay(13); - // fall through + // fall through case '.': myDelay(13); - // fall through + // fall through case ',': myDelay(13); - // fall through + // fall through default: break; } @@ -202,7 +202,7 @@ bool ImmortalEngine::textSub(Str s, FadeType f, int n) { } index++; } - + chr = text[index]; if (f != kTextFadeIn) { @@ -277,16 +277,16 @@ void ImmortalEngine::textDoSpace(Common::String s, int index) { index++; switch (s[index]) { case '=': - // fall through + // fall through case '@': - // fall through + // fall through case '%': - // fall through + // fall through case '[': - // fall through + // fall through case ' ': foundEnd = true; - // fall through + // fall through default: break; } @@ -294,7 +294,7 @@ void ImmortalEngine::textDoSpace(Common::String s, int index) { if (((index - start) + _collumn) >= kMaxCollumns) { if (_row < kMaxRows) { textCR(); - + } else { textAutoPageBreak(); } @@ -316,7 +316,7 @@ bool ImmortalEngine::yesNo() { if (tyes[_heldDirection] == 0) { noOn(); _lastYes = 0; - + } else { yesOn(); _lastYes = 1; @@ -333,7 +333,7 @@ bool ImmortalEngine::yesNo() { standardBeep(); if (_lastYes == 0) { noOn(); - + } else { yesOn(); } @@ -397,9 +397,9 @@ void ImmortalEngine::myDelay(int j) { break; case 0: Utilities::delay(1); - // fall through + // fall through case 2: - // fall through + // fall through default: break; } @@ -408,7 +408,7 @@ void ImmortalEngine::myDelay(int j) { } while (j != 0); } -/* +/* * * ----- ----- * ----- Input Related ----- @@ -419,11 +419,11 @@ void ImmortalEngine::myDelay(int j) { bool ImmortalEngine::buttonPressed() { // Returns false if the button was pressed, but not held or up getInput(); - + if (_heldAction == kActionButton) { // Zero just the button0held bit _myButton &= (0xFF - kButton0Held); - + } else if ((_myButton & kButton0Held) == 0) { _myButton |= kButton0Held; return false; @@ -435,10 +435,10 @@ bool ImmortalEngine::buttonPressed() { bool ImmortalEngine::firePressed() { // Returns false if the button was pressed, but not held or up getInput(); - + if (_heldAction == kActionFire) { _myButton &= (0xFF - kButton1Held); - + } else if ((_myButton & kButton1Held) == 0) { _myButton |= kButton1Held; return false; @@ -448,7 +448,7 @@ bool ImmortalEngine::firePressed() { } -/* +/* * * ----- ----- * ----- Screen Related ----- @@ -459,9 +459,9 @@ bool ImmortalEngine::firePressed() { /* * - * ----- ----- + * ----- ----- * ----- Sound Related ----- - * ----- ----- + * ----- ----- * */ diff --git a/engines/immortal/room.h b/engines/immortal/room.h index 5811b589e4d9..df968d68c4e0 100644 --- a/engines/immortal/room.h +++ b/engines/immortal/room.h @@ -90,10 +90,10 @@ struct Monster { }; struct Flame { -FPattern _p = kFlameOff; + FPattern _p = kFlameOff; uint8 _x = 0; uint8 _y = 0; - int _c = 0; + int _c = 0; }; struct Chest { @@ -126,12 +126,12 @@ class Room { RoomFlag _flags; - uint8 _xPos = 0; - uint8 _yPos = 0; + uint8 _xPos = 0; + uint8 _yPos = 0; uint8 _holeRoom = 0; uint8 _holeCellX = 0; uint8 _holeCellY = 0; - uint8 _candleTmp = 0; // Special case for candle in maze 0 + uint8 _candleTmp = 0; // Special case for candle in maze 0 uint8 _numFlames = 0; uint8 _numInRoom = 0; @@ -150,7 +150,7 @@ class Room { //void init(); //void inRoomNew(); - //void getTilePair(uint8 x, uint8 y); // Modifies a struct of the tile number, aboveTile number, and the cell coordinates of the tile + //void getTilePair(uint8 x, uint8 y); // Modifies a struct of the tile number, aboveTile number, and the cell coordinates of the tile void setHole(); void drawContents(uint16 vX, uint16 vY); @@ -172,14 +172,14 @@ class Room { */ // Init - int cycleNew(CycID id); // Adds a cycle to the current list + int cycleNew(CycID id); // Adds a cycle to the current list void cycleFree(int c); // Getters -DataSprite *cycleGetDataSprite(int c); // This takes the place of getFile + getNum - int cycleGetIndex(int c); - int cycleGetFrame(int c); - int cycleGetNumFrames(int c); + DataSprite *cycleGetDataSprite(int c); // This takes the place of getFile + getNum + int cycleGetIndex(int c); + int cycleGetFrame(int c); + int cycleGetNumFrames(int c); // Setters void cycleSetIndex(int c, int f); @@ -205,7 +205,7 @@ DataSprite *cycleGetDataSprite(int c); // This takes the place of getFile + ge void lightTorch(uint8 x, uint8 y); void flameFreeAll(); void flameSetRoom(Common::Array); - int flameGetCyc(Flame *f, int first); + int flameGetCyc(Flame *f, int first); /* * [bullet.cpp] Functions from Bullet.GS @@ -222,7 +222,7 @@ DataSprite *cycleGetDataSprite(int c); // This takes the place of getFile + ge * [Univ.cpp] Functions from Univ.GS */ - void univAddSprite(uint16 vX, uint16 vY, uint16 x, uint16 y, SpriteName s, int img, uint16 p); + void univAddSprite(uint16 vX, uint16 vY, uint16 x, uint16 y, SpriteName s, int img, uint16 p); }; } // namespace immortal diff --git a/engines/immortal/sprite_list.h b/engines/immortal/sprite_list.h index 3ef3e1307e15..e301a5089ac0 100644 --- a/engines/immortal/sprite_list.h +++ b/engines/immortal/sprite_list.h @@ -38,17 +38,17 @@ struct Image { }; struct DataSprite { - uint16 _cenX; // These are the base center positions + uint16 _cenX; // These are the base center positions uint16 _cenY; uint16 _numImages; Common::Array _images; }; struct Sprite { - int _image; // Index of _dSprite._images[] + int _image; // Index of _dSprite._images[] uint16 _X; uint16 _Y; - uint16 _on; // 1 = active + uint16 _on; // 1 = active uint16 _priority; DataSprite *_dSprite; }; diff --git a/engines/immortal/sprites.cpp b/engines/immortal/sprites.cpp index 170c8131b1d9..d997fdf1db22 100644 --- a/engines/immortal/sprites.cpp +++ b/engines/immortal/sprites.cpp @@ -53,7 +53,7 @@ namespace Immortal { -/* +/* * * ----- ----- * ----- Main Functions ----- @@ -145,10 +145,10 @@ bool ImmortalEngine::clipSprite(uint16 &height, uint16 &pointIndex, uint16 &skip } else if ((pointY + height) < superTop) { return true; - /* The actual clipping is pretty simple: - * Lower height = stop drawing the sprite early. Higher SkipY = start drawing the sprite late - * So we just determine the delta for each based on superTop and superBottom - */ + /* The actual clipping is pretty simple: + * Lower height = stop drawing the sprite early. Higher SkipY = start drawing the sprite late + * So we just determine the delta for each based on superTop and superBottom + */ } else { // Starting with checking if any of the sprite is under the bottom of the screen @@ -203,7 +203,7 @@ void ImmortalEngine::spriteAligned(DataSprite *dSprite, Image &img, uint16 &skip // as that is the transparent colour pixel1 = (img._bitmap[y][x] & kMask8High) >> 4; pixel2 = (img._bitmap[y][x] & kMask8Low); - + if (pixel1 != 0) { _screenBuff[pointIndex] = pixel1; } @@ -229,7 +229,7 @@ void ImmortalEngine::superSprite(DataSprite *dSprite, uint16 pointX, uint16 poin uint16 height = dSprite->_images[img]._rectH; uint16 skipY = 0; - uint16 pointIndex = 0; // This is 'screen' and 'screen + 2' in the source + uint16 pointIndex = 0; // This is 'screen' and 'screen + 2' in the source pointX -= cenX; pointY -= cenY; @@ -237,7 +237,7 @@ void ImmortalEngine::superSprite(DataSprite *dSprite, uint16 pointX, uint16 poin // Normally I would just make the return from clip be reversed, but the idea is that the return would be 'offscreen == true' if (!(clipSprite(height, pointIndex, skipY, dSprite, pointX, pointY, img, bmw, superTop, superBottom))) { - + // Alignment was a factor in the assembly because it was essentially 2 pixels per byte. However ScummVM is 1 pixel per byte spriteAligned(dSprite, dSprite->_images[img], skipY, pointIndex, height, bmw, dst); } diff --git a/engines/immortal/story.cpp b/engines/immortal/story.cpp index 0d598f82b24d..d86c6d345f58 100644 --- a/engines/immortal/story.cpp +++ b/engines/immortal/story.cpp @@ -32,16 +32,16 @@ * objects, and everything in the rooms. */ -/* These are the UNIVAT for each Story entry - UNIVAT 1024,480, 1152, 464, \-1, -1, zip,level1Ladders, rooma, 704/64, 544/32\ - UNIVAT 304, 448, 472+32, 500+16, \-1, -1, zip,level12Ladders, -1, 0, 0\ - UNIVAT 600, 450, 560, 598, \-1, r2.b+(16*r2.a), zip,level3Ladders, r2.b, 640/64, 576/32\ - UNIVAT 120, 540, 188, 584, \-1, -1, zip,level4Ladders, -1, 0, 0\ - UNIVAT 64, 128, 128, 128+32, \-1, -1, zip,level5Ladders, -1, 1088/64, 928/32\ - UNIVAT 768, 224, 896, 288-16, \-1, -1, zip,level5Ladders, -1, 1088/64, 928/32\ - UNIVAT 896, 672+64, 960, 832-16, \-1, -1, zip,level6Ladders, -1, 0, 0\ - UNIVAT 688, 800, 912-64, 888-32, \-1, -1, zip,level7Ladders, -1, 1088/64, 928/32\ - UNIVAT 64, 704, 64+96, 704+64, \-1, -1, zip,level8Ladders, -1, 0, 0\ +/* These are the UNIVAT for each Story entry + UNIVAT 1024,480, 1152, 464, \-1, -1, zip,level1Ladders, rooma, 704/64, 544/32\ + UNIVAT 304, 448, 472+32, 500+16, \-1, -1, zip,level12Ladders, -1, 0, 0\ + UNIVAT 600, 450, 560, 598, \-1, r2.b+(16*r2.a), zip,level3Ladders, r2.b, 640/64, 576/32\ + UNIVAT 120, 540, 188, 584, \-1, -1, zip,level4Ladders, -1, 0, 0\ + UNIVAT 64, 128, 128, 128+32, \-1, -1, zip,level5Ladders, -1, 1088/64, 928/32\ + UNIVAT 768, 224, 896, 288-16, \-1, -1, zip,level5Ladders, -1, 1088/64, 928/32\ + UNIVAT 896, 672+64, 960, 832-16, \-1, -1, zip,level6Ladders, -1, 0, 0\ + UNIVAT 688, 800, 912-64, 888-32, \-1, -1, zip,level7Ladders, -1, 1088/64, 928/32\ + UNIVAT 64, 704, 64+96, 704+64, \-1, -1, zip,level8Ladders, -1, 0, 0\ */ #include "immortal/immortal.h" @@ -50,155 +50,155 @@ namespace Immortal { void ImmortalEngine::initStoryStatic() { Common::Array s{"#" + Common::String(kSwordBigFrame) + "sword@", - "You find an Elven sword of&agility. Take it?@", - "Search the bones?%", - "}The sword permanently endows you with Elven agility and quickness in combat.@", - "}You notice something that looks wet and green under the pile. Search further?%", - "#" + Common::String(kBagBigFrame) + " dust@", - "}You find a bag containing Dust of Complaisance.&@", - "}Drop the bait on the ground here?%", - "}To use this dust, you throw it in the air. Do that here?%", - "_}Don+t bother me, I+m cutting a gem. Yes, you need it. No, you can+t have it. I wouldn+t give it to anyone, least of all you. Go away. ]]]]=", - "_}Let me help you. Please take this gem. No, really, I insist. Take it and go with my blessings. Good luck. ]]]]=", - "#" + Common::String(kCarpetBigFrame) + "carpet@", - "#" + Common::String(kBombBigFrame) + " bomb@", - "A gas bomb that goblins&use to paralyze trolls.&@", - "Take it?<>@", - "%", - " other@", - "#" + Common::String(kKeyBigFrame) + " key@", - "#" + Common::String(kKeyBigFrame) + " key@", - "A key to a chest.&@", - "The chest is open. Examine&contents?%", - "Put it on?%", - "Drop it?%", - "It+s unlocked. Open it?%", - "It+s locked but you have&the key. Open it?%", - "It+s locked and you don+t&have the key.@", - "The lock, triggered by a&complicated set of latches,&is unfamiliar to you.@", - "#" + Common::String(kGoldBigFrame) + "$0 gold@", - "You find $0 gold pieces.&&^#" + Common::String(kPileFrame) + "@", - "@", - "You can+t plant them on&stone tiles.@", - "It+s locked but you are&able to unlock it with&the key.@", - "_}The king is not dead, but the poison is taking effect. When he sees you, he attempts to speak:[(Give me water... the fountain... I give you... information... peace...+[Give him water?%", - "_}You dont have any water to give him. He mumbles something. Then silence... You find a key on his body.]]]]=", - "_}He mumbles something. Then silence... You find a key on his body.]]]]=", - "_}I+ll tell you how to... next level... past slime... three jewels... slime... rock becomes... floor... right, left, center of the... [Then silence. His hand opens, releasing a key.]]]]=", - "You find a door key.&@", - "You find a note.&@", - "#" + Common::String(kNoteBigFrame) + "note@", - "He+s dead.&Look for possessions?%", - "You don+t have it. Check&your inventory.@", - "Game Over&&Play again?@", - "Congratulations!&&Play again?@", - "You find a bag of bait.&@", - "#" + Common::String(kBagBigFrame) + " bait@", - "You find a stone. @", - "#" + Common::String(kStoneBigFrame) + " stone@", - "You find a red gem.&@", - "#" + Common::String(kGemBigFrame) + " gem@", - "You find a scroll with&fireball spells.&@", - "#" + Common::String(kScrollBigFrame) + "$ shots@", - "You find a map warning&you about pit traps.&@", - "#" + Common::String(kMapBigFrame) + " map@", - "#" + Common::String(kVaseBigFrame) + " oil@", - "You apply the oil but notice&as you walk that the leather&is drying out quickly.@", - "}You discover a scroll with a charm spell to use on will o+ the wisps.&@", - "#" + Common::String(kScrollBigFrame) + " charm@", - "}This charms the will o+ the wisps to follow you. Read the spell again to turn them against your enemies.@", - "}It looks like water. Drink it?%", - "Drink it?%", - "}It works! You are much stronger.]]]=", - "}It looks like it has green stuff inside. Open it?%", - "Now this will take&effect when you press the&fire button.@", - "You find a potion,&Magic Muscle.&@", - "#" + Common::String(kVaseBigFrame) + " potion@", - "You find a bottle.&@", - "#" + Common::String(kVaseBigFrame) + " bottle@", - "#" + Common::String(kRingBigFrame) + "Protean@", - "You find a Protean Ring.&@", - "You find a troll ritual knife,&used to declare a fight to&the death. @", - "#" + Common::String(kKnifeBigFrame) + " knife@", - "_}It is a fine woman+s garment. Folded inside is a ring with the words,[`To Ana, so harm will never find you. -Your loving father, Dunric.+&@", - "You find a small, well&crafted ring. @", - "#" + Common::String(kRingBigFrame) + " gift@", - "#" + Common::String(kRingBigFrame) + " Ana+s@", - "_}She is hurt and upset when she finds you don+t have her ring or won+t give it to her. She scurries back into the hole. The hole is too small for you to follow.&@", - "_}`Sir, can you help me,+ the girl pleads. `I was kidnapped and dragged down here. All the man would say is `Mordamir+s orders.+[I ~" + Common::String(kStrGive2), - "escaped using a ring my father gave me, but now I+ve lost it. Did you find it?+%", - "_}We have met before, old man. Do you remember? Because you helped me, you may pass. But I warn you, we are at war with the trolls.[Over this ladder, across the spikes, is troll territory. Very dangerous.@", - "_}You are an impostor!]]]]=", - "_}Old man, do you remember me? I am king of the goblins. You didn+t give me the water. You left me to die after you took the key from me. Now you will pay.]]]]=", - "_}You quickly fall into a deep, healing sleep...[Vivid images of a beautiful enchanted city pass by. All the city people are young and glowing. Fountains fill the city, and the splash and ~" + Common::String(kStrDream1P2), - "sparkle of water is everywhere...[Suddenly the images go black. A face appears... Mordamir!]][ ~" + Common::String(kStrDream1P3), - "He is different from how you remember him. His gentle features are now withered. His kind eyes, now cold and sunken, seem to look through you with a dark, penetrating stare. You wake rejuvenated, but disturbed.]]]]]=", - "_}Here, take this ring in return. [I don+t know if it will help, but I heard the unpleasant little dwarf say, (Clockwise, three rings around the triangle.+[Could that be a clue to his exit puzzle? I must go. Goodbye.]]]]=", - "#" + Common::String(kSackBigFrame) + " spores@", - "You find a sack of bad&smelling spores.&@", - "Please insert play disk.@", - "New game?%", - "Enter certificate:&-=", - "Invalid certificate.@", - "End of level!&Here is your certificate:&&=", - "&@", - "\\ Electronic Arts presents&& The Immortal&&&&  1990 Will Harvey|]]]]]]]]\\]=", - " written by&& Will Harvey& Ian Gooding& Michael Marcantel& Brett G. Durrett& Douglas Fulton|]]]]]]]/=", - "_}Greetings, friend! Come, I+ve got something you need. These parts are plagued with slime.[You can+t venture safely without my slime oil for boots, a bargain at only 80 gold pieces.%", - "_}All right, 60 gold pieces for my oil. Rub it on your boots and slime won+t touch you. 60, friend.%", - "This room doesn+t resemble&any part of the map.@", - "This room resembles part&of the map.@"}; + "You find an Elven sword of&agility. Take it?@", + "Search the bones?%", + "}The sword permanently endows you with Elven agility and quickness in combat.@", + "}You notice something that looks wet and green under the pile. Search further?%", + "#" + Common::String(kBagBigFrame) + " dust@", + "}You find a bag containing Dust of Complaisance.&@", + "}Drop the bait on the ground here?%", + "}To use this dust, you throw it in the air. Do that here?%", + "_}Don+t bother me, I+m cutting a gem. Yes, you need it. No, you can+t have it. I wouldn+t give it to anyone, least of all you. Go away. ]]]]=", + "_}Let me help you. Please take this gem. No, really, I insist. Take it and go with my blessings. Good luck. ]]]]=", + "#" + Common::String(kCarpetBigFrame) + "carpet@", + "#" + Common::String(kBombBigFrame) + " bomb@", + "A gas bomb that goblins&use to paralyze trolls.&@", + "Take it?<>@", + "%", + " other@", + "#" + Common::String(kKeyBigFrame) + " key@", + "#" + Common::String(kKeyBigFrame) + " key@", + "A key to a chest.&@", + "The chest is open. Examine&contents?%", + "Put it on?%", + "Drop it?%", + "It+s unlocked. Open it?%", + "It+s locked but you have&the key. Open it?%", + "It+s locked and you don+t&have the key.@", + "The lock, triggered by a&complicated set of latches,&is unfamiliar to you.@", + "#" + Common::String(kGoldBigFrame) + "$0 gold@", + "You find $0 gold pieces.&&^#" + Common::String(kPileFrame) + "@", + "@", + "You can+t plant them on&stone tiles.@", + "It+s locked but you are&able to unlock it with&the key.@", + "_}The king is not dead, but the poison is taking effect. When he sees you, he attempts to speak:[(Give me water... the fountain... I give you... information... peace...+[Give him water?%", + "_}You dont have any water to give him. He mumbles something. Then silence... You find a key on his body.]]]]=", + "_}He mumbles something. Then silence... You find a key on his body.]]]]=", + "_}I+ll tell you how to... next level... past slime... three jewels... slime... rock becomes... floor... right, left, center of the... [Then silence. His hand opens, releasing a key.]]]]=", + "You find a door key.&@", + "You find a note.&@", + "#" + Common::String(kNoteBigFrame) + "note@", + "He+s dead.&Look for possessions?%", + "You don+t have it. Check&your inventory.@", + "Game Over&&Play again?@", + "Congratulations!&&Play again?@", + "You find a bag of bait.&@", + "#" + Common::String(kBagBigFrame) + " bait@", + "You find a stone. @", + "#" + Common::String(kStoneBigFrame) + " stone@", + "You find a red gem.&@", + "#" + Common::String(kGemBigFrame) + " gem@", + "You find a scroll with&fireball spells.&@", + "#" + Common::String(kScrollBigFrame) + "$ shots@", + "You find a map warning&you about pit traps.&@", + "#" + Common::String(kMapBigFrame) + " map@", + "#" + Common::String(kVaseBigFrame) + " oil@", + "You apply the oil but notice&as you walk that the leather&is drying out quickly.@", + "}You discover a scroll with a charm spell to use on will o+ the wisps.&@", + "#" + Common::String(kScrollBigFrame) + " charm@", + "}This charms the will o+ the wisps to follow you. Read the spell again to turn them against your enemies.@", + "}It looks like water. Drink it?%", + "Drink it?%", + "}It works! You are much stronger.]]]=", + "}It looks like it has green stuff inside. Open it?%", + "Now this will take&effect when you press the&fire button.@", + "You find a potion,&Magic Muscle.&@", + "#" + Common::String(kVaseBigFrame) + " potion@", + "You find a bottle.&@", + "#" + Common::String(kVaseBigFrame) + " bottle@", + "#" + Common::String(kRingBigFrame) + "Protean@", + "You find a Protean Ring.&@", + "You find a troll ritual knife,&used to declare a fight to&the death. @", + "#" + Common::String(kKnifeBigFrame) + " knife@", + "_}It is a fine woman+s garment. Folded inside is a ring with the words,[`To Ana, so harm will never find you. -Your loving father, Dunric.+&@", + "You find a small, well&crafted ring. @", + "#" + Common::String(kRingBigFrame) + " gift@", + "#" + Common::String(kRingBigFrame) + " Ana+s@", + "_}She is hurt and upset when she finds you don+t have her ring or won+t give it to her. She scurries back into the hole. The hole is too small for you to follow.&@", + "_}`Sir, can you help me,+ the girl pleads. `I was kidnapped and dragged down here. All the man would say is `Mordamir+s orders.+[I ~" + Common::String(kStrGive2), + "escaped using a ring my father gave me, but now I+ve lost it. Did you find it?+%", + "_}We have met before, old man. Do you remember? Because you helped me, you may pass. But I warn you, we are at war with the trolls.[Over this ladder, across the spikes, is troll territory. Very dangerous.@", + "_}You are an impostor!]]]]=", + "_}Old man, do you remember me? I am king of the goblins. You didn+t give me the water. You left me to die after you took the key from me. Now you will pay.]]]]=", + "_}You quickly fall into a deep, healing sleep...[Vivid images of a beautiful enchanted city pass by. All the city people are young and glowing. Fountains fill the city, and the splash and ~" + Common::String(kStrDream1P2), + "sparkle of water is everywhere...[Suddenly the images go black. A face appears... Mordamir!]][ ~" + Common::String(kStrDream1P3), + "He is different from how you remember him. His gentle features are now withered. His kind eyes, now cold and sunken, seem to look through you with a dark, penetrating stare. You wake rejuvenated, but disturbed.]]]]]=", + "_}Here, take this ring in return. [I don+t know if it will help, but I heard the unpleasant little dwarf say, (Clockwise, three rings around the triangle.+[Could that be a clue to his exit puzzle? I must go. Goodbye.]]]]=", + "#" + Common::String(kSackBigFrame) + " spores@", + "You find a sack of bad&smelling spores.&@", + "Please insert play disk.@", + "New game?%", + "Enter certificate:&-=", + "Invalid certificate.@", + "End of level!&Here is your certificate:&&=", + "&@", + "\\ Electronic Arts presents&& The Immortal&&&&  1990 Will Harvey|]]]]]]]]\\]=", + " written by&& Will Harvey& Ian Gooding& Michael Marcantel& Brett G. Durrett& Douglas Fulton|]]]]]]]/=", + "_}Greetings, friend! Come, I+ve got something you need. These parts are plagued with slime.[You can+t venture safely without my slime oil for boots, a bargain at only 80 gold pieces.%", + "_}All right, 60 gold pieces for my oil. Rub it on your boots and slime won+t touch you. 60, friend.%", + "This room doesn+t resemble&any part of the map.@", + "This room resembles part&of the map.@"}; _strPtrs = s; - Common::Array cyc0{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,-1}; - Common::Array cyc1{15,16,17,18,19,20,21,22,-1}; - Common::Array cyc2{0,1,2,-1}; - Common::Array cyc3{3,4,5,-1}; - Common::Array cyc4{6,7,8,9,10,-1}; - Common::Array cyc5{11,12,13,14,15,-1}; - Common::Array cyc6{16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,-1}; - Common::Array cyc7{0,1,2,3,4,-1}; - Common::Array cyc8{5,1 + 5,2 + 5,3 + 5,4 + 5,-1}; - Common::Array cyc9{10,1 + 10,2 + 10,3 + 10,4 + 10,-1}; - Common::Array cyc10{15,1 + 15,2 + 15,3 + 15,4 + 15,-1}; - Common::Array cyc11{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,-1}; - Common::Array cyc12{0,1,2,3,4,5,6,7,8,9,-1}; - Common::Array cyc13{0,1,2,3, 0,1,2,3, 0,1,2,3, 0,1,2,3, 0,1,2,3, 0,1,2,3, 0,1,2,3, 0,1,2,3, -1}; - Common::Array cyc14{31,32,33,32, 34,35,36,35, 37,38,39,38, 40,41,42,41, 43,44,45,44, 46,47,48,47, 49,50,51,50, 52,53,54,53, -1}; + Common::Array cyc0{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, -1}; + Common::Array cyc1{15, 16, 17, 18, 19, 20, 21, 22, -1}; + Common::Array cyc2{0, 1, 2, -1}; + Common::Array cyc3{3, 4, 5, -1}; + Common::Array cyc4{6, 7, 8, 9, 10, -1}; + Common::Array cyc5{11, 12, 13, 14, 15, -1}; + Common::Array cyc6{16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, -1}; + Common::Array cyc7{0, 1, 2, 3, 4, -1}; + Common::Array cyc8{5, 1 + 5, 2 + 5, 3 + 5, 4 + 5, -1}; + Common::Array cyc9{10, 1 + 10, 2 + 10, 3 + 10, 4 + 10, -1}; + Common::Array cyc10{15, 1 + 15, 2 + 15, 3 + 15, 4 + 15, -1}; + Common::Array cyc11{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, -1}; + Common::Array cyc12{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1}; + Common::Array cyc13{0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, -1}; + Common::Array cyc14{31, 32, 33, 32, 34, 35, 36, 35, 37, 38, 39, 38, 40, 41, 42, 41, 43, 44, 45, 44, 46, 47, 48, 47, 49, 50, 51, 50, 52, 53, 54, 53, -1}; Common::Array cyc15{55, -1}; - Common::Array cyc16{63,64,65,66, 63,64,65,66, 63,64,65,66, 63,64,65,66, 63,64,65,66, 63,64,65,66, 63,64,65,66, 63,64,65,66,-1}; - Common::Array cyc17{0,1,0,-1}; - Common::Array cyc18{0,1,2,4,5,6,7,8,9,10,11,12,2,1,-1}; - Common::Array cyc19{0,0,1,2,13,14,15,16,4,2,3,-1}; - Common::Array cyc20{0,1,2,3,20,21,22,23,24,25,26,27,5,4,3,-1}; - Common::Array cyc21{0,1,2,3,-1}; - Common::Array cyc22{0,17,18,19,3,-1}; - Common::Array cyc23{0,1,-1}; - Common::Array cyc24{28,28,28,28,-1}; - Common::Array cyc25{15,16,15,16,15,1 + 15,1 + 15,-1}; - Common::Array cyc26{10 + 15,11+ 15,12 + 15,13 + 15,14 + 15,15 + 15,16 + 15,-1}; - Common::Array cyc27{2 + 15,3 + 15,4 + 15,5 + 15,-1}; - Common::Array cyc28{6 + 15,7 + 15,8 + 15,9 + 15,-1}; - Common::Array cyc29{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,-1}; - Common::Array cyc30{0,1,2,3,3,3,3,4,5,6,-1}; - Common::Array cyc31{0,1,2,3,4,5,6,7,8,-1}; + Common::Array cyc16{63, 64, 65, 66, 63, 64, 65, 66, 63, 64, 65, 66, 63, 64, 65, 66, 63, 64, 65, 66, 63, 64, 65, 66, 63, 64, 65, 66, 63, 64, 65, 66, -1}; + Common::Array cyc17{0, 1, 0, -1}; + Common::Array cyc18{0, 1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 2, 1, -1}; + Common::Array cyc19{0, 0, 1, 2, 13, 14, 15, 16, 4, 2, 3, -1}; + Common::Array cyc20{0, 1, 2, 3, 20, 21, 22, 23, 24, 25, 26, 27, 5, 4, 3, -1}; + Common::Array cyc21{0, 1, 2, 3, -1}; + Common::Array cyc22{0, 17, 18, 19, 3, -1}; + Common::Array cyc23{0, 1, -1}; + Common::Array cyc24{28, 28, 28, 28, -1}; + Common::Array cyc25{15, 16, 15, 16, 15, 1 + 15, 1 + 15, -1}; + Common::Array cyc26{10 + 15, 11 + 15, 12 + 15, 13 + 15, 14 + 15, 15 + 15, 16 + 15, -1}; + Common::Array cyc27{2 + 15, 3 + 15, 4 + 15, 5 + 15, -1}; + Common::Array cyc28{6 + 15, 7 + 15, 8 + 15, 9 + 15, -1}; + Common::Array cyc29{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, -1}; + Common::Array cyc30{0, 1, 2, 3, 3, 3, 3, 4, 5, 6, -1}; + Common::Array cyc31{0, 1, 2, 3, 4, 5, 6, 7, 8, -1}; - Common::Array c{SCycle(kBubble, false, cyc0), SCycle(kBubble, false, cyc1), - SCycle(kSpark, false, cyc2), SCycle(kSpark, false, cyc3), - SCycle(kSpark, false, cyc4), SCycle(kSpark, false, cyc5), SCycle(kSpark, false, cyc6), - SCycle(kPipe, false, cyc7), SCycle(kPipe, false, cyc8), - SCycle(kPipe, false, cyc9), SCycle(kPipe, false, cyc10), - SCycle(kAnaVanish, false, cyc11), SCycle(kAnaGlimpse, false, cyc12), - SCycle(kKnife, true, cyc13), - SCycle(kSpark, true, cyc14), SCycle(kSpark, true, cyc15), SCycle(kSpark, true, cyc16), - SCycle(kBigBurst, false, cyc17), - SCycle(kFlame, false, cyc18), SCycle(kFlame, false, cyc19), SCycle(kFlame, false, cyc20), - SCycle(kFlame, false, cyc21), SCycle(kFlame, false, cyc22), SCycle(kFlame, false, cyc23), - SCycle(kFlame, false, cyc24), - SCycle(kCandle, false, cyc25), SCycle(kCandle, false, cyc26), SCycle(kCandle, false, cyc27), - SCycle(kCandle, false, cyc28), SCycle(kCandle, false, cyc29), - SCycle(kSink, false, cyc30), - SCycle(kNorlacDown, false, cyc31)}; + Common::Array c{SCycle(kBubble, false, cyc0), SCycle(kBubble, false, cyc1), + SCycle(kSpark, false, cyc2), SCycle(kSpark, false, cyc3), + SCycle(kSpark, false, cyc4), SCycle(kSpark, false, cyc5), SCycle(kSpark, false, cyc6), + SCycle(kPipe, false, cyc7), SCycle(kPipe, false, cyc8), + SCycle(kPipe, false, cyc9), SCycle(kPipe, false, cyc10), + SCycle(kAnaVanish, false, cyc11), SCycle(kAnaGlimpse, false, cyc12), + SCycle(kKnife, true, cyc13), + SCycle(kSpark, true, cyc14), SCycle(kSpark, true, cyc15), SCycle(kSpark, true, cyc16), + SCycle(kBigBurst, false, cyc17), + SCycle(kFlame, false, cyc18), SCycle(kFlame, false, cyc19), SCycle(kFlame, false, cyc20), + SCycle(kFlame, false, cyc21), SCycle(kFlame, false, cyc22), SCycle(kFlame, false, cyc23), + SCycle(kFlame, false, cyc24), + SCycle(kCandle, false, cyc25), SCycle(kCandle, false, cyc26), SCycle(kCandle, false, cyc27), + SCycle(kCandle, false, cyc28), SCycle(kCandle, false, cyc29), + SCycle(kSink, false, cyc30), + SCycle(kNorlacDown, false, cyc31)}; _cycPtrs = c; Common::Array m{}; @@ -251,7 +251,7 @@ void ImmortalEngine::initStoryDynamic() { /* Universe related properties * including spawn point and entry/exit points - */ + */ int univRoom = 4; // The room the player starts in when beginning this level uint16 univRoomX = 512; uint16 univRoomY = 416; @@ -263,39 +263,39 @@ void ImmortalEngine::initStoryDynamic() { _stories[0]._playerPointX = (1152 - univRoomX) / 2; _stories[0]._playerPointY = 464 - univRoomY; - Common::Array ladders{-1, -1, kStoryNull, 2, 0, univRoom, (704 / 64),(544 / 32)}; + Common::Array ladders{-1, -1, kStoryNull, 2, 0, univRoom, (704 / 64), (544 / 32)}; _stories[0]._ladders = ladders; /* All of the rooms */ Common::Array rooms{SRoom(384, 256, kRoomFlag0), SRoom(512, 64, kRoomFlag0), - SRoom(640, 160, kRoomFlag0), SRoom(768, 224, kRoomFlag0), - SRoom(univRoomX, univRoomY, kRoomFlag0), SRoom(960, 512, kRoomFlag0), - SRoom(1024, 352, kRoomFlag0), SRoom(896, 64, kRoomFlag0)}; + SRoom(640, 160, kRoomFlag0), SRoom(768, 224, kRoomFlag0), + SRoom(univRoomX, univRoomY, kRoomFlag0), SRoom(960, 512, kRoomFlag0), + SRoom(1024, 352, kRoomFlag0), SRoom(896, 64, kRoomFlag0)}; _stories[0]._rooms = rooms; /* All of the doors */ Common::Array doors{SDoor(0, 704, 224, 0, 2, false), SDoor(1, 576, 352, 4, 0, true), - SDoor(1, 704, 96, 2, 1, false), SDoor(1, 960, 128, 7, 2, false), - SDoor(1, 1088,160, 3, 7, false), SDoor(1, 1088,320, 6, 3, false), - SDoor(1, 896, 416, 4, 3, false)}; + SDoor(1, 704, 96, 2, 1, false), SDoor(1, 960, 128, 7, 2, false), + SDoor(1, 1088, 160, 3, 7, false), SDoor(1, 1088, 320, 6, 3, false), + SDoor(1, 896, 416, 4, 3, false)}; _stories[0]._doors = doors; /* All of the flames * Macro for flames is (x - roomx), (y - roomy), pattern number */ - Common::Array f5{SFlame(512 - 384, (240 + 32) - 256, kFlameOff), SFlame(672 - 384, (240 + 32) - 256, kFlameOff)}; - Common::Array f7{SFlame(576 - 384, (112 + 32) - 256, kFlameNormal), SFlame(576 - 384, (112 + 32) - 256, kFlameNormal), - SFlame(928 - 384, (48 + 32) - 256, kFlameNormal)}; - Common::Array f8{SFlame(800 - 640, (144 + 32) - 160, kFlameNormal)}; - Common::Array f9{SFlame(768 - 768, (304 + 32) - 224, kFlameNormal), SFlame((928 - 768), (304 + 32) - 224, kFlameNormal), - SFlame(1024 - 768, (240 + 32) - 224, kFlameNormal)}; - Common::Array fA{SFlame(672 - 512, (400 + 32) - 416, kFlameNormal), SFlame((800 - 64) - 512, (496 - 32) - 416, kFlameNormal), - SFlame(576 - 512, (528 + 32) - 416, kFlameNormal)}; - Common::Array fD{SFlame(1024 - 960, (496 + 32) - 512, kFlameNormal)}; - Common::Array fE{SFlame(1184 - 1024, 432 - 352, kFlameCandle)}; - Common::Array fF{SFlame(1024 - 896, (144 + 32) - 64, kFlameNormal)}; + Common::Array f5{SFlame(512 - 384, (240 + 32) - 256, kFlameOff), SFlame(672 - 384, (240 + 32) - 256, kFlameOff)}; + Common::Array f7{SFlame(576 - 384, (112 + 32) - 256, kFlameNormal), SFlame(576 - 384, (112 + 32) - 256, kFlameNormal), + SFlame(928 - 384, (48 + 32) - 256, kFlameNormal)}; + Common::Array f8{SFlame(800 - 640, (144 + 32) - 160, kFlameNormal)}; + Common::Array f9{SFlame(768 - 768, (304 + 32) - 224, kFlameNormal), SFlame((928 - 768), (304 + 32) - 224, kFlameNormal), + SFlame(1024 - 768, (240 + 32) - 224, kFlameNormal)}; + Common::Array fA{SFlame(672 - 512, (400 + 32) - 416, kFlameNormal), SFlame((800 - 64) - 512, (496 - 32) - 416, kFlameNormal), + SFlame(576 - 512, (528 + 32) - 416, kFlameNormal)}; + Common::Array fD{SFlame(1024 - 960, (496 + 32) - 512, kFlameNormal)}; + Common::Array fE{SFlame(1184 - 1024, 432 - 352, kFlameCandle)}; + Common::Array fF{SFlame(1024 - 896, (144 + 32) - 64, kFlameNormal)}; CArray2D flames{f5, f7, f8, f9, fA, fD, fE, fF}; _stories[0]._flames = flames; @@ -303,29 +303,29 @@ void ImmortalEngine::initStoryDynamic() { * Macro for traps is arrowType,freq,#sinkTraps,#1(going toward 5),#3,#5,#7,#trapdoors */ Common::Array noTraps{}; - Common::Array o5Traps{0,0x80,0,0,0,0,0,5}; - Common::Array o7Traps{0,0x80,15,5,3,0,0,0}; - Common::Array o8Traps{0,0x80,0,0,0,0,0,3}; + Common::Array o5Traps{0, 0x80, 0, 0, 0, 0, 0, 5}; + Common::Array o7Traps{0, 0x80, 15, 5, 3, 0, 0, 0}; + Common::Array o8Traps{0, 0x80, 0, 0, 0, 0, 0, 3}; Common::Array noObj{}; Common::Array o5{SObj(kZip, kZip, kTypeTrap, kNoFrame, kObjIsRunning + kObjIsInvisible, o5Traps), - SObj(459, 379, kTypeCoin, kRingFrame, kObjNone, noTraps), - SObj(446, 327, kTypeWowCharm, kScrollFrame, kObjNone, noTraps)}; + SObj(459, 379, kTypeCoin, kRingFrame, kObjNone, noTraps), + SObj(446, 327, kTypeWowCharm, kScrollFrame, kObjNone, noTraps)}; Common::Array o7{SObj(145, 138, kTypeTrap, kNoFrame, kObjIsRunning + kObjIsInvisible, o7Traps)}; Common::Array o8{SObj(kZip, kZip, kTypeTrap, kNoFrame, kObjIsRunning + kObjIsInvisible, o8Traps)}; Common::Array o9{SObj(1052, 309, kTypeDead, kDeadGoblinFrame, kObjIsChest + kObjIsOnGround, noTraps), - SObj(kZip, kZip, kTypeFireBall, kScrollFrame, kObjUsesFireButton, noTraps), - SObj(128, 464, kTypeDunRing, kRingFrame, 0, noTraps), - SObj(837, 421, kTypeChest, kChest0Frame, kObjIsChest, noTraps), - SObj(kZip, kZip, kTypeDeathMap, kScrollFrame, 0, noTraps), - SObj(597, 457, kTypeWater, kVaseFrame, 0, noTraps), - SObj(kZip, kZip, kTypeSpores, kSporesFrame, 0, noTraps), - SObj(kZip, kZip, kTypeWormFood, kNoFrame, 0, noTraps), - SObj(205, 158, kTypeChestKey, kKeyFrame, 0, noTraps)}; + SObj(kZip, kZip, kTypeFireBall, kScrollFrame, kObjUsesFireButton, noTraps), + SObj(128, 464, kTypeDunRing, kRingFrame, 0, noTraps), + SObj(837, 421, kTypeChest, kChest0Frame, kObjIsChest, noTraps), + SObj(kZip, kZip, kTypeDeathMap, kScrollFrame, 0, noTraps), + SObj(597, 457, kTypeWater, kVaseFrame, 0, noTraps), + SObj(kZip, kZip, kTypeSpores, kSporesFrame, 0, noTraps), + SObj(kZip, kZip, kTypeWormFood, kNoFrame, 0, noTraps), + SObj(205, 158, kTypeChestKey, kKeyFrame, 0, noTraps)}; Common::Array oE{SObj(1184, 426, kTypePhant, kAltarFrame, 0, noTraps), - SObj(145, 138, kTypeGold, kNoFrame, kObjIsRunning, noTraps), - SObj(671, 461, kTypeHay, kNoFrame, kObjIsRunning + kObjIsInvisible, noTraps), - SObj(780, 508, kTypeBeam, kNoFrame, kObjIsRunning + kObjIsInvisible, noTraps)}; + SObj(145, 138, kTypeGold, kNoFrame, kObjIsRunning, noTraps), + SObj(671, 461, kTypeHay, kNoFrame, kObjIsRunning + kObjIsInvisible, noTraps), + SObj(780, 508, kTypeBeam, kNoFrame, kObjIsRunning + kObjIsInvisible, noTraps)}; CArray2D objects{o5, o7, o8, o9, noObj, noObj, oE, noObj}; _stories[0]._objects = objects; @@ -341,10 +341,10 @@ void ImmortalEngine::initStoryDynamic() { Common::Array noMonst{}; Common::Array m5{SMonster(448, 344, 12, kMonstPlayer, kMonstA + kMonstIsEngage + kMonstIsTough, progShade, kShadow), - SMonster(590, 381, 12, kMonstPlayer, kMonstA + kMonstIsEngage + kMonstIsTough, progShade, kShadow)}; + SMonster(590, 381, 12, kMonstPlayer, kMonstA + kMonstIsEngage + kMonstIsTough, progShade, kShadow)}; Common::Array m9{SMonster(1106, 258, 3, kMonstPlayer, kMonstA + kMonstIsEngage, progEasy, kGoblin0), - SMonster(832, 364, 10, kMonstA, kMonstB + kMonstIsPoss, progUlindor, kUlindor3), - SMonster(838, 370, 15, kMonstPlayer, kMonstA + kMonstIsEngage, progGoblin5, kGoblin7)}; + SMonster(832, 364, 10, kMonstA, kMonstB + kMonstIsPoss, progUlindor, kUlindor3), + SMonster(838, 370, 15, kMonstPlayer, kMonstA + kMonstIsEngage, progGoblin5, kGoblin7)}; Common::Array mE{SMonster(1136, 464, 15, kMonstMonster, kMonstPlayer + kMonstIsEngage, progPlayer, kWizard0)}; Common::Array mF{SMonster(1182, 116, 5, kMonstPlayer, kMonstA + kMonstIsEngage, progWill2, kGoblin5)}; CArray2D monsters{m5, noMonst, noMonst, m9, noMonst, noMonst, mE, mF}; diff --git a/engines/immortal/story.h b/engines/immortal/story.h index f201c8ae0e49..b3cfd1732aa4 100644 --- a/engines/immortal/story.h +++ b/engines/immortal/story.h @@ -32,25 +32,25 @@ namespace Immortal { // These maximum numbers aren't really needed, because most of these are vectors and have .size() enum StoryMaxes { - kMaxRooms = 16, - kMaxDoors = 10, - kMaxFlames = 32, + kMaxRooms = 16, + kMaxDoors = 10, + kMaxFlames = 32, kMaxFlamesInRoom = 5, - kMaxObjects = 42, - kMaxMonsters = 20, - kMaxGenSprites = 6, - kMaxCycles = 32 + kMaxObjects = 42, + kMaxMonsters = 20, + kMaxGenSprites = 6, + kMaxCycles = 32 }; // These are flags that are relevant to their specific story data structures -enum RoomFlag : uint8 { // Generic properties available to each room +enum RoomFlag : uint8 { // Generic properties available to each room kRoomFlag0 = 0x01, kRoomFlag1 = 0x02, kRoomFlag2 = 0x04, kRoomFlag3 = 0x08 }; -enum ObjFlag : uint8 { // Properties of the object essentially +enum ObjFlag : uint8 { // Properties of the object essentially kObjUsesFireButton = 0x40, kObjIsInvisible = 0x20, kObjIsRunning = 0x10, @@ -58,16 +58,16 @@ enum ObjFlag : uint8 { // Properties of the object essentially kObjIsOnGround = 0x04, kObjIsF1 = 0x02, kObjIsF2 = 0x01, - kObjNone = 0x0 + kObjNone = 0x0 }; -enum IsA : uint8 { // To be completely honest, I'm not really sure what this is. It seems to be more object flags, but they act a little strangely - kIsAF1 = 0x20, - kIsAF2 = 0x40, +enum IsA : uint8 { // To be completely honest, I'm not really sure what this is. It seems to be more object flags, but they act a little strangely + kIsAF1 = 0x20, + kIsAF2 = 0x40, kIsANone = 0x0, }; -enum MonsterFlag : uint8 { // Mostly properties of the AI for a given monster, *including the player* +enum MonsterFlag : uint8 { // Mostly properties of the AI for a given monster, *including the player* kMonstIsNone = 0x00, kMonstIsTough = 0x10, kMonstIsDead = 0x20, @@ -78,14 +78,14 @@ enum MonsterFlag : uint8 { // Mostly properties of the AI for a given monst kMonstMonster = 0x01, kMonstAnybody = 0x02, kMonstNobody = 0x03, - kMonstA = 0x04, - kMonstB = 0x05, - kMonstC = 0x06, - kMonstD = 0x07 + kMonstA = 0x04, + kMonstB = 0x05, + kMonstC = 0x06, + kMonstD = 0x07 }; // Flame pattern is used by the story data, in-room data, *and* the level based total flame data. So it needs to be in story.h to be used by immortal.h and room.h -enum FPattern : uint8 { // This defines which Cyc animation it uses +enum FPattern : uint8 { // This defines which Cyc animation it uses kFlameNormal, kFlameCandle, kFlameOff, @@ -128,7 +128,7 @@ struct ObjType { // Cycles define the animation of sprites within a level. There is a fixed total of cycles available, and they are not room dependant struct Cycle { - int _index; // In source this is actually the position within the *instruction list*, but since cycle's are structs, it's just the index of frames now + int _index; // In source this is actually the position within the *instruction list*, but since cycle's are structs, it's just the index of frames now CycID _cycList; }; @@ -141,12 +141,12 @@ struct SCycle { SpriteName _sName; Common::Array _frames; bool _repeat; - SCycle() {} - SCycle(SpriteName s, bool r, Common::Array f) { - _sName = s; - _repeat = r; - _frames = f; - } + SCycle() {} + SCycle(SpriteName s, bool r, Common::Array f) { + _sName = s; + _repeat = r; + _frames = f; + } }; struct SRoom { @@ -156,8 +156,8 @@ struct SRoom { RoomFlag _flags = kRoomFlag0; SRoom() {} SRoom(uint16 x, uint16 y, RoomFlag f) { - _x = x; - _y = y; + _x = x; + _y = y; _flags = f; } }; @@ -174,19 +174,19 @@ struct SDoor { SDoor() {} SDoor(uint8 d, uint16 x, uint16 y, uint16 f, uint16 t, bool l) { _dir = d; - _x = x; - _y = y; + _x = x; + _y = y; _fromRoom = f; - _toRoom = t; + _toRoom = t; _isLocked = l; - } + } }; struct SFlame { - uint16 _x = 0; - uint16 _y = 0; + uint16 _x = 0; + uint16 _y = 0; FPattern _p = kFlameOff; SFlame() {} @@ -207,9 +207,9 @@ struct SObj { Common::Array _traps; SObj() {} SObj(uint16 x, uint16 y, SObjType t, SpriteFrame s, uint8 f, Common::Array traps) { - _x = x; - _y = y; - _type = t; + _x = x; + _y = y; + _type = t; _flags = f; _traps = traps; _frame = s; @@ -227,13 +227,13 @@ struct SMonster { Common::Array _program; SMonster() {} SMonster(uint16 x, uint16 y, uint16 h, MonsterFlag m, uint8 f, Common::Array p, SpriteName s) { - _x = x; - _y = y; - _hits = h; + _x = x; + _y = y; + _hits = h; _madAt = m; _flags = f; - _program = p; - _sprite = s; + _program = p; + _sprite = s; } }; @@ -246,12 +246,12 @@ struct Story { uint16 _playerPointX = 0; uint16 _playerPointY = 0; - Common::Array _ladders; + Common::Array _ladders; Common::Array _rooms; Common::Array _doors; - CArray2D _flames; - CArray2D _objects; - CArray2D _monsters; + CArray2D _flames; + CArray2D _objects; + CArray2D _monsters; }; } // namespace immortal diff --git a/engines/immortal/utilities.cpp b/engines/immortal/utilities.cpp index 46d098a2fb0d..03e5107fc4e1 100644 --- a/engines/immortal/utilities.cpp +++ b/engines/immortal/utilities.cpp @@ -23,7 +23,7 @@ namespace Immortal { -/* +/* * * ----- ----- * ----- General Use ----- From ffb7ffc6eb71431d0a79a34837b232ce40c99d71 Mon Sep 17 00:00:00 2001 From: Quote58 Date: Mon, 30 Jan 2023 21:11:07 -0500 Subject: [PATCH 371/412] IMMORTAL: Pass flameSet list by reference instead of copy --- engines/immortal/flameSet.cpp | 2 +- engines/immortal/room.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/engines/immortal/flameSet.cpp b/engines/immortal/flameSet.cpp index f9a7964f8d31..a5f487448815 100644 --- a/engines/immortal/flameSet.cpp +++ b/engines/immortal/flameSet.cpp @@ -88,7 +88,7 @@ void Room::lightTorch(uint8 x, uint8 y) { } } -void Room::flameSetRoom(Common::Array allFlames) { +void Room::flameSetRoom(Common::Array &allFlames) { for (int i = 0; i < allFlames.size(); i++) { Flame f; f._p = allFlames[i]._p; diff --git a/engines/immortal/room.h b/engines/immortal/room.h index df968d68c4e0..0f26e364f2cb 100644 --- a/engines/immortal/room.h +++ b/engines/immortal/room.h @@ -204,7 +204,7 @@ class Room { bool roomLighted(); void lightTorch(uint8 x, uint8 y); void flameFreeAll(); - void flameSetRoom(Common::Array); + void flameSetRoom(Common::Array &allFlames); int flameGetCyc(Flame *f, int first); /* From 4116c881e628a2e9b405f959cb9b4353be6d27d5 Mon Sep 17 00:00:00 2001 From: Quote58 Date: Tue, 31 Jan 2023 18:47:08 -0500 Subject: [PATCH 372/412] IMMORTAL: Change loadPalette to use readUint16LE() instead of read() --- engines/immortal/kernal.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/engines/immortal/kernal.cpp b/engines/immortal/kernal.cpp index 00f0d27ed3d7..2db5382ed75d 100644 --- a/engines/immortal/kernal.cpp +++ b/engines/immortal/kernal.cpp @@ -779,13 +779,19 @@ void ImmortalEngine::loadPalette() { // The palettes are stored at a particular location in the disk, this just grabs them Common::File d; d.open("IMMORTAL.dsk"); - d.seek(kPaletteOffset); - d.read(_palDefault, 32); - d.read(_palWhite, 32); - d.read(_palBlack, 32); - d.read(_palDim, 32); + + // Each palette is stored after each other at this kPaletteOffset in the disk + uint16 *pals[4] = {_palDefault, _palWhite, _palBlack, _palDim}; + + // So we can just grab 16 colours at a time and store them to the appropriate palette + for (int p = 0; p < 4; p++) { + for (int i = 0; i < 16; i++) { + pals[p][i] = d.readUint16LE(); + } + } + // And now we are done with the file d.close(); } From 878fbe404ca5d8d56a559909a760c1b503305aa2 Mon Sep 17 00:00:00 2001 From: Quote58 Date: Tue, 31 Jan 2023 19:45:18 -0500 Subject: [PATCH 373/412] IMMORTAL: Clean up some of the header dependancies --- engines/immortal/disk.cpp | 3 --- engines/immortal/immortal.cpp | 8 ++++---- engines/immortal/immortal.h | 9 +-------- engines/immortal/level.cpp | 2 -- engines/immortal/room.h | 16 +--------------- engines/immortal/utilities.h | 5 ----- 6 files changed, 6 insertions(+), 37 deletions(-) diff --git a/engines/immortal/disk.cpp b/engines/immortal/disk.cpp index 5767aefac6c4..1e706f56f5d5 100644 --- a/engines/immortal/disk.cpp +++ b/engines/immortal/disk.cpp @@ -19,9 +19,6 @@ * */ - -#include "common/debug.h" -#include "common/file.h" #include "immortal/disk.h" namespace Immortal { diff --git a/engines/immortal/immortal.cpp b/engines/immortal/immortal.cpp index e7c5ca7913b1..90b19ca8d3a8 100644 --- a/engines/immortal/immortal.cpp +++ b/engines/immortal/immortal.cpp @@ -19,11 +19,11 @@ * */ +// common/config-manager is needed for the search manager #include "common/config-manager.h" -#include "common/system.h" +// engines/util is needed for initGraphics() #include "engines/util.h" - #include "immortal/immortal.h" namespace Immortal { @@ -108,7 +108,7 @@ Common::ErrorCode ImmortalEngine::initDisks() { if (SearchMan.hasFile("IMMORTAL.dsk")) { // Instantiate the disk as an object. The disk will then open and parse itself - ProDOSDisk *diskBoot = new ProDOSDisk("IMMORTAL.dsk"); + ProDOSDisk *diskBoot = new ProDOSDisk("IMMORTAL.dsk"); if (diskBoot) { // With the disk successfully parsed, it can be added to the search manager @@ -122,7 +122,7 @@ Common::ErrorCode ImmortalEngine::initDisks() { // Check for the gfx disk if (SearchMan.hasFile("IMMORTAL_GFX.dsk")) { - ProDOSDisk *diskGFX = new ProDOSDisk("IMMORTAL_GFX.dsk"); + ProDOSDisk *diskGFX = new ProDOSDisk("IMMORTAL_GFX.dsk"); if (diskGFX) { debug("Gfx disk found"); SearchMan.add("IMMORTAL_GFX.dsk", diskGFX, 0, true); diff --git a/engines/immortal/immortal.h b/engines/immortal/immortal.h index 2e2b520b4901..d56dfe8875bf 100644 --- a/engines/immortal/immortal.h +++ b/engines/immortal/immortal.h @@ -40,28 +40,21 @@ // Disk is only used by immortal.cpp #include "immortal/disk.h" -// Common is needed by immortal.h, room.h, and monster.h -#include "common/debug.h" #include "common/debug-channels.h" #include "common/events.h" #include "common/scummsys.h" #include "common/system.h" -#include "common/error.h" #include "common/fs.h" -#include "common/file.h" -#include "common/memstream.h" #include "common/hash-str.h" #include "common/random.h" #include "common/serializer.h" #include "common/util.h" #include "common/platform.h" -// Story is needed by both immortal.h and room.h -#include "immortal/story.h" - // Utilities.h contains many things used by all objects, not just immortal #include "immortal/utilities.h" +// Room also includes story.h #include "immortal/room.h" namespace Immortal { diff --git a/engines/immortal/level.cpp b/engines/immortal/level.cpp index 2010da59ca33..67a92b702d97 100644 --- a/engines/immortal/level.cpp +++ b/engines/immortal/level.cpp @@ -24,8 +24,6 @@ namespace Immortal { -struct Flame; - void ImmortalEngine::levelInitAtStartOfGameOnly() { initStoryDynamic(); _lastLevelLoaded = -1; diff --git a/engines/immortal/room.h b/engines/immortal/room.h index 0f26e364f2cb..b6bf67833e73 100644 --- a/engines/immortal/room.h +++ b/engines/immortal/room.h @@ -23,28 +23,14 @@ * */ -// Common is needed by immortal.h, room.h, and monster.h -#include "common/debug.h" -#include "common/debug-channels.h" -#include "common/events.h" -#include "common/scummsys.h" +// Common/system includes basic things like Array #include "common/system.h" -#include "common/error.h" -#include "common/fs.h" -#include "common/file.h" -#include "common/memstream.h" -#include "common/hash-str.h" -#include "common/random.h" -#include "common/serializer.h" -#include "common/util.h" -#include "common/platform.h" // Story is needed by both immortal.h and room.h #include "immortal/story.h" // Utilities.h contains many things used by all objects, not just immortal #include "immortal/utilities.h" - #include "immortal/immortal.h" #ifndef IMMORTAL_ROOM_H diff --git a/engines/immortal/utilities.h b/engines/immortal/utilities.h index d1a1fcd064ff..79e76efebf1a 100644 --- a/engines/immortal/utilities.h +++ b/engines/immortal/utilities.h @@ -22,13 +22,8 @@ #ifndef IMMORTAL_UTIL_H #define IMMORTAL_UTIL_H -#include "common/debug.h" -#include "common/debug-channels.h" #include "common/system.h" -#include "immortal/sprite_list.h" -#include "immortal/definitions.h" - namespace Immortal { enum BitMask16 : uint16 { From cae5e1cadd4f26c73b4f66f1f10f286acbc2ebf3 Mon Sep 17 00:00:00 2001 From: Eugene Sandulenko Date: Sun, 5 Feb 2023 22:04:44 +0100 Subject: [PATCH 374/412] JANITORIAL: Fix namespace comments --- engines/immortal/bullet.cpp | 2 +- engines/immortal/compression.cpp | 2 +- engines/immortal/definitions.h | 2 +- engines/immortal/door.cpp | 2 +- engines/immortal/drawChr.cpp | 2 +- engines/immortal/flameSet.cpp | 2 +- engines/immortal/level.cpp | 2 +- engines/immortal/room.cpp | 2 +- engines/immortal/room.h | 2 +- engines/immortal/sprite_list.h | 2 +- engines/immortal/story.h | 2 +- engines/immortal/univ.cpp | 2 +- engines/immortal/utilities.h | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/engines/immortal/bullet.cpp b/engines/immortal/bullet.cpp index e17e84c29f12..f6d225d29f60 100644 --- a/engines/immortal/bullet.cpp +++ b/engines/immortal/bullet.cpp @@ -29,4 +29,4 @@ namespace Immortal { -} // namespace immortal +} // namespace Immortal diff --git a/engines/immortal/compression.cpp b/engines/immortal/compression.cpp index 08d7055149e0..11ecaf951527 100644 --- a/engines/immortal/compression.cpp +++ b/engines/immortal/compression.cpp @@ -258,4 +258,4 @@ void ImmortalEngine::appendList(uint16 codeW, uint16 k, uint16 &hash, uint16 &fi } } -} // namespace immortal +} // namespace Immortal diff --git a/engines/immortal/definitions.h b/engines/immortal/definitions.h index d19c3debad6e..510b6cf03675 100644 --- a/engines/immortal/definitions.h +++ b/engines/immortal/definitions.h @@ -235,6 +235,6 @@ enum SObjType { }; -} // namespace immortal +} // namespace Immortal #endif diff --git a/engines/immortal/door.cpp b/engines/immortal/door.cpp index 187268dab316..f2b99d94efdb 100644 --- a/engines/immortal/door.cpp +++ b/engines/immortal/door.cpp @@ -127,4 +127,4 @@ void ImmortalEngine::doorCloseSecret() {} void ImmortalEngine::doorInit() {} void ImmortalEngine::doorClrLock() {} -} // namespace immortal +} // namespace Immortal diff --git a/engines/immortal/drawChr.cpp b/engines/immortal/drawChr.cpp index b898849b113c..5f8e4e8dff93 100644 --- a/engines/immortal/drawChr.cpp +++ b/engines/immortal/drawChr.cpp @@ -43,4 +43,4 @@ void ImmortalEngine::drawURHC(int chr, int x, int y) {} void ImmortalEngine::drawLLHC(int chr, int x, int y) {} void ImmortalEngine::drawLRHC(int chr, int x, int y) {} -} // namespace immortal +} // namespace Immortal diff --git a/engines/immortal/flameSet.cpp b/engines/immortal/flameSet.cpp index a5f487448815..8bb4ec3abce6 100644 --- a/engines/immortal/flameSet.cpp +++ b/engines/immortal/flameSet.cpp @@ -148,4 +148,4 @@ int Room::flameGetCyc(Flame *f, int first) { } } -} // namespace immortal +} // namespace Immortal diff --git a/engines/immortal/level.cpp b/engines/immortal/level.cpp index 67a92b702d97..1fa299e72ae6 100644 --- a/engines/immortal/level.cpp +++ b/engines/immortal/level.cpp @@ -153,4 +153,4 @@ bool ImmortalEngine::levelIsShowRoom(int r) { return false; } -} // namespace immortal +} // namespace Immortal diff --git a/engines/immortal/room.cpp b/engines/immortal/room.cpp index 47de77211fb2..da508ec87316 100644 --- a/engines/immortal/room.cpp +++ b/engines/immortal/room.cpp @@ -85,4 +85,4 @@ bool Room::getWallNormal(uint8 x, uint8 y, uint8 xPrev, uint8 yPrev, int id) { return true; } -} // namespace immortal +} // namespace Immortal diff --git a/engines/immortal/room.h b/engines/immortal/room.h index b6bf67833e73..4a0552598246 100644 --- a/engines/immortal/room.h +++ b/engines/immortal/room.h @@ -211,6 +211,6 @@ class Room { void univAddSprite(uint16 vX, uint16 vY, uint16 x, uint16 y, SpriteName s, int img, uint16 p); }; -} // namespace immortal +} // namespace Immortal #endif diff --git a/engines/immortal/sprite_list.h b/engines/immortal/sprite_list.h index e301a5089ac0..686020474aa8 100644 --- a/engines/immortal/sprite_list.h +++ b/engines/immortal/sprite_list.h @@ -294,6 +294,6 @@ enum SpriteName { kFont }; -} // namespace immortal +} // namespace Immortal #endif diff --git a/engines/immortal/story.h b/engines/immortal/story.h index b3cfd1732aa4..edce41f81610 100644 --- a/engines/immortal/story.h +++ b/engines/immortal/story.h @@ -254,6 +254,6 @@ struct Story { CArray2D _monsters; }; -} // namespace immortal +} // namespace Immortal #endif diff --git a/engines/immortal/univ.cpp b/engines/immortal/univ.cpp index 9458d645f1e7..3b8fbd2c7d87 100644 --- a/engines/immortal/univ.cpp +++ b/engines/immortal/univ.cpp @@ -28,4 +28,4 @@ void Room::univAddSprite(uint16 vX, uint16 vY, uint16 x, uint16 y, SpriteName s, //g_immortal->addSprite(vX, vY, s, img, x, y, p); } -} // namespace immortal +} // namespace Immortal diff --git a/engines/immortal/utilities.h b/engines/immortal/utilities.h index 79e76efebf1a..1bfbfcbe25c4 100644 --- a/engines/immortal/utilities.h +++ b/engines/immortal/utilities.h @@ -79,7 +79,7 @@ void delay8(int j); // || /8 bool inside(uint8 dist, uint8 centX, uint8 centY, uint8 pointX, uint8 pointY); bool insideRect(uint8 rectX, uint8 rectY, uint8 w, uint8 h, uint8 pointX, uint8 pointY); -}; // namespace Util +}; // namespace Utilities }; // namespace Immortal From 1e9ee2777bcb4e147a9712e283ceacd14e11b3c9 Mon Sep 17 00:00:00 2001 From: Eugene Sandulenko Date: Sun, 5 Feb 2023 22:06:40 +0100 Subject: [PATCH 375/412] IMMORTAL: Sort files alphabetically in module.mk --- engines/immortal/module.mk | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/engines/immortal/module.mk b/engines/immortal/module.mk index 3d98cfe27292..54038fbe0a05 100644 --- a/engines/immortal/module.mk +++ b/engines/immortal/module.mk @@ -1,24 +1,24 @@ MODULE := engines/immortal MODULE_OBJS = \ - metaengine.o \ - utilities.o \ + bullet.o \ + compression.o \ + cycle.o \ + door.o \ disk.o \ + drawChr.o \ + flameSet.o \ immortal.o \ kernal.o \ + level.o \ logic.o \ - sprites.o \ - compression.o \ + metaengine.o \ misc.o \ - cycle.o \ - drawChr.o \ - level.o \ - story.o \ room.o \ - flameSet.o \ - univ.o \ - door.o \ - bullet.o + sprites.o \ + story.o \ + utilities.o \ + univ.o # object.o \ # monster.o \ From db0495af5ac8e85f5dc78004c8624288b451430c Mon Sep 17 00:00:00 2001 From: Eugene Sandulenko Date: Sun, 5 Feb 2023 22:08:09 +0100 Subject: [PATCH 376/412] IMMORTAL: Remove redundant includes --- engines/immortal/detection.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/engines/immortal/detection.cpp b/engines/immortal/detection.cpp index ce19d7f2b7d1..a071b6448fa6 100644 --- a/engines/immortal/detection.cpp +++ b/engines/immortal/detection.cpp @@ -23,14 +23,6 @@ #include "engines/advancedDetector.h" #include "immortal/immortal.h" -#include "common/config-manager.h" -#include "common/file.h" -#include "common/md5.h" -#include "common/str-array.h" -#include "common/translation.h" -#include "common/util.h" - -#include "immortal/detection.h" #include "immortal/detection_tables.h" ImmortalMetaEngineDetection::ImmortalMetaEngineDetection() : AdvancedMetaEngineDetection(Immortal::gameDescriptions, From 10e69c7509902efea98ae779b803567c0a05ee1b Mon Sep 17 00:00:00 2001 From: eientei95 Date: Sun, 29 Jan 2023 19:26:43 +1300 Subject: [PATCH 377/412] MACOS: Fix warning about CFBundleTypeRole When run from terminal, it'd spit out `NSDocumentController Info.plist warning: The values of CFBundleTypeRole entries must be 'Editor', 'Viewer', 'None', or 'Shell'.` This silences that warning. --- dists/macosx/Info.plist | 2 ++ dists/macosx/Info.plist.in | 2 ++ 2 files changed, 4 insertions(+) diff --git a/dists/macosx/Info.plist b/dists/macosx/Info.plist index 3890500dffa4..61d28f1d9847 100644 --- a/dists/macosx/Info.plist +++ b/dists/macosx/Info.plist @@ -11,6 +11,8 @@ CFBundleTypeName All Files + CFBundleTypeRole + Viewer LSHandlerRank Alternate LSItemContentTypes diff --git a/dists/macosx/Info.plist.in b/dists/macosx/Info.plist.in index 01193a752add..7021acfd7055 100644 --- a/dists/macosx/Info.plist.in +++ b/dists/macosx/Info.plist.in @@ -11,6 +11,8 @@ CFBundleTypeName All Files + CFBundleTypeRole + Viewer LSHandlerRank Alternate LSItemContentTypes From 58e96a8755b536307ebd7c79f15c7bfc4bfbf769 Mon Sep 17 00:00:00 2001 From: Cameron Cawley Date: Mon, 30 Jan 2023 22:42:13 +0000 Subject: [PATCH 378/412] OPENGL: Check if GL_TEXTURE_MAX_LEVEL is supported before using it --- engines/stark/gfx/opengltexture.cpp | 10 ++++------ graphics/opengl/context.cpp | 8 +++++++- graphics/opengl/context.h | 3 +++ graphics/opengl/system_headers.h | 4 ++++ 4 files changed, 18 insertions(+), 7 deletions(-) diff --git a/engines/stark/gfx/opengltexture.cpp b/engines/stark/gfx/opengltexture.cpp index 2f00a2835513..ab097324923c 100644 --- a/engines/stark/gfx/opengltexture.cpp +++ b/engines/stark/gfx/opengltexture.cpp @@ -73,17 +73,15 @@ void OpenGlTexture::setLevelCount(uint32 count) { _levelCount = count; if (count >= 1) { -#if !USE_FORCED_GLES2 - // GLES2 does not allow setting the max provided mipmap level. + // GLES1 and GLES2 do not allow setting the max provided mipmap level. // It expects all the levels to be provided, which is not the case in TLJ. - // FIXME: Enable mipmapping on GLES2 - if (OpenGLContext.type != OpenGL::kContextGLES2) { + // FIXME: Enable mipmapping on GLES without this extension + if (OpenGLContext.textureMaxLevelSupported) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, count - 1); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } -#endif glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT); @@ -93,7 +91,7 @@ void OpenGlTexture::setLevelCount(uint32 count) { void OpenGlTexture::addLevel(uint32 level, const Graphics::Surface *surface, const byte *palette) { assert(level < _levelCount); - if (level == 0 || OpenGLContext.type != OpenGL::kContextGLES2) { + if (level == 0 || OpenGLContext.textureMaxLevelSupported) { updateLevel(level, surface, palette); } } diff --git a/graphics/opengl/context.cpp b/graphics/opengl/context.cpp index 91ba6e020369..f66b8227d808 100644 --- a/graphics/opengl/context.cpp +++ b/graphics/opengl/context.cpp @@ -71,6 +71,7 @@ void Context::reset() { textureEdgeClampSupported = false; textureBorderClampSupported = false; textureMirrorRepeatSupported = false; + textureMaxLevelSupported = false; } void Context::initialize(ContextType contextType) { @@ -186,6 +187,8 @@ void Context::initialize(ContextType contextType) { textureBorderClampSupported = true; } else if (token == "GL_ARB_texture_mirrored_repeat") { textureMirrorRepeatSupported = true; + } else if (token == "GL_SGIS_texture_lod" || token == "GL_APPLE_texture_max_level") { + textureMaxLevelSupported = true; } } @@ -219,6 +222,7 @@ void Context::initialize(ContextType contextType) { textureEdgeClampSupported = true; // No border clamping in GLES2 textureMirrorRepeatSupported = true; + // TODO: textureMaxLevelSupported with GLES3 debug(5, "OpenGL: GLES2 context initialized"); } else if (type == kContextGLES) { // GLES doesn't support shaders natively @@ -264,10 +268,11 @@ void Context::initialize(ContextType contextType) { glGetIntegerv(GL_MAX_SAMPLES, (GLint *)&multisampleMaxSamples); } - // OpenGL 1.2 and later always has packed pixels and texture edge clamp support + // OpenGL 1.2 and later always has packed pixels, texture edge clamp and texture max level support if (isGLVersionOrHigher(1, 2)) { packedPixelsSupported = true; textureEdgeClampSupported = true; + textureMaxLevelSupported = true; } // OpenGL 1.3 adds texture border clamp support if (isGLVersionOrHigher(1, 3)) { @@ -302,6 +307,7 @@ void Context::initialize(ContextType contextType) { debug(5, "OpenGL: Unpack subimage support: %d", unpackSubImageSupported); debug(5, "OpenGL: OpenGL ES depth 24 support: %d", OESDepth24); debug(5, "OpenGL: Texture edge clamping support: %d", textureEdgeClampSupported); + debug(5, "OpenGL: Texture max level support: %d", textureMaxLevelSupported); } int Context::getGLSLVersion() const { diff --git a/graphics/opengl/context.h b/graphics/opengl/context.h index 4ca34f9879c8..925ff0607fc4 100644 --- a/graphics/opengl/context.h +++ b/graphics/opengl/context.h @@ -117,6 +117,9 @@ class Context : public Common::Singleton { /** Whether texture coordinate mirrored repeat is available or not. */ bool textureMirrorRepeatSupported; + /** Whether texture max level is available or not. */ + bool textureMaxLevelSupported; + private: /** * Returns the native GLSL version supported by the driver. diff --git a/graphics/opengl/system_headers.h b/graphics/opengl/system_headers.h index 4f8b8d1722b1..f26fc141b5f1 100644 --- a/graphics/opengl/system_headers.h +++ b/graphics/opengl/system_headers.h @@ -99,4 +99,8 @@ #endif #endif +#if !defined(GL_TEXTURE_MAX_LEVEL) && defined(GL_TEXTURE_MAX_LEVEL_APPLE) + #define GL_TEXTURE_MAX_LEVEL GL_TEXTURE_MAX_LEVEL_APPLE +#endif + #endif From 17c5a0ce44dbb0062f8acc5c664762ef04eb9ad0 Mon Sep 17 00:00:00 2001 From: Vladimir Serbinenko Date: Mon, 23 Jan 2023 11:37:19 +0100 Subject: [PATCH 379/412] SDL: Don't use SDLK_UNDO prior to its introduction in SDL-1.2.3 --- backends/events/sdl/sdl-events.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/backends/events/sdl/sdl-events.cpp b/backends/events/sdl/sdl-events.cpp index 5d702698ee8e..11a8f6849d64 100644 --- a/backends/events/sdl/sdl-events.cpp +++ b/backends/events/sdl/sdl-events.cpp @@ -318,7 +318,9 @@ Common::KeyCode SdlEventSource::SDLToOSystemKeycode(const SDL_Keycode key) { case SDLK_SYSREQ: return Common::KEYCODE_SYSREQ; case SDLK_MENU: return Common::KEYCODE_MENU; case SDLK_POWER: return Common::KEYCODE_POWER; +#if SDL_VERSION_ATLEAST(1, 2, 3) case SDLK_UNDO: return Common::KEYCODE_UNDO; +#endif #if SDL_VERSION_ATLEAST(2, 0, 0) case SDLK_SCROLLLOCK: return Common::KEYCODE_SCROLLOCK; case SDLK_NUMLOCKCLEAR: return Common::KEYCODE_NUMLOCK; From 8a77ad45c3240f118f9cf4ffbb348db1d0bff024 Mon Sep 17 00:00:00 2001 From: Vladimir Serbinenko Date: Mon, 23 Jan 2023 11:41:21 +0100 Subject: [PATCH 380/412] SDL: Stub for Kolibri OS resolution --- backends/platform/sdl/sdl-window.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/backends/platform/sdl/sdl-window.cpp b/backends/platform/sdl/sdl-window.cpp index 07264cf120a8..e9f78cc19e64 100644 --- a/backends/platform/sdl/sdl-window.cpp +++ b/backends/platform/sdl/sdl-window.cpp @@ -51,6 +51,9 @@ SdlWindow::SdlWindow() : #elif defined(MAEMO) // All supported Maemo devices have a display resolution of 800x480 _desktopRes = Common::Rect(800, 480); +#elif defined(KOLIBRIOS) + // TODO: Use kolibriOS call to determine this. + _desktopRes = Common::Rect(640, 480); #else #error Unable to detect screen resolution #endif From 3a3da1b41e87cec8c86ca217fe50565faaf553fd Mon Sep 17 00:00:00 2001 From: Vladimir Serbinenko Date: Mon, 23 Jan 2023 11:38:48 +0100 Subject: [PATCH 381/412] SDL: Allow joystick init to fail It's not critical so can be skipped --- backends/events/sdl/sdl-events.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/backends/events/sdl/sdl-events.cpp b/backends/events/sdl/sdl-events.cpp index 11a8f6849d64..e69f694ecaae 100644 --- a/backends/events/sdl/sdl-events.cpp +++ b/backends/events/sdl/sdl-events.cpp @@ -81,12 +81,14 @@ SdlEventSource::SdlEventSource() if (joystick_num >= 0) { // Initialize SDL joystick subsystem if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) == -1) { - error("Could not initialize SDL: %s", SDL_GetError()); + warning("Could not initialize SDL joystick: %s", SDL_GetError()); + return; } #if SDL_VERSION_ATLEAST(2, 0, 0) if (SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) == -1) { - error("Could not initialize SDL: %s", SDL_GetError()); + warning("Could not initialize SDL game controller: %s", SDL_GetError()); + return; } loadGameControllerMappingFile(); #endif From 4bcd4671ab0345c09878f5aa88154c4d946ab8cb Mon Sep 17 00:00:00 2001 From: Vladimir Serbinenko Date: Mon, 23 Jan 2023 22:36:44 +0100 Subject: [PATCH 382/412] KOLIBRI: Add kolibrios backend --- .../fs/kolibrios/kolibrios-fs-factory.cpp | 48 +++ backends/fs/kolibrios/kolibrios-fs-factory.h | 39 +++ backends/fs/kolibrios/kolibrios-fs.cpp | 302 ++++++++++++++++++ backends/fs/kolibrios/kolibrios-fs.h | 93 ++++++ backends/module.mk | 24 +- .../platform/sdl/kolibrios/kolibrios-main.cpp | 48 +++ backends/platform/sdl/kolibrios/kolibrios.cpp | 117 +++++++ backends/platform/sdl/kolibrios/kolibrios.h | 52 +++ backends/platform/sdl/kolibrios/sdl-stubs.cpp | 58 ++++ backends/platform/sdl/module.mk | 7 + .../plugins/kolibrios/kolibrios-provider.cpp | 88 +++++ .../plugins/kolibrios/kolibrios-provider.h | 37 +++ backends/plugins/sdl/sdl-provider.cpp | 2 +- backends/saves/kolibrios/kolibrios-saves.cpp | 74 +++++ backends/saves/kolibrios/kolibrios-saves.h | 40 +++ graphics/scaler/hq.cpp | 2 +- 16 files changed, 1028 insertions(+), 3 deletions(-) create mode 100644 backends/fs/kolibrios/kolibrios-fs-factory.cpp create mode 100644 backends/fs/kolibrios/kolibrios-fs-factory.h create mode 100644 backends/fs/kolibrios/kolibrios-fs.cpp create mode 100644 backends/fs/kolibrios/kolibrios-fs.h create mode 100644 backends/platform/sdl/kolibrios/kolibrios-main.cpp create mode 100644 backends/platform/sdl/kolibrios/kolibrios.cpp create mode 100644 backends/platform/sdl/kolibrios/kolibrios.h create mode 100644 backends/platform/sdl/kolibrios/sdl-stubs.cpp create mode 100644 backends/plugins/kolibrios/kolibrios-provider.cpp create mode 100644 backends/plugins/kolibrios/kolibrios-provider.h create mode 100644 backends/saves/kolibrios/kolibrios-saves.cpp create mode 100644 backends/saves/kolibrios/kolibrios-saves.h diff --git a/backends/fs/kolibrios/kolibrios-fs-factory.cpp b/backends/fs/kolibrios/kolibrios-fs-factory.cpp new file mode 100644 index 000000000000..51f06268a751 --- /dev/null +++ b/backends/fs/kolibrios/kolibrios-fs-factory.cpp @@ -0,0 +1,48 @@ +/* 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 . + * + */ + +// Re-enable some forbidden symbols to avoid clashes with stat.h and unistd.h. +// Also with clock() in sys/time.h in some macOS SDKs. +#define FORBIDDEN_SYMBOL_EXCEPTION_time_h +#define FORBIDDEN_SYMBOL_EXCEPTION_unistd_h +#define FORBIDDEN_SYMBOL_EXCEPTION_mkdir +#define FORBIDDEN_SYMBOL_EXCEPTION_exit //Needed for IRIX's unistd.h +#define FORBIDDEN_SYMBOL_EXCEPTION_random +#define FORBIDDEN_SYMBOL_EXCEPTION_srandom + +#include "backends/fs/kolibrios/kolibrios-fs-factory.h" +#include "backends/fs/kolibrios/kolibrios-fs.h" + +#include + +AbstractFSNode *KolibriOSFilesystemFactory::makeRootFileNode() const { + return new KolibriOSFilesystemNode("/"); +} + +AbstractFSNode *KolibriOSFilesystemFactory::makeCurrentDirectoryFileNode() const { + char buf[MAXPATHLEN]; + return getcwd(buf, MAXPATHLEN) ? new KolibriOSFilesystemNode(buf) : NULL; +} + +AbstractFSNode *KolibriOSFilesystemFactory::makeFileNodePath(const Common::String &path) const { + assert(!path.empty()); + return new KolibriOSFilesystemNode(path); +} diff --git a/backends/fs/kolibrios/kolibrios-fs-factory.h b/backends/fs/kolibrios/kolibrios-fs-factory.h new file mode 100644 index 000000000000..d226450505ca --- /dev/null +++ b/backends/fs/kolibrios/kolibrios-fs-factory.h @@ -0,0 +1,39 @@ +/* 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 . + * + */ + +#ifndef KOLIBRIOS_FILESYSTEM_FACTORY_H +#define KOLIBRIOS_FILESYSTEM_FACTORY_H + +#include "backends/fs/fs-factory.h" + +/** + * Creates KolibriOSFilesystemNode objects. + * + * Parts of this class are documented in the base interface class, FilesystemFactory. + */ +class KolibriOSFilesystemFactory : public FilesystemFactory { +protected: + AbstractFSNode *makeRootFileNode() const override; + AbstractFSNode *makeCurrentDirectoryFileNode() const override; + AbstractFSNode *makeFileNodePath(const Common::String &path) const override; +}; + +#endif /*KOLIBRIOS_FILESYSTEM_FACTORY_H*/ diff --git a/backends/fs/kolibrios/kolibrios-fs.cpp b/backends/fs/kolibrios/kolibrios-fs.cpp new file mode 100644 index 000000000000..b1bf8184f55f --- /dev/null +++ b/backends/fs/kolibrios/kolibrios-fs.cpp @@ -0,0 +1,302 @@ +/* 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 . + * + */ + +#define FORBIDDEN_SYMBOL_EXCEPTION_time_h +#define FORBIDDEN_SYMBOL_EXCEPTION_unistd_h +#define FORBIDDEN_SYMBOL_EXCEPTION_mkdir +#define FORBIDDEN_SYMBOL_EXCEPTION_getenv + +#include "backends/fs/kolibrios/kolibrios-fs.h" +#include "backends/fs/posix/posix-iostream.h" +#include "common/algorithm.h" +#include "common/debug.h" + +#include +#include +#include +#include +#include +#include + +#include "common/pack-start.h" // START STRUCT PACKING + +struct kol_readdir_result_header { + uint32 version; + uint32 number_of_placed_blocks; + uint32 total_number_of_blocks; + byte reserved[20]; +} PACKED_STRUCT; + +struct kol_readdir_result_entry { + ksys_bdfe_t bdfe; + char fileName[520]; +} PACKED_STRUCT; + +struct kol_readdir_result { + kol_readdir_result_header header; + kol_readdir_result_entry entries[0]; +} PACKED_STRUCT; + +#include "common/pack-end.h" // END STRUCT PACKING + +namespace { + +// opendir/readdir are buggy. And they encourage using syscalls. Whatever +kol_readdir_result *kol_readdir(const char *path, uint32 max_blocks) { + ksys70_status_t ret_result; + int result_buffer_size = sizeof (kol_readdir_result_header) + + max_blocks * sizeof (kol_readdir_result_entry); + kol_readdir_result *result_buffer = (kol_readdir_result *) malloc (result_buffer_size); + if (!result_buffer) + return nullptr; + memset(result_buffer, 0, result_buffer_size); + ksys70_t request; + request.p00 = 1; // Read directory + request.p04dw = 0; + request.p08dw = 3; // UTF-8 + request.p12 = max_blocks; + request.buf16 = result_buffer; + request.p20 = 0; // Don't use inline path + request.p21 = path; + + ret_result = _ksys70(&request); + + // 0 is returned for normal dirs, 6 for virtual directories + if (ret_result.status != 0 && ret_result.status != 6) { + free (result_buffer); + return nullptr; + } + + return result_buffer; +} + +kol_readdir_result *kol_readdir(const char *path) { + kol_readdir_result *res = kol_readdir(path, 2); + + if (!res) + return nullptr; + + uint32 tot_blocks = res->header.total_number_of_blocks; + free(res); + + return kol_readdir(path, tot_blocks); +} + +bool getFileAttrs(Common::String path, uint32& attrs) { + fileinfo_t info; + + memset(&info, 0, sizeof(info)); + info.attr = 0x10; + if(get_fileinfo(path.c_str(), &info)) { + attrs = 0; + return false; + } + + attrs = info.attr; + return true; +} + +} // namespace + +bool KolibriOSFilesystemNode::exists() const { + uint32 attrs; + return getFileAttrs(_path, attrs); +} + +bool KolibriOSFilesystemNode::isReadable() const { + uint32 attrs; + return getFileAttrs(_path, attrs); +} + +bool KolibriOSFilesystemNode::isWritable() const { + uint32 attrs; + return getFileAttrs(_path, attrs) && !(attrs & 0x01); +} + +void KolibriOSFilesystemNode::setFlags() { + _isValid = getFileAttrs(_path, _attributes); +} + +KolibriOSFilesystemNode::KolibriOSFilesystemNode(const Common::String &p) { + assert(p.size() > 0); + + _path = p; + + // Normalize the path (that is, remove unneeded slashes etc.) + _path = Common::normalizePath(_path, '/'); + _displayName = Common::lastPathComponent(_path, '/'); + + setFlags(); +} + +AbstractFSNode *KolibriOSFilesystemNode::getChild(const Common::String &n) const { + assert(!_path.empty()); + assert(isDirectory()); + + // Make sure the string contains no slashes + assert(!n.contains('/')); + + // We assume here that _path is already normalized (hence don't bother to call + // Common::normalizePath on the final path). + Common::String newPath(_path); + if (_path.lastChar() != '/') + newPath += '/'; + newPath += n; + + return makeNode(newPath); +} + +bool KolibriOSFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, bool hidden) const { + kol_readdir_result *res = kol_readdir(_path.c_str()); + + if (!res) + return false; + + for (int i = 0; i < (int) res->header.number_of_placed_blocks; i++) + { + // Skip 'invisible' files if necessary + if (res->entries[i].fileName[0] == '.' && !hidden) { + continue; + } + // Skip '.' and '..' to avoid cycles + if ((res->entries[i].fileName[0] == '.' && res->entries[i].fileName[1] == 0) + || (res->entries[i].fileName[0] == '.' && res->entries[i].fileName[1] == '.' && res->entries[i].fileName[2] == 0)) { + continue; + } + + // Start with a clone of this node, with the correct path set + KolibriOSFilesystemNode entry(*this); + entry._displayName = res->entries[i].fileName; + if (_path.lastChar() != '/') + entry._path += '/'; + entry._path += entry._displayName; + + entry._isValid = true; + entry._attributes = res->entries[i].bdfe.attributes; + + // Honor the chosen mode + if ((mode == Common::FSNode::kListFilesOnly && entry.isDirectory()) || + (mode == Common::FSNode::kListDirectoriesOnly && !entry.isDirectory())) + continue; + + myList.push_back(new KolibriOSFilesystemNode(entry)); + + } + + free(res); + + return true; +} + +AbstractFSNode *KolibriOSFilesystemNode::getParent() const { + if (_path == "/") + return 0; // The filesystem root has no parent + + const char *start = _path.c_str(); + const char *end = start + _path.size(); + + // Strip of the last component. We make use of the fact that at this + // point, _path is guaranteed to be normalized + while (end > start && *(end-1) != '/') + end--; + + if (end == start) { + // This only happens if we were called with a relative path, for which + // there simply is no parent. + // TODO: We could also resolve this by assuming that the parent is the + // current working directory, and returning a node referring to that. + return 0; + } + + return makeNode(Common::String(start, end)); +} + +Common::SeekableReadStream *KolibriOSFilesystemNode::createReadStream() { + return PosixIoStream::makeFromPath(getPath(), false); +} + +Common::SeekableWriteStream *KolibriOSFilesystemNode::createWriteStream() { + return PosixIoStream::makeFromPath(getPath(), true); +} + +bool KolibriOSFilesystemNode::createDirectory() { + if (mkdir(_path.c_str(), 0755) == 0) + setFlags(); + + return isDirectory(); +} + +namespace KolibriOS { + +bool assureDirectoryExists(const Common::String &dir, const char *prefix) { + + // Check whether the prefix exists if one is supplied. + if (prefix) { + uint32 attrs; + if (!getFileAttrs(prefix, attrs) || !KolibriOSFilesystemNode::isDirectory(attrs)) { + return false; + } + } + + // Obtain absolute path. + Common::String path; + if (prefix) { + path = prefix; + path += '/'; + path += dir; + } else { + path = dir; + } + + path = Common::normalizePath(path, '/'); + + const Common::String::iterator end = path.end(); + Common::String::iterator cur = path.begin(); + if (cur[0] == '/' && cur[1] >= 1 && cur[1] <= 3 && cur[2] == '/') + cur += 2; + if (*cur == '/') + ++cur; + + do { + if (cur + 1 != end) { + if (*cur != '/') { + continue; + } + + // It is kind of ugly and against the purpose of Common::String to + // insert 0s inside, but this is just for a local string and + // simplifies the code a lot. + *cur = '\0'; + } + + if (mkdir(path.c_str(), 0755) != 0) { + uint32 attrs; + if (!getFileAttrs(path, attrs) || !KolibriOSFilesystemNode::isDirectory(attrs)) + return false; + } + + *cur = '/'; + } while (cur++ != end); + + return true; +} + +} // End of namespace KolibriOS diff --git a/backends/fs/kolibrios/kolibrios-fs.h b/backends/fs/kolibrios/kolibrios-fs.h new file mode 100644 index 000000000000..ffa6fd75f45b --- /dev/null +++ b/backends/fs/kolibrios/kolibrios-fs.h @@ -0,0 +1,93 @@ +/* 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 . + * + */ + +#ifndef KOLIBRIOS_FS_H +#define KOLIBRIOS_FS_H + +#include "backends/fs/abstract-fs.h" + +/** + * Implementation of the ScummVM file system API based on KolibriOS. + * + * Parts of this class are documented in the base interface class, AbstractFSNode. + */ +class KolibriOSFilesystemNode : public AbstractFSNode { +public: + /** + * Creates a KolibriOSFilesystemNode for a given path. + * + * @param path the path the new node should point to. + */ + KolibriOSFilesystemNode(const Common::String &path); + + bool exists() const override; + Common::U32String getDisplayName() const override { return _displayName; } + Common::String getName() const override { return _displayName; } + Common::String getPath() const override { return _path; } + static bool isDirectory(uint32 attrs) { return attrs & 0x18; } + bool isDirectory() const override { return isDirectory(_attributes); } + bool isReadable() const override; + bool isWritable() const override; + + AbstractFSNode *getChild(const Common::String &n) const override; + bool getChildren(AbstractFSList &list, ListMode mode, bool hidden) const override; + AbstractFSNode *getParent() const override; + + Common::SeekableReadStream *createReadStream() override; + Common::SeekableWriteStream *createWriteStream() override; + bool createDirectory() override; + +protected: + Common::String _displayName; + Common::String _path; + uint32 _attributes; + bool _isValid; + + virtual AbstractFSNode *makeNode(const Common::String &path) const { + return new KolibriOSFilesystemNode(path); + } + + /** + * Plain constructor, for internal use only (hence protected). + */ + KolibriOSFilesystemNode() : _attributes(0), _isValid(false) {} + + /** + * Tests and sets the _isValid and _isDirectory flags, using the stat() function. + */ + virtual void setFlags(); +}; + +namespace KolibriOS { + +/** + * Assure that a directory path exists. + * + * @param dir The path which is required to exist. + * @param prefix An (optional) prefix which should not be created if non existent. + * prefix is prepended to dir if supplied. + * @return true in case the directory exists (or was created), false otherwise. + */ +bool assureDirectoryExists(const Common::String &dir, const char *prefix = nullptr); + +} // End of namespace KolibriOS + +#endif diff --git a/backends/module.mk b/backends/module.mk index 2db8d9a113ed..aabb93103c52 100644 --- a/backends/module.mk +++ b/backends/module.mk @@ -146,9 +146,18 @@ MODULE_OBJS += \ graphics/surfacesdl/surfacesdl-graphics.o \ mixer/sdl/sdl-mixer.o \ mutex/sdl/sdl-mutex.o \ - plugins/sdl/sdl-provider.o \ timer/sdl/sdl-timer.o +ifdef KOLIBRIOS +MODULE_OBJS += plugins/kolibrios/kolibrios-provider.o +endif + +ifndef RISCOS +ifndef KOLIBRIOS +MODULE_OBJS += plugins/sdl/sdl-provider.o +endif +endif + # SDL 2 removed audio CD support ifndef USE_SDL2 MODULE_OBJS += \ @@ -174,6 +183,19 @@ MODULE_OBJS += \ endif endif +ifdef KOLIBRIOS +MODULE_OBJS += \ + fs/kolibrios/kolibrios-fs.o \ + fs/kolibrios/kolibrios-fs-factory.o \ + fs/posix/posix-iostream.o \ + fs/posix-drives/posix-drives-fs.o \ + fs/posix-drives/posix-drives-fs-factory.o \ + fs/chroot/chroot-fs-factory.o \ + fs/chroot/chroot-fs.o \ + plugins/posix/posix-provider.o \ + saves/kolibrios/kolibrios-saves.o +endif + ifdef POSIX MODULE_OBJS += \ fs/posix/posix-fs.o \ diff --git a/backends/platform/sdl/kolibrios/kolibrios-main.cpp b/backends/platform/sdl/kolibrios/kolibrios-main.cpp new file mode 100644 index 000000000000..5f363b7d4150 --- /dev/null +++ b/backends/platform/sdl/kolibrios/kolibrios-main.cpp @@ -0,0 +1,48 @@ +/* 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 . + * + */ +#define FORBIDDEN_SYMBOL_ALLOW_ALL + +#include "common/scummsys.h" + +#include "backends/platform/sdl/kolibrios/kolibrios.h" +#include "backends/plugins/kolibrios/kolibrios-provider.h" +#include "base/main.h" + +extern "C" int kolibrios_main(int argc, char *argv[]) { + // Create our OSystem instance + g_system = new OSystem_KolibriOS(argv[0]); + assert(g_system); + + // Pre initialize the backend + g_system->init(); + +#ifdef DYNAMIC_MODULES + PluginManager::instance().addPluginProvider(new KolibriOSPluginProvider()); +#endif + + // Invoke the actual ScummVM main entry point: + int res = scummvm_main(argc, argv); + + // Free OSystem + g_system->destroy(); + + return res; +} diff --git a/backends/platform/sdl/kolibrios/kolibrios.cpp b/backends/platform/sdl/kolibrios/kolibrios.cpp new file mode 100644 index 000000000000..adafa025ef33 --- /dev/null +++ b/backends/platform/sdl/kolibrios/kolibrios.cpp @@ -0,0 +1,117 @@ +/* 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 . + * + */ + +#define FORBIDDEN_SYMBOL_EXCEPTION_getenv +#define FORBIDDEN_SYMBOL_EXCEPTION_mkdir +#define FORBIDDEN_SYMBOL_EXCEPTION_exit +#define FORBIDDEN_SYMBOL_EXCEPTION_unistd_h + +#include "common/scummsys.h" + +#include "backends/audiocd/default/default-audiocd.h" +#include "backends/platform/sdl/kolibrios/kolibrios.h" +#include "backends/saves/kolibrios/kolibrios-saves.h" +#include "backends/fs/kolibrios/kolibrios-fs-factory.h" +#include "backends/fs/kolibrios/kolibrios-fs.h" + +#include "common/textconsole.h" + +#include +#include +#include + +OSystem_KolibriOS::OSystem_KolibriOS(const char *exeName) : _exeName(exeName) { +} + +void OSystem_KolibriOS::init() { + _exePath = Common::Path(_exeName).getParent(); + if (KolibriOS::assureDirectoryExists("scummvm-home", _exePath.toString().c_str())) { + debug("Using /scummvm-home"); + _writablePath = _exePath.join("scummvm-home"); + } else { + KolibriOS::assureDirectoryExists("scummvm", "/tmp0/1"); + _writablePath = "/tmp0/1/scummvm"; + debug("Using /tmp0/1"); + } + + // Initialze File System Factory + _fsFactory = new KolibriOSFilesystemFactory(); + + // Invoke parent implementation of this method + OSystem_SDL::init(); +} + +void OSystem_KolibriOS::addSysArchivesToSearchSet(Common::SearchSet &s, int priority) { + Common::FSNode dataNode(_exePath); + s.add("exePath", new Common::FSDirectory(dataNode, 4), priority); +} + +void OSystem_KolibriOS::initBackend() { + Common::String defaultThemePath = _exePath.join("themes").toString(); + Common::String defaultEngineData = _exePath.join("engine-data").toString(); + ConfMan.registerDefault("themepath", defaultThemePath); + ConfMan.registerDefault("extrapath", defaultEngineData); + + if (!ConfMan.hasKey("themepath")) { + ConfMan.set("themepath", defaultThemePath); + } + if (!ConfMan.hasKey("extrapath")) { + ConfMan.set("extrapath", defaultEngineData); + } + + // Create the savefile manager + if (_savefileManager == 0) + _savefileManager = new KolibriOSSaveFileManager(_writablePath); + + // Invoke parent implementation of this method + OSystem_SDL::initBackend(); +} + +Common::String OSystem_KolibriOS::getDefaultConfigFileName() { + return _writablePath.join("scummvm.ini").toString(); +} + +Common::String OSystem_KolibriOS::getDefaultIconsPath() { + return _exePath.join("icons").toString(); +} + +Common::String OSystem_KolibriOS::getScreenshotsPath() { + // If the user has configured a screenshots path, use it + const Common::String path = OSystem_SDL::getScreenshotsPath(); + if (!path.empty()) { + return path; + } + + static const char *SCREENSHOTS_DIR_NAME = "ScummVM Screenshots"; + if (!KolibriOS::assureDirectoryExists(SCREENSHOTS_DIR_NAME, _writablePath.toString().c_str())) { + return ""; + } + + return _writablePath.join(SCREENSHOTS_DIR_NAME).toString(); +} + +Common::String OSystem_KolibriOS::getDefaultLogFileName() { + return _writablePath.join("scummvm.log").toString(); +} + +AudioCDManager *OSystem_KolibriOS::createAudioCDManager() { + return new DefaultAudioCDManager(); +} diff --git a/backends/platform/sdl/kolibrios/kolibrios.h b/backends/platform/sdl/kolibrios/kolibrios.h new file mode 100644 index 000000000000..4a3d40564445 --- /dev/null +++ b/backends/platform/sdl/kolibrios/kolibrios.h @@ -0,0 +1,52 @@ +/* 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 . + * + */ + +#ifndef PLATFORM_SDL_KOLIBRIOS_H +#define PLATFORM_SDL_KOLIBRIOS_H + +#include "backends/platform/sdl/sdl.h" + +class OSystem_KolibriOS : public OSystem_SDL { +public: + OSystem_KolibriOS(const char *exeName); + + void init() override; + void initBackend() override; + + // Default paths + Common::String getDefaultIconsPath() override; + Common::String getScreenshotsPath() override; + void addSysArchivesToSearchSet(Common::SearchSet &s, int priority) override; + const Common::Path& getExePath() const { return _exePath; } + +protected: + Common::String getDefaultConfigFileName() override; + Common::String getDefaultLogFileName() override; + + AudioCDManager *createAudioCDManager() override; + +private: + Common::Path _exePath; + Common::Path _writablePath; + Common::String _exeName; +}; + +#endif diff --git a/backends/platform/sdl/kolibrios/sdl-stubs.cpp b/backends/platform/sdl/kolibrios/sdl-stubs.cpp new file mode 100644 index 000000000000..0c8f23f1b089 --- /dev/null +++ b/backends/platform/sdl/kolibrios/sdl-stubs.cpp @@ -0,0 +1,58 @@ +/* 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 "backends/events/sdl/sdl-events.h" + +SDL_Joystick *SDL_JoystickOpen (int index) { + return nullptr; +} + +const char *SDL_JoystickName (int index) { + return nullptr; +} + +int SDL_NumJoysticks (void) { + return 0; +} + +void SDL_JoystickClose (SDL_Joystick *joystick) { +} + +// SDL CDAudio is not used on kolibri as it's redirected away from +// in platform-specific code but since it's still linked-in it needs those stubs +CDstatus SDL_CDStatus (SDL_CD *cdrom) { + return CD_ERROR; +} + +int SDL_CDPlayTracks (SDL_CD *cdrom, int start_track, int start_frame, int ntracks, int nframes) { + return -1; +} + +int SDL_CDStop (SDL_CD *cdrom) { + return -1; +} + +SDL_CD *SDL_CDOpen (int drive) { + return nullptr; +} + +void SDL_CDClose (SDL_CD *cdrom) { +} diff --git a/backends/platform/sdl/module.mk b/backends/platform/sdl/module.mk index ca8628f6f2aa..c50955601939 100644 --- a/backends/platform/sdl/module.mk +++ b/backends/platform/sdl/module.mk @@ -4,6 +4,13 @@ MODULE_OBJS := \ sdl.o \ sdl-window.o +ifdef KOLIBRIOS +MODULE_OBJS += \ + kolibrios/kolibrios-main.o \ + kolibrios/kolibrios.o \ + kolibrios/sdl-stubs.o +endif + ifdef POSIX MODULE_OBJS += \ posix/posix-main.o \ diff --git a/backends/plugins/kolibrios/kolibrios-provider.cpp b/backends/plugins/kolibrios/kolibrios-provider.cpp new file mode 100644 index 000000000000..0327273a9488 --- /dev/null +++ b/backends/plugins/kolibrios/kolibrios-provider.cpp @@ -0,0 +1,88 @@ +/* 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 . + * + */ + +#define FORBIDDEN_SYMBOL_ALLOW_ALL +#include "common/scummsys.h" + +#if defined(DYNAMIC_MODULES) + +#include "backends/platform/sdl/kolibrios/kolibrios.h" +#include "backends/plugins/kolibrios/kolibrios-provider.h" +#include "backends/plugins/dynamic-plugin.h" + +#include "common/debug.h" + +#include +#include + +class KolibriOSPlugin final : public DynamicPlugin { +protected: + void *_dlHandle; + + VoidFunc findSymbol(const char *symbol) override { + void *func = get_proc_address(_dlHandle, symbol); + if (!func) + debug("Failed loading symbol '%s' from plugin '%s'", symbol, _filename.c_str()); + + return (void (*)())func; + } + +public: + KolibriOSPlugin(const Common::String &filename) + : DynamicPlugin(filename), _dlHandle(0) {} + + bool loadPlugin() override { + if (_dlHandle) + return true; + _dlHandle = load_library(_filename.c_str()); + + if (!_dlHandle) { + debug("Failed loading plugin '%s' (error code %d)", _filename.c_str(), errno); + return false; + } else { + debug(1, "Success loading plugin '%s', handle %p", _filename.c_str(), _dlHandle); + } + + return DynamicPlugin::loadPlugin(); + } + + void unloadPlugin() override { + DynamicPlugin::unloadPlugin(); + /* Not supported */ + } +}; + + +Plugin* KolibriOSPluginProvider::createPlugin(const Common::FSNode &node) const { + return new KolibriOSPlugin(node.getPath()); +} + +void KolibriOSPluginProvider::addCustomDirectories(Common::FSList &dirs) const { + OSystem_KolibriOS *sys = dynamic_cast(g_system); + // load_library doesn't handle relative paths correctly so remove all other paths which are relative + dirs.clear(); + if (sys) { + debug(1, "Adding path %s", sys->getExePath().join("plugins").toString().c_str()); + dirs.push_back(Common::FSNode(sys->getExePath().join("plugins"))); + } +} + +#endif // defined(DYNAMIC_MODULES) diff --git a/backends/plugins/kolibrios/kolibrios-provider.h b/backends/plugins/kolibrios/kolibrios-provider.h new file mode 100644 index 000000000000..7af3e7f43904 --- /dev/null +++ b/backends/plugins/kolibrios/kolibrios-provider.h @@ -0,0 +1,37 @@ +/* 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 . + * + */ + +#if defined(DYNAMIC_MODULES) + +#ifndef BACKENDS_PLUGINS_KOLIBRIOS_PROVIDER_H +#define BACKENDS_PLUGINS_KOLIBRIOS_PROVIDER_H + +#include "base/plugins.h" + +class KolibriOSPluginProvider : public FilePluginProvider { +public: + Plugin *createPlugin(const Common::FSNode &node) const override; + void addCustomDirectories(Common::FSList &dirs) const override; +}; + +#endif // BACKENDS_PLUGINS_KOLIBRIOS_PROVIDER_H + +#endif // defined(DYNAMIC_MODULES) diff --git a/backends/plugins/sdl/sdl-provider.cpp b/backends/plugins/sdl/sdl-provider.cpp index 7793a8b8f5b7..75c51dfe0dee 100644 --- a/backends/plugins/sdl/sdl-provider.cpp +++ b/backends/plugins/sdl/sdl-provider.cpp @@ -22,7 +22,7 @@ #include "common/scummsys.h" // RiscOS uses its own plugin provider and SDL one doesn't work -#if defined(DYNAMIC_MODULES) && defined(SDL_BACKEND) && !defined(RISCOS) +#if defined(DYNAMIC_MODULES) && defined(SDL_BACKEND) #include "backends/plugins/sdl/sdl-provider.h" #include "backends/plugins/dynamic-plugin.h" diff --git a/backends/saves/kolibrios/kolibrios-saves.cpp b/backends/saves/kolibrios/kolibrios-saves.cpp new file mode 100644 index 000000000000..34fe433293f5 --- /dev/null +++ b/backends/saves/kolibrios/kolibrios-saves.cpp @@ -0,0 +1,74 @@ +/* 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 . + * + */ + + +#define FORBIDDEN_SYMBOL_EXCEPTION_mkdir +#define FORBIDDEN_SYMBOL_EXCEPTION_getenv +#define FORBIDDEN_SYMBOL_EXCEPTION_time_h + +#include "common/scummsys.h" + +#if !defined(DISABLE_DEFAULT_SAVEFILEMANAGER) + +#include "backends/saves/kolibrios/kolibrios-saves.h" +#include "backends/fs/kolibrios/kolibrios-fs.h" + +#include "common/config-manager.h" +#include "common/savefile.h" +#include "common/textconsole.h" + +#include + +KolibriOSSaveFileManager::KolibriOSSaveFileManager(const Common::Path& writeablePath) { + // Register default savepath. + Common::String savePath; + + if (KolibriOS::assureDirectoryExists("saves", writeablePath.toString().c_str())) { + savePath = writeablePath.join("saves").toString().c_str(); + } + + if (!savePath.empty() && savePath.size() < MAXPATHLEN) { + ConfMan.registerDefault("savepath", savePath); + } + + // The user can override the savepath with the SCUMMVM_SAVEPATH + // environment variable. This is weaker than a --savepath on the + // command line, but overrides the default savepath. + // + // To ensure that the command line option (if given) has precedence, + // we only set the value in the transient domain if it is not + // yet present there. + if (!ConfMan.hasKey("savepath", Common::ConfigManager::kTransientDomain)) { + const char *dir = getenv("SCUMMVM_SAVEPATH"); + if (dir && *dir && strlen(dir) < MAXPATHLEN) { + Common::FSNode saveDir(dir); + if (!saveDir.exists()) { + warning("Ignoring non-existent SCUMMVM_SAVEPATH '%s'", dir); + } else if (!saveDir.isWritable()) { + warning("Ignoring non-writable SCUMMVM_SAVEPATH '%s'", dir); + } else { + ConfMan.set("savepath", dir, Common::ConfigManager::kTransientDomain); + } + } + } +} + +#endif diff --git a/backends/saves/kolibrios/kolibrios-saves.h b/backends/saves/kolibrios/kolibrios-saves.h new file mode 100644 index 000000000000..1e665be1639f --- /dev/null +++ b/backends/saves/kolibrios/kolibrios-saves.h @@ -0,0 +1,40 @@ +/* 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 . + * + */ + +#if !defined(BACKEND_KOLIBRIOS_SAVES_H) && !defined(DISABLE_DEFAULT_SAVEFILEMANAGER) +#define BACKEND_KOLIBRIOS_SAVES_H + +#include "backends/saves/default/default-saves.h" + +#if !defined(DISABLE_DEFAULT_SAVEFILEMANAGER) +/** + * Customization of the DefaultSaveFileManager for KolibriOS. + * The only two differences are that the default constructor sets + * up the savepath based on HOME, and that checkPath tries to + * create the savedir, if missing, via the mkdir() syscall. + */ +class KolibriOSSaveFileManager : public DefaultSaveFileManager { +public: + KolibriOSSaveFileManager(const Common::Path& writeablePath); +}; +#endif + +#endif diff --git a/graphics/scaler/hq.cpp b/graphics/scaler/hq.cpp index 9510be8598fa..479accd96354 100644 --- a/graphics/scaler/hq.cpp +++ b/graphics/scaler/hq.cpp @@ -42,7 +42,7 @@ struct hqx_parameters { extern "C" { -#if !defined(_WIN32) && !defined(MACOSX) && !defined(__OS2__) +#if !defined(_WIN32) && !defined(MACOSX) && !defined(__OS2__) && !defined(KOLIBRIOS) #define hq2x_16 _hq2x_16 #define hq3x_16 _hq3x_16 #endif From 37230e79a12208ecb8a153f311dea03c03ab4a83 Mon Sep 17 00:00:00 2001 From: Vladimir Serbinenko Date: Thu, 26 Jan 2023 05:45:23 +0100 Subject: [PATCH 383/412] KOLIBRI: Add a launch wrapper Exporting symbols from main binary is cumbersome on KolibriOS but importing from another dll is fine. So we make scummvm core into a dll and add a thin launcher for it. --- .../platform/sdl/kolibrios/wrapper-main.c | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 backends/platform/sdl/kolibrios/wrapper-main.c diff --git a/backends/platform/sdl/kolibrios/wrapper-main.c b/backends/platform/sdl/kolibrios/wrapper-main.c new file mode 100644 index 000000000000..ac5d05e96c31 --- /dev/null +++ b/backends/platform/sdl/kolibrios/wrapper-main.c @@ -0,0 +1,56 @@ +/* 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 +#include + +/* This is just a small wrapper so that the main scummvm is loaded as dll. */ +int kolibrios_main(int argc, char *argv[]); + +int main(int argc, char *argv[]) { + printf("Loading SCUMMVM\n"); + if (argc < 1 || strnlen(argv[0], 3005) > 3000) { + fprintf(stderr, "Couldn't determine exe path"); + return 1; + } + const char *r = strrchr(argv[0], '/'); + static char dllName[4000]; + int p = 0; + if (r) { + p = r - argv[0] + 1; + memcpy(dllName, argv[0], p); + } + memcpy(dllName + p, "scummvm.dll", sizeof("scummvm.dll")); + + void *dlHandle = load_library(dllName); + if (!dlHandle) { + fprintf(stderr, "Couldn't load %s", dllName); + return 2; + } + + void (*kolibrios_main) (int argc, char *argv[]) = get_proc_address(dlHandle, "kolibrios_main"); + if (!kolibrios_main) { + fprintf(stderr, "Failed to located kolibrios_main"); + return 3; + } + + kolibrios_main(argc, argv); +} From 31071d793874239ad52618e4c74e18e2558c21f4 Mon Sep 17 00:00:00 2001 From: Vladimir Serbinenko Date: Mon, 23 Jan 2023 11:41:43 +0100 Subject: [PATCH 384/412] CONFIGURE: Support for kolibri OS --- backends/module.mk | 10 +-- .../platform/sdl/kolibrios/build-kolibri.sh | 11 +++ backends/platform/sdl/kolibrios/kolibrios.mk | 35 ++++++++ .../platform/sdl/kolibrios/kolibrios.spec | 15 ++++ configure | 85 +++++++++++++++++-- 5 files changed, 142 insertions(+), 14 deletions(-) create mode 100755 backends/platform/sdl/kolibrios/build-kolibri.sh create mode 100644 backends/platform/sdl/kolibrios/kolibrios.mk create mode 100644 backends/platform/sdl/kolibrios/kolibrios.spec diff --git a/backends/module.mk b/backends/module.mk index aabb93103c52..996455f2052d 100644 --- a/backends/module.mk +++ b/backends/module.mk @@ -148,10 +148,6 @@ MODULE_OBJS += \ mutex/sdl/sdl-mutex.o \ timer/sdl/sdl-timer.o -ifdef KOLIBRIOS -MODULE_OBJS += plugins/kolibrios/kolibrios-provider.o -endif - ifndef RISCOS ifndef KOLIBRIOS MODULE_OBJS += plugins/sdl/sdl-provider.o @@ -188,11 +184,7 @@ MODULE_OBJS += \ fs/kolibrios/kolibrios-fs.o \ fs/kolibrios/kolibrios-fs-factory.o \ fs/posix/posix-iostream.o \ - fs/posix-drives/posix-drives-fs.o \ - fs/posix-drives/posix-drives-fs-factory.o \ - fs/chroot/chroot-fs-factory.o \ - fs/chroot/chroot-fs.o \ - plugins/posix/posix-provider.o \ + plugins/kolibrios/kolibrios-provider.o \ saves/kolibrios/kolibrios-saves.o endif diff --git a/backends/platform/sdl/kolibrios/build-kolibri.sh b/backends/platform/sdl/kolibrios/build-kolibri.sh new file mode 100755 index 000000000000..1a2228d5fe4a --- /dev/null +++ b/backends/platform/sdl/kolibrios/build-kolibri.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +set -e + +export KOS32_SDK_DIR=$HOME/sdk +export KOS32_AUTOBUILD=$HOME/autobuild + +# Use plugins for both engines and detection as KolibriOS has a limit per executable module +./configure --host=kos32 --enable-release --enable-plugins --default-dynamic --enable-detection-dynamic --enable-engine=testbed + +make -j5 all zip-root scummvm-zip diff --git a/backends/platform/sdl/kolibrios/kolibrios.mk b/backends/platform/sdl/kolibrios/kolibrios.mk new file mode 100644 index 000000000000..6de4096498a6 --- /dev/null +++ b/backends/platform/sdl/kolibrios/kolibrios.mk @@ -0,0 +1,35 @@ +bundle = zip-root + +all: scummvm.kos $(EXECUTABLE) + +scummvm.kos: $(srcdir)/backends/platform/sdl/kolibrios/wrapper-main.c + +$(QUIET_CC)$(CXX) -I$(KOS32_SDK_DIR)/sources/newlib/libc/include -specs=$(srcdir)/backends/platform/sdl/kolibrios/kolibrios.spec -x c -o $@.coff $< + +$(QUIET)$(KOS32_AUTOBUILD)/bin/kos32-objcopy $@.coff -O binary $@ + +$(bundle): all + $(RM) -rf $(bundle) + $(MKDIR) -p $(bundle)/scummvm + $(CP) $(DIST_FILES_DOCS) $(bundle)/scummvm + $(MKDIR) $(bundle)/scummvm/themes + $(CP) $(DIST_FILES_THEMES) $(bundle)/scummvm/themes/ + +ifdef DIST_FILES_ENGINEDATA + $(MKDIR) $(bundle)/scummvm/engine-data + $(CP) $(DIST_FILES_ENGINEDATA) $(bundle)/scummvm/engine-data/ +endif +ifdef DIST_FILES_NETWORKING + $(CP) $(DIST_FILES_NETWORKING) $(bundle)/scummvm +endif +ifdef DIST_FILES_VKEYBD + $(CP) $(DIST_FILES_VKEYBD) $(bundle)/scummvm +endif +ifdef DYNAMIC_MODULES + $(MKDIR) $(bundle)/scummvm/plugins/ + $(CP) $(PLUGINS) $(bundle)/scummvm/plugins/ +endif + $(CP) scummvm.kos $(bundle)/scummvm/scummvm + $(CP) scummvm.dll $(bundle)/scummvm/scummvm.dll + +scummvm-zip: $(bundle) + $(RM) scummvm_kolibrios.zip + cd $(bundle) && zip -r ../scummvm_kolibri.zip scummvm diff --git a/backends/platform/sdl/kolibrios/kolibrios.spec b/backends/platform/sdl/kolibrios/kolibrios.spec new file mode 100644 index 000000000000..1f2db4241dc1 --- /dev/null +++ b/backends/platform/sdl/kolibrios/kolibrios.spec @@ -0,0 +1,15 @@ +*lib: +-lc %{!static:-ldll} + +*libgcc: +-lsupc++ -lgcc + +*link: +%{mdll:%{shared: %eshared and mdll are not compatible} %{static: %estatic and mdll are not compatible}} -L%:getenv(KOS32_SDK_DIR /lib) %{shared|mdll: -shared --entry _DllStartup} %{shared:-T%:getenv(KOS32_SDK_DIR /sources/newlib/dll.lds)} %{static: -static -T%:getenv(KOS32_SDK_DIR /sources/newlib/app.lds)} %{!mdll:%{!static:%{!shared: -call_shared -T%:getenv(KOS32_SDK_DIR /sources/newlib/app-dynamic.lds)}}} %{!mdll:-s --image-base 0} %{mdll:--enable-auto-image-base} %(shared_libgcc_undefs) + +*startfile: + + +*endfile: + + diff --git a/configure b/configure index c84791f0424d..6e81da6a5f03 100755 --- a/configure +++ b/configure @@ -557,6 +557,9 @@ get_system_exe_extension() { gph-linux) _exeext=".gph" ;; + kolibrios | kos32) + _exeext=".dll" + ;; mingw* | *os2-emx) _exeext=".exe" ;; @@ -835,6 +838,7 @@ Special configuration feature: iphone for Apple iPhone (iOS <= 6) ios7 for Apple iPhone / iPad (iOS >= 7) ios7-arm64 for Apple iPhone / iPad (iOS >= 7, 64-bit) + kos32 for Kolibri OS maemo for Nokia Maemo miyoo for 1st generation Miyoo miyoomini for Miyoo Mini @@ -1628,6 +1632,11 @@ ios7-arm64) _host_cpu=aarch64 _host_alias=arm64-apple-darwin11 ;; +kos32) + _host_os=kolibrios + _host_cpu=i686 + _host_alias=kos32 + ;; maemo) _host_os=maemo _host_cpu=arm @@ -1854,6 +1863,24 @@ emscripten) exit 1 fi ;; +kolibrios) + if test -z "$KOS32_SDK_DIR" || test -z "$KOS32_AUTOBUILD"; then + echo "Please set KOS32_SDK_DIR and KOS32_AUTOBUILD in your environment. export KOS32_SDK_DIR= and export KOS32_AUTOBUILD=" + exit 1 + fi + _as="${KOS32_AUTOBUILD}/bin/kos32-as" + _ar="${KOS32_AUTOBUILD}/bin/kos32-ar cr" + _ranlib="${KOS32_AUTOBUILD}/bin/kos32-ar -s" + _strip="${KOS32_AUTOBUILD}/bin/kos32-strip" + if test -z "$CXX"; then + CXX="${KOS32_AUTOBUILD}/bin/kos32-g++" + fi + append_var DEFINES "-U__WIN32__ -U_Win32 -U_WIN32 -U__MINGW32__ -UWIN32 -DKOLIBRIOS=1 -D_POSIX_C_SOURCE=1 -D_XOPEN_SOURCE=1" + append_var CXXFLAGS "-I${KOS32_SDK_DIR}/sources/newlib/libc/include -I${KOS32_SDK_DIR}/sources/libstdc++-v3/include -fno-ident -fomit-frame-pointer" + # Final executable will be a DLL but for tests we need to stick to a standard binary because DLLs having a main function trigger a build failure + # We will add the -shared option at the end + append_var LDFLAGS "-specs=$_srcdir/backends/platform/sdl/kolibrios/kolibrios.spec" + ;; n64) if test -z "$N64SDK"; then echo "Please set N64SDK in your environment. export N64SDK=" @@ -2198,7 +2225,7 @@ if test "$have_gcc" = yes ; then case $_host_os in # newlib-based system include files suppress non-C89 function # declarations under __STRICT_ANSI__, undefine it - 3ds | android | gamecube | psp | switch | wii) + 3ds | android | gamecube | kolibrios | psp | switch | wii) std_variant=gnu++ pedantic=no ;; @@ -3493,6 +3520,35 @@ if test -n "$_host"; then _seq_midi=no _timidity=no ;; + kos32) + # neither pkg-config nor *-config work, so we setup everything manually + _pkgconfig=/bin/false + _pkg_config=no + + ZLIB_CFLAGS="-I${KOS32_SDK_DIR}/sources/zlib" + if test "$_png" != no; then + PNG_CFLAGS="-I${KOS32_SDK_DIR}/sources/libpng" + PNG_LIBS="-lpng16 -lz" + _png=yes + fi + JPEG_CFLAGS="-I${KOS32_SDK_DIR}/sources/libjpeg" + + FREETYPE2_STATIC_LIBS="-lfreetype" + FREETYPE2_CFLAGS="-I${KOS32_SDK_DIR}/sources/freetype/include" + _freetype_found="true" + + SDL_CFLAGS="-I${KOS32_SDK_DIR}/sources/SDL-1.2.2_newlib/include" + SDL_LIBS="-lSDLn -lsound" + _sdl=yes + _sdlversion=1.2.2 + _backend="kolibrios" + + _timidity=no + add_line_to_config_mk 'KOLIBRIOS = 1' + add_line_to_config_mk 'KOS32_AUTOBUILD = '"${KOS32_AUTOBUILD}" + add_line_to_config_mk 'KOS32_SDK_DIR = '"${KOS32_SDK_DIR}" + _port_mk="backends/platform/sdl/kolibrios/kolibrios.mk" + ;; m68k-atari-mint) _seq_midi=no _timidity=no @@ -3846,6 +3902,10 @@ case $_backend in append_var CXXFLAGS "-isysroot $SDKROOT -I$SDKROOT/usr/include/c++/4.2.1 -F$SDKROOT/System/Library/Frameworks" fi ;; + kolibrios) + _sdl=yes + append_var MODULES "backends/platform/sdl" + ;; maemo) append_var DEFINES "-DMAEMO" append_var LIBS "-lX11" @@ -3928,7 +3988,6 @@ case $_backend in ;; esac - append_var MODULES "backends/platform/$_backend" # @@ -4062,7 +4121,7 @@ fi # Enable 16bit support only for backends which support it # case $_backend in - 3ds | android | dingux | dc | ds | gph | iphone | ios7 | maemo | null | opendingux | miyoomini | miyoo | openpandora | psp | psp2 | samsungtv | sdl | switch | wii) + 3ds | android | dingux | dc | ds | gph | iphone | ios7 | kolibrios | maemo | null | opendingux | miyoomini | miyoo | openpandora | psp | psp2 | samsungtv | sdl | switch | wii) if test "$_16bit" = auto ; then _16bit=yes else @@ -4135,7 +4194,7 @@ esac # echo_n "Checking if host is POSIX compliant... " case $_host_os in - amigaos* | dreamcast | ds | gamecube | mingw* | morphos | n64 | ps3 | psp2 | psp | riscos | wii) + amigaos* | dreamcast | ds | gamecube | kolibrios | mingw* | morphos | n64 | ps3 | psp2 | psp | riscos | wii) _posix=no ;; 3ds | android | beos* | bsd* | cygwin* | darwin* | dragonfly* | freebsd* | gnu* | gph-linux | haiku* | hpux* | iphone | ios7 | irix*| k*bsd*-gnu* | linux* | maemo | mint* | netbsd* | openbsd* | serenity* | solaris* | sunos* | switch | uclinux*) @@ -4419,6 +4478,16 @@ PLUGIN_EXTRA_DEPS = PLUGIN_LDFLAGS += -shared -static-libgcc PRE_OBJS_FLAGS := -Wl,-export-dynamic -Wl,-whole-archive POST_OBJS_FLAGS := -Wl,-no-whole-archive +' + ;; + kolibrios) + _plugin_suffix=".svm.dll" + append_var DEFINES "-DUNCACHED_PLUGINS" +_mak_plugins=' +PLUGIN_EXTRA_DEPS = $(EXECUTABLE) +PLUGIN_LDFLAGS += -specs=$(srcdir)/backends/platform/sdl/kolibrios/kolibrios.spec -mdll -Wl,-q,--retain-symbols-file,$(srcdir)/backends/plugins/elf/plugin.syms -Wl,--enable-auto-import ./libscummvm.a +PRE_OBJS_FLAGS := -Wl,--whole-archive +POST_OBJS_FLAGS := -Wl,--export-all-symbols -Wl,--no-whole-archive -Wl,--out-implib,./libscummvm.a ' ;; @@ -5936,7 +6005,7 @@ if test "$_have_x86" = yes ; then darwin*) append_var NASMFLAGS "-f macho" ;; - mingw*) + mingw* | kolibrios) append_var NASMFLAGS "-f win32" ;; os2-emx*) @@ -6472,6 +6541,12 @@ case $_host_os in LIBS=`echo ${LIBS} | sed 's/-lz//g'` fi ;; + kolibrios) + # In reality we will build a DLL + append_var LDFLAGS "-shared" + # kos32 toolchain only has libpng16 + LIBS=`echo ${LIBS} | sed 's/-lpng //g'` + ;; mingw*) if test "$_windows_unicode" = yes; then append_var DEFINES "-DUNICODE -D_UNICODE" From d9da411b069c17261509cca9ce2703d7218a3d1f Mon Sep 17 00:00:00 2001 From: Roland van Laar Date: Sun, 5 Feb 2023 22:51:49 +0100 Subject: [PATCH 385/412] DIRECTOR: LINGO: Fix segfaults in clean up Split resetLingo into the cleanup and reset part. cleanup is necessary on ~Lingo. The reset and cleanup part when loading the next movie. --- engines/director/lingo/lingo.cpp | 10 ++++++---- engines/director/lingo/lingo.h | 2 ++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/engines/director/lingo/lingo.cpp b/engines/director/lingo/lingo.cpp index 7aa9bcb2145a..3e85f4751d60 100644 --- a/engines/director/lingo/lingo.cpp +++ b/engines/director/lingo/lingo.cpp @@ -224,7 +224,7 @@ Lingo::Lingo(DirectorEngine *vm) : _vm(vm) { } Lingo::~Lingo() { - resetLingo(); + cleanupLingo(); cleanupFuncs(); cleanupMethods(); delete _compiler; @@ -707,15 +707,17 @@ void Lingo::resetLingoGo() { // puppetSprite } -void Lingo::resetLingo() { - debugC(3, kDebugLingoExec, "Resetting Lingo!"); - +void Lingo::cleanupLingo() { g_director->_wm->removeMenu(); while (_state->callstack.size()) { popContext(true); } +} +void Lingo::resetLingo() { + debugC(3, kDebugLingoExec, "Resetting Lingo!"); + cleanupLingo(); resetLingoGo(); } diff --git a/engines/director/lingo/lingo.h b/engines/director/lingo/lingo.h index ddfbfb4d24d5..04268942a399 100644 --- a/engines/director/lingo/lingo.h +++ b/engines/director/lingo/lingo.h @@ -314,7 +314,9 @@ class Lingo { ~Lingo(); void resetLingo(); + void cleanupLingo(); void resetLingoGo(); + int getMenuNum(); int getMenuItemsNum(Datum &d); From 434316f284740f6a9d301c6f2c1a57412f061afd Mon Sep 17 00:00:00 2001 From: Eugene Sandulenko Date: Sun, 5 Feb 2023 23:01:40 +0100 Subject: [PATCH 386/412] NEWS: Mention KolibriOS support --- NEWS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/NEWS.md b/NEWS.md index c9a3da3dd6bc..b68ecd860ba6 100644 --- a/NEWS.md +++ b/NEWS.md @@ -25,6 +25,7 @@ For a more comprehensive changelog of the latest experimental code, see: - 1st generation Miyoo (New BittBoy, Pocket Go and PowKiddy Q90-V90-Q20) under TriForceX MiyooCFW. - Miyoo mini + - KolibriOS General: - Reduced amount of false positives in Mass Add. From 442365ec848c09f88149ac093f9008e47fd3cc31 Mon Sep 17 00:00:00 2001 From: Vladimir Serbinenko Date: Thu, 2 Feb 2023 02:12:14 +0100 Subject: [PATCH 387/412] 3DS: Specify version in .cia metadata .cia supports version only in form X.Y.Z so just put there MAJOR.MINOR.PATCH --- backends/platform/3ds/3ds.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backends/platform/3ds/3ds.mk b/backends/platform/3ds/3ds.mk index f4d4293bf2c8..e68b78011c4c 100644 --- a/backends/platform/3ds/3ds.mk +++ b/backends/platform/3ds/3ds.mk @@ -60,7 +60,7 @@ $(TARGET).bnr: $(APP_BANNER_IMAGE) $(APP_BANNER_AUDIO) @echo built ... $(notdir $@) $(TARGET).cia: $(EXECUTABLE) $(APP_RSF) $(TARGET).smdh $(TARGET).bnr romfs - @$(MAKEROM) -f cia -target t -exefslogo -o $@ -elf $(EXECUTABLE) -rsf $(APP_RSF) -banner $(TARGET).bnr -icon $(TARGET).smdh -DAPP_ROMFS=romfs/ + @$(MAKEROM) -ver $(shell echo $$(($(VER_MAJOR)*1024+$(VER_MINOR)*16+$(VER_PATCH)))) -f cia -target t -exefslogo -o $@ -elf $(EXECUTABLE) -rsf $(APP_RSF) -banner $(TARGET).bnr -icon $(TARGET).smdh -DAPP_ROMFS=romfs/ @echo built ... $(notdir $@) dist_3ds: $(TARGET).cia $(TARGET).3dsx $(DIST_FILES_DOCS) From 6903fb4be1a2c8c7bdf85cb51ed16a9d7d59ebe7 Mon Sep 17 00:00:00 2001 From: Cameron Cawley Date: Fri, 3 Feb 2023 15:28:31 +0000 Subject: [PATCH 388/412] COMMON: Simplify API for getHumanReadableBytes() --- common/util.cpp | 14 +++++++------- common/util.h | 2 +- gui/downloaddialog.cpp | 13 ++++++------- gui/downloadpacksdialog.cpp | 27 +++++++++++++-------------- gui/options.cpp | 4 ++-- gui/saveload-dialog.cpp | 6 +++--- 6 files changed, 32 insertions(+), 34 deletions(-) diff --git a/common/util.cpp b/common/util.cpp index 9a2b99d4ec74..4540f3bad33d 100644 --- a/common/util.cpp +++ b/common/util.cpp @@ -177,33 +177,33 @@ bool isBlank(int c) { #pragma mark - -Common::U32String getHumanReadableBytes(uint64 bytes, Common::String &unitsOut) { +Common::String getHumanReadableBytes(uint64 bytes, const char *&unitsOut) { if (bytes < 1024) { // I18N: Abbreviation for 'bytes' as data size - unitsOut = _("B"); + unitsOut = _s("B"); return Common::String::format("%lu", (unsigned long int)bytes); } double floating = bytes / 1024.0; - // I18N: Abbreviation for 'kilobytes' as data size - unitsOut = _("KB"); + // I18N: Abbreviation for 'kilobytes' as data size + unitsOut = _s("KB"); if (floating >= 1024) { floating /= 1024.0; // I18N: Abbreviation for 'megabytes' as data size - unitsOut = _("MB"); + unitsOut = _s("MB"); } if (floating >= 1024) { floating /= 1024.0; // I18N: Abbreviation for 'gigabytes' as data size - unitsOut = _("GB"); + unitsOut = _s("GB"); } if (floating >= 1024) { // woah floating /= 1024.0; // I18N: Abbreviation for 'terabytes' as data size - unitsOut = _("TB"); + unitsOut = _s("TB"); } // print one digit after floating point diff --git a/common/util.h b/common/util.h index 60f606a4be06..b4d9be28c70d 100644 --- a/common/util.h +++ b/common/util.h @@ -413,7 +413,7 @@ bool isBlank(int c); * * @return String with a floating point number representing the given size. */ -Common::U32String getHumanReadableBytes(uint64 bytes, Common::String &unitsOut); +Common::String getHumanReadableBytes(uint64 bytes, const char *&unitsOut); /** @} */ diff --git a/gui/downloaddialog.cpp b/gui/downloaddialog.cpp index 0a037865066f..3eba17dcea7c 100644 --- a/gui/downloaddialog.cpp +++ b/gui/downloaddialog.cpp @@ -208,17 +208,16 @@ void DownloadDialog::reflowLayout() { } Common::U32String DownloadDialog::getSizeLabelText() { - Common::String downloaded, downloadedUnits, total, totalUnits; - downloaded = getHumanReadableBytes(CloudMan.getDownloadBytesNumber(), downloadedUnits); - total = getHumanReadableBytes(CloudMan.getDownloadTotalBytesNumber(), totalUnits); + const char *downloadedUnits, *totalUnits; + Common::String downloaded = Common::getHumanReadableBytes(CloudMan.getDownloadBytesNumber(), downloadedUnits); + Common::String total = Common::getHumanReadableBytes(CloudMan.getDownloadTotalBytesNumber(), totalUnits); return Common::U32String::format(_("Downloaded %s %S / %s %S"), downloaded.c_str(), _(downloadedUnits).c_str(), total.c_str(), _(totalUnits).c_str()); } Common::U32String DownloadDialog::getSpeedLabelText() { - Common::String speed, speedUnits; - speed = getHumanReadableBytes(CloudMan.getDownloadSpeed(), speedUnits); - speedUnits += "/s"; - return Common::U32String::format(_("Download speed: %s %S"), speed.c_str(), _(speedUnits).c_str()); + const char *speedUnits; + Common::String speed = Common::getHumanReadableBytes(CloudMan.getDownloadSpeed(), speedUnits); + return Common::U32String::format(_("Download speed: %s %S/s"), speed.c_str(), _(speedUnits).c_str()); } void DownloadDialog::refreshWidgets() { diff --git a/gui/downloadpacksdialog.cpp b/gui/downloadpacksdialog.cpp index a990cec0bee6..412116d3c4ca 100644 --- a/gui/downloadpacksdialog.cpp +++ b/gui/downloadpacksdialog.cpp @@ -255,8 +255,8 @@ void DownloadPacksDialog::setState(IconProcessState state) { break; case kDownloadStateListCalculated: { - Common::String size, sizeUnits; - size = getHumanReadableBytes(g_state->totalSize, sizeUnits); + const char *sizeUnits; + Common::String size = Common::getHumanReadableBytes(g_state->totalSize, sizeUnits); _statusText->setLabel(Common::U32String::format(_("Detected %d new packs, %s %S"), g_state->fileHash.size(), size.c_str(), _(sizeUnits).c_str())); @@ -282,8 +282,8 @@ void DownloadPacksDialog::setState(IconProcessState state) { break; case kDownloadComplete: { - Common::String size, sizeUnits; - size = getHumanReadableBytes(g_state->totalSize, sizeUnits); + const char *sizeUnits; + Common::String size = Common::getHumanReadableBytes(g_state->totalSize, sizeUnits); _statusText->setLabel(Common::U32String::format(_("Download complete, downloaded %d packs, %s %S"), g_state->totalFiles, size.c_str(), _(sizeUnits).c_str())); _cancelButton->setVisible(false); _cancelButton->setLabel(_("Cancel download")); @@ -358,17 +358,16 @@ void DownloadPacksDialog::reflowLayout() { } Common::U32String DownloadPacksDialog::getSizeLabelText() { - Common::String downloaded, downloadedUnits, total, totalUnits; - downloaded = getHumanReadableBytes(g_state->downloadedSize, downloadedUnits); - total = getHumanReadableBytes(g_state->totalSize, totalUnits); + const char *downloadedUnits, *totalUnits; + Common::String downloaded = Common::getHumanReadableBytes(g_state->downloadedSize, downloadedUnits); + Common::String total = Common::getHumanReadableBytes(g_state->totalSize, totalUnits); return Common::U32String::format(_("Downloaded %s %S / %s %S"), downloaded.c_str(), _(downloadedUnits).c_str(), total.c_str(), _(totalUnits).c_str()); } Common::U32String DownloadPacksDialog::getSpeedLabelText() { - Common::String speed, speedUnits; - speed = getHumanReadableBytes(getDownloadSpeed(), speedUnits); - speedUnits += "/s"; - return Common::U32String::format(_("Download speed: %s %S"), speed.c_str(), _(speedUnits).c_str()); + const char *speedUnits; + Common::String speed = Common::getHumanReadableBytes(getDownloadSpeed(), speedUnits); + return Common::U32String::format(_("Download speed: %s %S/s"), speed.c_str(), _(speedUnits).c_str()); } void DownloadPacksDialog::refreshWidgets() { @@ -457,10 +456,10 @@ void DownloadPacksDialog::clearCache() { totalSize += size; } - Common::String sizeUnits; - Common::String size = getHumanReadableBytes(totalSize, sizeUnits); + const char *sizeUnits; + Common::String size = Common::getHumanReadableBytes(totalSize, sizeUnits); - GUI::MessageDialog dialog(Common::U32String::format(_("You are about to remove %s %s of data, deleting all previously downloaded %S. Do you want to proceed?"), size.c_str(), sizeUnits.c_str(), _packname.c_str()), _("Proceed"), _("Cancel")); + GUI::MessageDialog dialog(Common::U32String::format(_("You are about to remove %s %S of data, deleting all previously downloaded %S. Do you want to proceed?"), size.c_str(), _(sizeUnits).c_str(), _packname.c_str()), _("Proceed"), _("Cancel")); if (dialog.runModal() == ::GUI::kMessageOK) { // Build list of previously downloaded icon files diff --git a/gui/options.cpp b/gui/options.cpp index 11a4a267f412..44fa46702cf6 100644 --- a/gui/options.cpp +++ b/gui/options.cpp @@ -3541,8 +3541,8 @@ void GlobalOptionsDialog::setupCloudTab() { if (_storageUsedSpaceDesc) _storageUsedSpaceDesc->setVisible(shownConnectedInfo); if (_storageUsedSpace) { uint64 usedSpace = CloudMan.getStorageUsedSpace(_selectedStorageIndex); - Common::String usedSpaceNumber, usedSpaceUnits; - usedSpaceNumber = Common::getHumanReadableBytes(usedSpace, usedSpaceUnits); + const char *usedSpaceUnits; + Common::String usedSpaceNumber = Common::getHumanReadableBytes(usedSpace, usedSpaceUnits); _storageUsedSpace->setLabel(Common::U32String::format("%s %S", usedSpaceNumber.c_str(), _(usedSpaceUnits).c_str())); _storageUsedSpace->setVisible(shownConnectedInfo); } diff --git a/gui/saveload-dialog.cpp b/gui/saveload-dialog.cpp index bc7f75d44bbb..becf92617c53 100644 --- a/gui/saveload-dialog.cpp +++ b/gui/saveload-dialog.cpp @@ -113,9 +113,9 @@ void SaveLoadCloudSyncProgressDialog::pollCloudMan() { Cloud::Storage::SyncDownloadingInfo info; CloudMan.getSyncDownloadingInfo(info); - Common::String downloaded, downloadedUnits, total, totalUnits; - downloaded = getHumanReadableBytes(info.bytesDownloaded, downloadedUnits); - total = getHumanReadableBytes(info.bytesToDownload, totalUnits); + const char *downloadedUnits, *totalUnits; + Common::String downloaded = Common::getHumanReadableBytes(info.bytesDownloaded, downloadedUnits); + Common::String total = Common::getHumanReadableBytes(info.bytesToDownload, totalUnits); Common::String progressPercent = Common::String::format("%u %%", progress); Common::String filesDownloaded = Common::String::format("%llu", (unsigned long long)info.filesDownloaded); From 3044a8dd0bd9c5b9e5a966b6273115c46b121b9a Mon Sep 17 00:00:00 2001 From: antoniou79 Date: Fri, 3 Feb 2023 21:01:32 +0200 Subject: [PATCH 389/412] DEVTOOLS: COMPANION: Fix python error for createmacfonts Error was in line 686: NameError: name 'io' is not defined. Did you mean: 'id'? --- devtools/dumper-companion.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devtools/dumper-companion.py b/devtools/dumper-companion.py index 22d06964d50e..4a573eac2c3a 100755 --- a/devtools/dumper-companion.py +++ b/devtools/dumper-companion.py @@ -683,7 +683,7 @@ def create_macfonts(args: argparse.Namespace) -> int: ) as fontzip: for hpath, obj in vol.iter_paths(): print(f"Compressing {hpath[-1]}...") - with io.BytesIO() as fonts_bytesio: + with BytesIO() as fonts_bytesio: file_to_macbin(fonts_bytesio, obj, hpath[-1].encode("mac_roman")) fontzip.writestr(f"{hpath[-1]}.bin", fonts_bytesio.getvalue()) From 9bebbf211652323d2d080349eb56a8a630c2849e Mon Sep 17 00:00:00 2001 From: antoniou79 Date: Sat, 4 Feb 2023 13:01:09 +0200 Subject: [PATCH 390/412] DEVTOOLS: Updates to README file Fix deprecated url for dumper companion as well as some minor edits --- devtools/README | 50 +++++++++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/devtools/README b/devtools/README index 05a1093f1cdb..7e6195923ec4 100644 --- a/devtools/README +++ b/devtools/README @@ -26,21 +26,23 @@ convbdf Hint from SumthinWicked: If you use ttf2bdf, it'll convert all glyphs to bitmaps, but ScummVM only needs some of them. So you may want to do your conversion like this: + ttf2bdf -p SIZE -l "32_160" -o FONT.bdf FONT.ttf + where SIZE is replaced by the desired font height. -create_classicmacfonts.sh, create_japanesemacfonts.sh +create_japanesemacfonts.sh _____________________________________________________ - Scripts for extracting fonts from Classic MacOS images freely - available from apple.com. Used in Director, MacVenture, SCUMM - and WAGE engines. + Script for extracting fonts from Classic Japanese MacOS images + freely available from apple.com (used in Director, MacVenture, + SCUMM and WAGE engines). create_cryo ----------- Creates cryo.dat file which contains a lot of hardcoded tables used - by the Cryo engine.. + by the Cryo engine. create_drascula (sev) @@ -55,8 +57,8 @@ create_drascula (sev) create_encodings (phcoder) -------------- - Transforms CJK tables from unicode consortium format to the format - used by ScummVM + Transforms CJK tables from Unicode consortium format to the format + used by ScummVM. create_hugo (Strangerke) @@ -141,7 +143,7 @@ dist-scummvm.sh Note #2: This assumes that our naming conventions for release tags are being followed. I.e. the tag must be named "release-0-7-1" in the above example. You can, however, specify an alternate tag as the - fourth param. + fourth parameter. Note #3: Since SF.net anon CVS tends to lag behind developer CVS, if you just tagged CVS, anon CVS may not yet have this. So if you are @@ -164,8 +166,10 @@ docker.sh dumper_companion.py ___________________ Tool for dumping HFS/HFS+ volumes and game files with non-ASCII - characters in names. Full documentation could be found at - https://wiki.scummvm.org/index.php?title=HOWTO-Dump_Macintosh_Media + characters in names, as well as extracting fonts from Classic + MacOS images freely available from apple.com (used in Director, + MacVenture, SCUMM and WAGE engines). Full documentation can be found at: + https://docs.scummvm.org/en/latest/use_scummvm/mac_game_files.html gog_gameid.py, steam_gameid.py @@ -176,18 +180,20 @@ ______________________________ make_class.py ------------------- - Tool that adds all the boilerplate for a new C++ class inside an engine - Examples: - - $ make_class.py scumm . LeChuck - Make new class `LeChuck` in the scumm engine root (engines/scumm/). - Creates boilerplate class Scumm::LeChuck, in le_chuck.cpp and le_chuck.h - (files are lower-cased, upper-case letters from class name get '_' added). - Adds corresponding .o file to module.mk list. - - $ make_class.py -n BladeRunner bladerunner ui Scores - Make a new class BladeRunner::Scores in the engines/bladerunner/ui/ - directory. + Tool that adds all the boilerplate for a new C++ class inside an engine. + Examples: + + make_class.py scumm . LeChuck + + This will make a new class `LeChuck` under scumm engine root (engines/scumm/). + Creates boilerplate class Scumm::LeChuck, in le_chuck.cpp and le_chuck.h + (files are lower-cased, upper-case letters from class name get '_' added). + Adds corresponding .o file to module.mk list. + + make_class.py -n BladeRunner bladerunner ui Scores + + This will make a new class BladeRunner::Scores in the engines/bladerunner/ui/ + directory. make-scumm-fontdata (eriktorbjorn) From d97bd0c817f643ce1c74400d4a21cdeaacca46ec Mon Sep 17 00:00:00 2001 From: sluicebox <22204938+sluicebox@users.noreply.github.com> Date: Sun, 5 Feb 2023 02:59:05 -0800 Subject: [PATCH 391/412] CREATE_PROJECT: Set Xcode MACOSX_DEPLOYMENT_TARGET --- devtools/create_project/xcode.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/devtools/create_project/xcode.cpp b/devtools/create_project/xcode.cpp index 3f21708a59e7..be06f56eeeca 100644 --- a/devtools/create_project/xcode.cpp +++ b/devtools/create_project/xcode.cpp @@ -1389,6 +1389,7 @@ void XcodeProvider::setupBuildConfiguration(const BuildSetup &setup) { scummvmOSX_LibPaths.push_back("\"$(inherited)\""); scummvmOSX_LibPaths.push_back("\"\\\"$(SRCROOT)/lib\\\"\""); ADD_SETTING_LIST(scummvmOSX_Debug, "LIBRARY_SEARCH_PATHS", scummvmOSX_LibPaths, kSettingsNoQuote | kSettingsAsList, 5); + ADD_SETTING_QUOTE(scummvmOSX_Debug, "MACOSX_DEPLOYMENT_TARGET", "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)"); ADD_SETTING_QUOTE(scummvmOSX_Debug, "OTHER_CFLAGS", ""); ADD_SETTING(scummvmOSX_Debug, "PRODUCT_NAME", PROJECT_NAME); From 380643315e87480066f9eb55ca5e93bd8aa4134f Mon Sep 17 00:00:00 2001 From: Cameron Cawley Date: Sat, 4 Feb 2023 13:37:57 +0000 Subject: [PATCH 392/412] GRAPHICS: Support flipping in scaleBlit and rotoscaleBlit --- graphics/blit-scale.cpp | 76 +++++++++++++++++++++------------- graphics/blit.h | 6 ++- graphics/transform_struct.h | 18 +++++++- graphics/transparent_surface.h | 16 ------- 4 files changed, 68 insertions(+), 48 deletions(-) diff --git a/graphics/blit-scale.cpp b/graphics/blit-scale.cpp index d4c279cc402e..8b59a6be7b8f 100644 --- a/graphics/blit-scale.cpp +++ b/graphics/blit-scale.cpp @@ -40,18 +40,30 @@ void scaleNN(byte *dst, const byte *src, const uint dstPitch, const uint srcPitch, const uint dstW, const uint dstH, const uint srcW, const uint srcH, - int *scaleCacheX) { + int *scaleCacheX, const byte flip) { + const bool flipx = flip & FLIP_H; + const bool flipy = flip & FLIP_V; - const uint dstDelta = (dstPitch - dstW * sizeof(Size)); + const int dstIncX = (flipx ? -1 : 1); + const int dstIncY = (flipy ? -dstPitch : dstPitch); + + if (flipx) { + dst += (dstW - 1) * sizeof(Size); + } + + if (flipy) { + dst += (dstH - 1) * dstPitch; + } for (uint y = 0; y < dstH; y++) { const Size *srcP = (const Size *)(src + ((y * srcH) / dstH) * srcPitch); + Size *dst1 = (Size *)dst; for (uint x = 0; x < dstW; x++) { int val = srcP[scaleCacheX[x]]; - *(Size *)dst = val; - dst += sizeof(Size); + *dst1 = val; + dst1 += dstIncX; } - dst += dstDelta; + dst += dstIncY; } } @@ -61,7 +73,8 @@ bool scaleBlit(byte *dst, const byte *src, const uint dstPitch, const uint srcPitch, const uint dstW, const uint dstH, const uint srcW, const uint srcH, - const Graphics::PixelFormat &fmt) { + const Graphics::PixelFormat &fmt, + const byte flip) { int *scaleCacheX = new int[dstW]; for (uint x = 0; x < dstW; x++) { @@ -70,13 +83,13 @@ bool scaleBlit(byte *dst, const byte *src, switch (fmt.bytesPerPixel) { case 1: - scaleNN(dst, src, dstPitch, srcPitch, dstW, dstH, srcW, srcH, scaleCacheX); + scaleNN(dst, src, dstPitch, srcPitch, dstW, dstH, srcW, srcH, scaleCacheX, flip); break; case 2: - scaleNN(dst, src, dstPitch, srcPitch, dstW, dstH, srcW, srcH, scaleCacheX); + scaleNN(dst, src, dstPitch, srcPitch, dstW, dstH, srcW, srcH, scaleCacheX, flip); break; case 4: - scaleNN(dst, src, dstPitch, srcPitch, dstW, dstH, srcW, srcH, scaleCacheX); + scaleNN(dst, src, dstPitch, srcPitch, dstW, dstH, srcW, srcH, scaleCacheX, flip); break; default: delete[] scaleCacheX; @@ -158,13 +171,15 @@ Size scaleBlitBilinearInterpolate(Size c01, Size c00, Size c11, Size c10, int ex return fmt.ARGBToColorT(dp_a, dp_r, dp_g, dp_b); } -template // TODO: See mirroring comment in RenderTicket ctor +template void scaleBlitBilinearLogic(byte *dst, const byte *src, const uint dstPitch, const uint srcPitch, const uint dstW, const uint dstH, const uint srcW, const uint srcH, const Graphics::PixelFormat &fmt, - int *sax, int *say) { + int *sax, int *say, byte flip) { + const bool flipx = flip & FLIP_H; + const bool flipy = flip & FLIP_V; int spixelw = (srcW - 1); int spixelh = (srcH - 1); @@ -172,7 +187,7 @@ void scaleBlitBilinearLogic(byte *dst, const byte *src, const byte *sp = src; if (flipx) { - sp += spixelw; + sp += spixelw * sizeof(Size); } if (flipy) { sp += srcPitch * spixelh; @@ -248,7 +263,7 @@ void scaleBlitBilinearLogic(byte *dst, const byte *src, } } -template // TODO: See mirroring comment in RenderTicket ctor +template void rotoscaleBlitLogic(byte *dst, const byte *src, const uint dstPitch, const uint srcPitch, const uint dstW, const uint dstH, @@ -256,6 +271,8 @@ void rotoscaleBlitLogic(byte *dst, const byte *src, const Graphics::PixelFormat &fmt, const TransformStruct &transform, const Common::Point &newHotspot) { + const bool flipx = transform._flip & FLIP_H; + const bool flipy = transform._flip & FLIP_V; assert(transform._angle != kDefaultAngle); // This would not be ideal; rotoscale() should never be called in conditional branches where angle = 0 anyway. @@ -344,7 +361,8 @@ bool scaleBlitBilinear(byte *dst, const byte *src, const uint dstPitch, const uint srcPitch, const uint dstW, const uint dstH, const uint srcW, const uint srcH, - const Graphics::PixelFormat &fmt) { + const Graphics::PixelFormat &fmt, + const byte flip) { if (fmt.bytesPerPixel != 2 && fmt.bytesPerPixel != 4) return false; @@ -393,18 +411,18 @@ bool scaleBlitBilinear(byte *dst, const byte *src, } if (fmt == createPixelFormat<8888>()) { - scaleBlitBilinearLogic, uint32, false, false>(dst, src, dstPitch, srcPitch, dstW, dstH, srcW, srcH, fmt, sax, say); + scaleBlitBilinearLogic, uint32>(dst, src, dstPitch, srcPitch, dstW, dstH, srcW, srcH, fmt, sax, say, flip); } else if (fmt == createPixelFormat<888>()) { - scaleBlitBilinearLogic, uint32, false, false>(dst, src, dstPitch, srcPitch, dstW, dstH, srcW, srcH, fmt, sax, say); + scaleBlitBilinearLogic, uint32>(dst, src, dstPitch, srcPitch, dstW, dstH, srcW, srcH, fmt, sax, say, flip); } else if (fmt == createPixelFormat<565>()) { - scaleBlitBilinearLogic, uint16, false, false>(dst, src, dstPitch, srcPitch, dstW, dstH, srcW, srcH, fmt, sax, say); + scaleBlitBilinearLogic, uint16>(dst, src, dstPitch, srcPitch, dstW, dstH, srcW, srcH, fmt, sax, say, flip); } else if (fmt == createPixelFormat<555>()) { - scaleBlitBilinearLogic, uint16, false, false>(dst, src, dstPitch, srcPitch, dstW, dstH, srcW, srcH, fmt, sax, say); + scaleBlitBilinearLogic, uint16>(dst, src, dstPitch, srcPitch, dstW, dstH, srcW, srcH, fmt, sax, say, flip); } else if (fmt.bytesPerPixel == 4) { - scaleBlitBilinearLogic, uint32, false, false>(dst, src, dstPitch, srcPitch, dstW, dstH, srcW, srcH, fmt, sax, say); + scaleBlitBilinearLogic, uint32>(dst, src, dstPitch, srcPitch, dstW, dstH, srcW, srcH, fmt, sax, say, flip); } else if (fmt.bytesPerPixel == 2) { - scaleBlitBilinearLogic, uint16, false, false>(dst, src, dstPitch, srcPitch, dstW, dstH, srcW, srcH, fmt, sax, say); + scaleBlitBilinearLogic, uint16>(dst, src, dstPitch, srcPitch, dstW, dstH, srcW, srcH, fmt, sax, say, flip); } else { delete[] sax; delete[] say; @@ -426,11 +444,11 @@ bool rotoscaleBlit(byte *dst, const byte *src, const TransformStruct &transform, const Common::Point &newHotspot) { if (fmt.bytesPerPixel == 4) { - rotoscaleBlitLogic, uint32, false, false, false>(dst, src, dstPitch, srcPitch, dstW, dstH, srcW, srcH, fmt, transform, newHotspot); + rotoscaleBlitLogic, uint32, false>(dst, src, dstPitch, srcPitch, dstW, dstH, srcW, srcH, fmt, transform, newHotspot); } else if (fmt.bytesPerPixel == 2) { - rotoscaleBlitLogic, uint16, false, false, false>(dst, src, dstPitch, srcPitch, dstW, dstH, srcW, srcH, fmt, transform, newHotspot); + rotoscaleBlitLogic, uint16, false>(dst, src, dstPitch, srcPitch, dstW, dstH, srcW, srcH, fmt, transform, newHotspot); } else if (fmt.bytesPerPixel == 1) { - rotoscaleBlitLogic, uint8, false, false, false>(dst, src, dstPitch, srcPitch, dstW, dstH, srcW, srcH, fmt, transform, newHotspot); + rotoscaleBlitLogic, uint8, false>(dst, src, dstPitch, srcPitch, dstW, dstH, srcW, srcH, fmt, transform, newHotspot); } else { return false; } @@ -446,18 +464,18 @@ bool rotoscaleBlitBilinear(byte *dst, const byte *src, const TransformStruct &transform, const Common::Point &newHotspot) { if (fmt == createPixelFormat<8888>()) { - rotoscaleBlitLogic, uint32, true, false, false>(dst, src, dstPitch, srcPitch, dstW, dstH, srcW, srcH, fmt, transform, newHotspot); + rotoscaleBlitLogic, uint32, true>(dst, src, dstPitch, srcPitch, dstW, dstH, srcW, srcH, fmt, transform, newHotspot); } else if (fmt == createPixelFormat<888>()) { - rotoscaleBlitLogic, uint32, true, false, false>(dst, src, dstPitch, srcPitch, dstW, dstH, srcW, srcH, fmt, transform, newHotspot); + rotoscaleBlitLogic, uint32, true>(dst, src, dstPitch, srcPitch, dstW, dstH, srcW, srcH, fmt, transform, newHotspot); } else if (fmt == createPixelFormat<565>()) { - rotoscaleBlitLogic, uint16, true, false, false>(dst, src, dstPitch, srcPitch, dstW, dstH, srcW, srcH, fmt, transform, newHotspot); + rotoscaleBlitLogic, uint16, true>(dst, src, dstPitch, srcPitch, dstW, dstH, srcW, srcH, fmt, transform, newHotspot); } else if (fmt == createPixelFormat<555>()) { - rotoscaleBlitLogic, uint16, true, false, false>(dst, src, dstPitch, srcPitch, dstW, dstH, srcW, srcH, fmt, transform, newHotspot); + rotoscaleBlitLogic, uint16, true>(dst, src, dstPitch, srcPitch, dstW, dstH, srcW, srcH, fmt, transform, newHotspot); } else if (fmt.bytesPerPixel == 4) { - rotoscaleBlitLogic, uint32, true, false, false>(dst, src, dstPitch, srcPitch, dstW, dstH, srcW, srcH, fmt, transform, newHotspot); + rotoscaleBlitLogic, uint32, true>(dst, src, dstPitch, srcPitch, dstW, dstH, srcW, srcH, fmt, transform, newHotspot); } else if (fmt.bytesPerPixel == 2) { - rotoscaleBlitLogic, uint16, true, false, false>(dst, src, dstPitch, srcPitch, dstW, dstH, srcW, srcH, fmt, transform, newHotspot); + rotoscaleBlitLogic, uint16, true>(dst, src, dstPitch, srcPitch, dstW, dstH, srcW, srcH, fmt, transform, newHotspot); } else { return false; } diff --git a/graphics/blit.h b/graphics/blit.h index cf09ded21603..aae83aafa0b3 100644 --- a/graphics/blit.h +++ b/graphics/blit.h @@ -151,13 +151,15 @@ bool scaleBlit(byte *dst, const byte *src, const uint dstPitch, const uint srcPitch, const uint dstW, const uint dstH, const uint srcW, const uint srcH, - const Graphics::PixelFormat &fmt); + const Graphics::PixelFormat &fmt, + const byte flip = 0); bool scaleBlitBilinear(byte *dst, const byte *src, const uint dstPitch, const uint srcPitch, const uint dstW, const uint dstH, const uint srcW, const uint srcH, - const Graphics::PixelFormat &fmt); + const Graphics::PixelFormat &fmt, + const byte flip = 0); bool rotoscaleBlit(byte *dst, const byte *src, const uint dstPitch, const uint srcPitch, diff --git a/graphics/transform_struct.h b/graphics/transform_struct.h index 4c8de37d80da..35e5d9cde10c 100644 --- a/graphics/transform_struct.h +++ b/graphics/transform_struct.h @@ -35,6 +35,22 @@ enum TSpriteBlendMode { NUM_BLEND_MODES }; +/** + @brief The possible flipping parameters for the blit method. + */ +enum FLIP_FLAGS { + /// The image will not be flipped. + FLIP_NONE = 0, + /// The image will be flipped at the horizontal axis. + FLIP_H = 1, + /// The image will be flipped at the vertical axis. + FLIP_V = 2, + /// The image will be flipped at the horizontal and vertical axis. + FLIP_HV = FLIP_H | FLIP_V, + /// The image will be flipped at the horizontal and vertical axis. + FLIP_VH = FLIP_H | FLIP_V +}; + /** * Contains all the required information that define a transform. * Same source sprite + same TransformStruct = Same resulting sprite. @@ -65,7 +81,7 @@ struct TransformStruct { Common::Point _zoom; ///< Zoom; 100 = no zoom Common::Point _hotspot; ///< Position of the hotspot int32 _angle; ///< Rotation angle, in degrees - byte _flip; ///< Bitflag: see TransparentSurface::FLIP_XXX + byte _flip; ///< Bitflag: see FLIP_XXX bool _alphaDisable; TSpriteBlendMode _blendMode; uint32 _rgbaMod; ///< RGBa diff --git a/graphics/transparent_surface.h b/graphics/transparent_surface.h index 737e80e633a2..5e6b292ead8a 100644 --- a/graphics/transparent_surface.h +++ b/graphics/transparent_surface.h @@ -49,22 +49,6 @@ namespace Graphics { */ // Enums -/** - @brief The possible flipping parameters for the blit method. - */ -enum FLIP_FLAGS { - /// The image will not be flipped. - FLIP_NONE = 0, - /// The image will be flipped at the horizontal axis. - FLIP_H = 1, - /// The image will be flipped at the vertical axis. - FLIP_V = 2, - /// The image will be flipped at the horizontal and vertical axis. - FLIP_HV = FLIP_H | FLIP_V, - /// The image will be flipped at the horizontal and vertical axis. - FLIP_VH = FLIP_H | FLIP_V -}; - enum AlphaType { ALPHA_OPAQUE = 0, ALPHA_BINARY = 1, From 5f06b599c83730cda2ea2904bd4d1025d1d5876a Mon Sep 17 00:00:00 2001 From: Cameron Cawley Date: Sun, 5 Feb 2023 18:54:04 +0000 Subject: [PATCH 393/412] GUI: Don't create a popup for the stretch mode if it's not supported --- gui/options.cpp | 115 +++++++++++++++++++++++++----------------------- 1 file changed, 61 insertions(+), 54 deletions(-) diff --git a/gui/options.cpp b/gui/options.cpp index 44fa46702cf6..5de18f936a3b 100644 --- a/gui/options.cpp +++ b/gui/options.cpp @@ -346,26 +346,6 @@ void OptionsDialog::build() { _renderModePopUp->setSelectedTag(sel); } - _stretchPopUp->setSelected(0); - - if (g_system->hasFeature(OSystem::kFeatureStretchMode)) { - if (ConfMan.hasKey("stretch_mode", _domain)) { - const OSystem::GraphicsMode *sm = g_system->getSupportedStretchModes(); - Common::String stretchMode(ConfMan.get("stretch_mode", _domain)); - int stretchCount = 1; - while (sm->name) { - stretchCount++; - if (scumm_stricmp(sm->name, stretchMode.c_str()) == 0) - _stretchPopUp->setSelected(stretchCount); - sm++; - } - } - } else { - _stretchPopUpDesc->setVisible(false); - _stretchPopUp->setVisible(false); - _stretchPopUp->setEnabled(false); - } - _scalerPopUp->setSelected(0); _scaleFactorPopUp->setSelected(0); @@ -442,6 +422,27 @@ void OptionsDialog::build() { } } + if (_stretchPopUp) { + if (g_system->hasFeature(OSystem::kFeatureStretchMode)) { + _stretchPopUp->setSelected(0); + + if (ConfMan.hasKey("stretch_mode", _domain)) { + const OSystem::GraphicsMode *sm = g_system->getSupportedStretchModes(); + Common::String stretchMode(ConfMan.get("stretch_mode", _domain)); + int stretchCount = 1; + while (sm->name) { + stretchCount++; + if (scumm_stricmp(sm->name, stretchMode.c_str()) == 0) + _stretchPopUp->setSelected(stretchCount); + sm++; + } + } + } else { + _stretchPopUpDesc->setVisible(false); + _stretchPopUp->setVisible(false); + } + } + // Shader options if (_shader) { if (g_system->hasFeature(OSystem::kFeatureShaders)) { @@ -650,28 +651,30 @@ void OptionsDialog::apply() { } } - isSet = false; - if ((int32)_stretchPopUp->getSelectedTag() >= 0) { - const OSystem::GraphicsMode *sm = g_system->getSupportedStretchModes(); - - while (sm->name) { - if (sm->id == (int)_stretchPopUp->getSelectedTag()) { - if (ConfMan.get("stretch_mode", _domain) != sm->name) { - graphicsModeChanged = true; - ConfMan.set("stretch_mode", sm->name, _domain); - _stretchPopUpDesc->setFontColor(ThemeEngine::FontColor::kFontColorNormal); + if (g_system->hasFeature(OSystem::kFeatureStretchMode)) { + isSet = false; + if ((int32)_stretchPopUp->getSelectedTag() >= 0) { + const OSystem::GraphicsMode *sm = g_system->getSupportedStretchModes(); + + while (sm->name) { + if (sm->id == (int)_stretchPopUp->getSelectedTag()) { + if (ConfMan.get("stretch_mode", _domain) != sm->name) { + graphicsModeChanged = true; + ConfMan.set("stretch_mode", sm->name, _domain); + _stretchPopUpDesc->setFontColor(ThemeEngine::FontColor::kFontColorNormal); + } + isSet = true; + break; } - isSet = true; - break; + sm++; } - sm++; } - } - if (!isSet) { - _stretchPopUpDesc->setFontColor(ThemeEngine::FontColor::kFontColorNormal); - ConfMan.removeKey("stretch_mode", _domain); - if (g_system->getStretchMode() != g_system->getDefaultStretchMode()) - graphicsModeChanged = true; + if (!isSet) { + _stretchPopUpDesc->setFontColor(ThemeEngine::FontColor::kFontColorNormal); + ConfMan.removeKey("stretch_mode", _domain); + if (g_system->getStretchMode() != g_system->getDefaultStretchMode()) + graphicsModeChanged = true; + } } isSet = false; @@ -1229,8 +1232,11 @@ void OptionsDialog::setGraphicSettingsState(bool enabled) { _stretchPopUpDesc->setEnabled(enabled); _stretchPopUp->setEnabled(enabled); } else { - _stretchPopUpDesc->setEnabled(false); - _stretchPopUp->setEnabled(false); + // Happens when we switch to backend that doesn't support stretch modes + if (_stretchPopUp) { + _stretchPopUpDesc->setEnabled(false); + _stretchPopUp->setEnabled(false); + } } if (g_system->hasFeature(OSystem::kFeatureScalers)) { @@ -1582,17 +1588,19 @@ void OptionsDialog::addGraphicControls(GuiObject *boss, const Common::String &pr } // The Stretch mode popup - const OSystem::GraphicsMode *sm = g_system->getSupportedStretchModes(); - _stretchPopUpDesc = new StaticTextWidget(boss, prefix + "grStretchModePopupDesc", _("Stretch mode:")); - if (ConfMan.isKeyTemporary("stretch_mode")) - _stretchPopUpDesc->setFontColor(ThemeEngine::FontColor::kFontColorOverride); - _stretchPopUp = new PopUpWidget(boss, prefix + "grStretchModePopup"); + if (g_system->hasFeature(OSystem::kFeatureStretchMode)) { + const OSystem::GraphicsMode *sm = g_system->getSupportedStretchModes(); + _stretchPopUpDesc = new StaticTextWidget(boss, prefix + "grStretchModePopupDesc", _("Stretch mode:")); + if (ConfMan.isKeyTemporary("stretch_mode")) + _stretchPopUpDesc->setFontColor(ThemeEngine::FontColor::kFontColorOverride); + _stretchPopUp = new PopUpWidget(boss, prefix + "grStretchModePopup"); - _stretchPopUp->appendEntry(_("")); - _stretchPopUp->appendEntry(Common::U32String()); - while (sm->name) { - _stretchPopUp->appendEntry(_c(sm->description, context), sm->id); - sm++; + _stretchPopUp->appendEntry(_("")); + _stretchPopUp->appendEntry(Common::U32String()); + while (sm->name) { + _stretchPopUp->appendEntry(_c(sm->description, context), sm->id); + sm++; + } } // The Scaler popup @@ -1998,6 +2006,8 @@ void OptionsDialog::setupGraphicsTab() { // Fixes crash when switching from SDL Surface to OpenGL if (!_shader && g_system->hasFeature(OSystem::kFeatureShaders)) { rebuild(); + } else if (!_stretchPopUp && g_system->hasFeature(OSystem::kFeatureStretchMode)) { + rebuild(); } setGraphicSettingsState(_enableGraphicSettings); } @@ -2008,9 +2018,6 @@ void OptionsDialog::setupGraphicsTab() { if (g_system->hasFeature(OSystem::kFeatureStretchMode)) { _stretchPopUpDesc->setVisible(true); _stretchPopUp->setVisible(true); - } else { - _stretchPopUpDesc->setVisible(false); - _stretchPopUp->setVisible(false); } _fullscreenCheckbox->setVisible(true); if (g_system->hasFeature(OSystem::kFeatureFilteringMode)) From ce4bbb223312cab0fecbfd636e13ec9c650ac6b7 Mon Sep 17 00:00:00 2001 From: Cameron Cawley Date: Sun, 5 Feb 2023 19:06:49 +0000 Subject: [PATCH 394/412] GUI: Don't create popups for scalers if they're not supported --- gui/options.cpp | 157 +++++++++++++++++++++++++----------------------- 1 file changed, 81 insertions(+), 76 deletions(-) diff --git a/gui/options.cpp b/gui/options.cpp index 5de18f936a3b..408ad71e1502 100644 --- a/gui/options.cpp +++ b/gui/options.cpp @@ -346,39 +346,6 @@ void OptionsDialog::build() { _renderModePopUp->setSelectedTag(sel); } - _scalerPopUp->setSelected(0); - _scaleFactorPopUp->setSelected(0); - - if (g_system->hasFeature(OSystem::kFeatureScalers)) { - if (ConfMan.hasKey("scaler", _domain)) { - const PluginList &scalerPlugins = ScalerMan.getPlugins(); - Common::String scaler(ConfMan.get("scaler", _domain)); - - for (uint scalerIndex = 0; scalerIndex < scalerPlugins.size(); scalerIndex++) { - if (scumm_stricmp(scalerPlugins[scalerIndex]->get().getName(), scaler.c_str()) != 0) - continue; - - _scalerPopUp->setSelectedTag(scalerIndex); - updateScaleFactors(scalerIndex); - - if (ConfMan.hasKey("scale_factor", _domain)) { - int scaleFactor = ConfMan.getInt("scale_factor", _domain); - if (scalerPlugins[scalerIndex]->get().hasFactor(scaleFactor)) - _scaleFactorPopUp->setSelectedTag(scaleFactor); - } - - break; - } - - } - } else { - _scalerPopUpDesc->setVisible(false); - _scalerPopUp->setVisible(false); - _scalerPopUp->setEnabled(false); - _scaleFactorPopUp->setVisible(false); - _scaleFactorPopUp->setEnabled(false); - } - // Fullscreen setting if (g_system->hasFeature(OSystem::kFeatureFullscreenMode)) { _fullscreenCheckbox->setState(ConfMan.getBool("fullscreen", _domain)); @@ -443,6 +410,39 @@ void OptionsDialog::build() { } } + if (_scalerPopUp) { + if (g_system->hasFeature(OSystem::kFeatureScalers)) { + _scalerPopUp->setSelected(0); + _scaleFactorPopUp->setSelected(0); + + if (ConfMan.hasKey("scaler", _domain)) { + const PluginList &scalerPlugins = ScalerMan.getPlugins(); + Common::String scaler(ConfMan.get("scaler", _domain)); + + for (uint scalerIndex = 0; scalerIndex < scalerPlugins.size(); scalerIndex++) { + if (scumm_stricmp(scalerPlugins[scalerIndex]->get().getName(), scaler.c_str()) != 0) + continue; + + _scalerPopUp->setSelectedTag(scalerIndex); + updateScaleFactors(scalerIndex); + + if (ConfMan.hasKey("scale_factor", _domain)) { + int scaleFactor = ConfMan.getInt("scale_factor", _domain); + if (scalerPlugins[scalerIndex]->get().hasFactor(scaleFactor)) + _scaleFactorPopUp->setSelectedTag(scaleFactor); + } + + break; + } + + } + } else { + _scalerPopUpDesc->setVisible(false); + _scalerPopUp->setVisible(false); + _scaleFactorPopUp->setVisible(false); + } + } + // Shader options if (_shader) { if (g_system->hasFeature(OSystem::kFeatureShaders)) { @@ -677,35 +677,37 @@ void OptionsDialog::apply() { } } - isSet = false; - const PluginList &scalerPlugins = ScalerMan.getPlugins(); - if ((int32)_scalerPopUp->getSelectedTag() >= 0) { - const char *name = scalerPlugins[_scalerPopUp->getSelectedTag()]->get().getName(); - if (ConfMan.get("scaler", _domain) != name) { - graphicsModeChanged = true; - ConfMan.set("scaler", name, _domain); - _scalerPopUpDesc->setFontColor(ThemeEngine::FontColor::kFontColorNormal); - } + if (g_system->hasFeature(OSystem::kFeatureScalers)) { + isSet = false; + const PluginList &scalerPlugins = ScalerMan.getPlugins(); + if ((int32)_scalerPopUp->getSelectedTag() >= 0) { + const char *name = scalerPlugins[_scalerPopUp->getSelectedTag()]->get().getName(); + if (ConfMan.get("scaler", _domain) != name) { + graphicsModeChanged = true; + ConfMan.set("scaler", name, _domain); + _scalerPopUpDesc->setFontColor(ThemeEngine::FontColor::kFontColorNormal); + } - int factor = _scaleFactorPopUp->getSelectedTag(); - if (ConfMan.getInt("scale_factor", _domain) != factor) { - ConfMan.setInt("scale_factor", factor, _domain); - graphicsModeChanged = true; - _scalerPopUpDesc->setFontColor(ThemeEngine::FontColor::kFontColorNormal); + int factor = _scaleFactorPopUp->getSelectedTag(); + if (ConfMan.getInt("scale_factor", _domain) != factor) { + ConfMan.setInt("scale_factor", factor, _domain); + graphicsModeChanged = true; + _scalerPopUpDesc->setFontColor(ThemeEngine::FontColor::kFontColorNormal); + } + isSet = true; } - isSet = true; - } - if (!isSet) { - ConfMan.removeKey("scaler", _domain); - ConfMan.removeKey("scale_factor", _domain); - _scalerPopUpDesc->setFontColor(ThemeEngine::FontColor::kFontColorNormal); + if (!isSet) { + ConfMan.removeKey("scaler", _domain); + ConfMan.removeKey("scale_factor", _domain); + _scalerPopUpDesc->setFontColor(ThemeEngine::FontColor::kFontColorNormal); - uint defaultScaler = g_system->getDefaultScaler(); - uint defaultScaleFactor = g_system->getDefaultScaleFactor(); - if (g_system->getScaler() != defaultScaler) - graphicsModeChanged = true; - else if (g_system->getScaleFactor() != defaultScaleFactor) - graphicsModeChanged = true; + uint defaultScaler = g_system->getDefaultScaler(); + uint defaultScaleFactor = g_system->getDefaultScaleFactor(); + if (g_system->getScaler() != defaultScaler) + graphicsModeChanged = true; + else if (g_system->getScaleFactor() != defaultScaleFactor) + graphicsModeChanged = true; + } } if (_rendererTypePopUp->getSelectedTag() > 0) { @@ -1244,9 +1246,12 @@ void OptionsDialog::setGraphicSettingsState(bool enabled) { _scalerPopUp->setEnabled(enabled); _scaleFactorPopUp->setEnabled(enabled); } else { - _scalerPopUpDesc->setEnabled(false); - _scalerPopUp->setEnabled(false); - _scaleFactorPopUp->setEnabled(false); + // Happens when we switch to backend that doesn't support scalers + if (_scalerPopUp) { + _scalerPopUpDesc->setEnabled(false); + _scalerPopUp->setEnabled(false); + _scaleFactorPopUp->setEnabled(false); + } } if (g_system->hasFeature(OSystem::kFeatureShaders)) { @@ -1604,18 +1609,20 @@ void OptionsDialog::addGraphicControls(GuiObject *boss, const Common::String &pr } // The Scaler popup - const PluginList &scalerPlugins = ScalerMan.getPlugins(); - _scalerPopUpDesc = new StaticTextWidget(boss, prefix + "grScalerPopupDesc", _("Scaler:")); - _scalerPopUp = new PopUpWidget(boss, prefix + "grScalerPopup", Common::U32String(), kScalerPopUpCmd); + if (g_system->hasFeature(OSystem::kFeatureScalers)) { + const PluginList &scalerPlugins = ScalerMan.getPlugins(); + _scalerPopUpDesc = new StaticTextWidget(boss, prefix + "grScalerPopupDesc", _("Scaler:")); + _scalerPopUp = new PopUpWidget(boss, prefix + "grScalerPopup", Common::U32String(), kScalerPopUpCmd); - _scalerPopUp->appendEntry(_("")); - _scalerPopUp->appendEntry(Common::U32String()); - for (uint scalerIndex = 0; scalerIndex < scalerPlugins.size(); scalerIndex++) { - _scalerPopUp->appendEntry(_c(scalerPlugins[scalerIndex]->get().getPrettyName(), context), scalerIndex); - } + _scalerPopUp->appendEntry(_("")); + _scalerPopUp->appendEntry(Common::U32String()); + for (uint scalerIndex = 0; scalerIndex < scalerPlugins.size(); scalerIndex++) { + _scalerPopUp->appendEntry(_c(scalerPlugins[scalerIndex]->get().getPrettyName(), context), scalerIndex); + } - _scaleFactorPopUp = new PopUpWidget(boss, prefix + "grScaleFactorPopup"); - updateScaleFactors(_scalerPopUp->getSelectedTag()); + _scaleFactorPopUp = new PopUpWidget(boss, prefix + "grScaleFactorPopup"); + updateScaleFactors(_scalerPopUp->getSelectedTag()); + } if (g_system->hasFeature(OSystem::kFeatureShaders)) { if (g_system->getOverlayWidth() > 320) @@ -2006,6 +2013,8 @@ void OptionsDialog::setupGraphicsTab() { // Fixes crash when switching from SDL Surface to OpenGL if (!_shader && g_system->hasFeature(OSystem::kFeatureShaders)) { rebuild(); + } else if (!_scalerPopUp && g_system->hasFeature(OSystem::kFeatureScalers)) { + rebuild(); } else if (!_stretchPopUp && g_system->hasFeature(OSystem::kFeatureStretchMode)) { rebuild(); } @@ -2033,10 +2042,6 @@ void OptionsDialog::setupGraphicsTab() { _scalerPopUpDesc->setFontColor(ThemeEngine::FontColor::kFontColorOverride); _scalerPopUp->setVisible(true); _scaleFactorPopUp->setVisible(true); - } else { - _scalerPopUpDesc->setVisible(false); - _scalerPopUp->setVisible(false); - _scaleFactorPopUp->setVisible(false); } if (g_system->hasFeature(OSystem::kFeatureShaders)) { From 5f7f242239adbfb6657783583d5b9193bdb64d69 Mon Sep 17 00:00:00 2001 From: Cameron Cawley Date: Sun, 5 Feb 2023 22:05:37 +0000 Subject: [PATCH 395/412] GUI: Don't create a popup for 3D renderers if they're not supported --- gui/options.cpp | 57 ++++++++++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 24 deletions(-) diff --git a/gui/options.cpp b/gui/options.cpp index 408ad71e1502..133339b4f736 100644 --- a/gui/options.cpp +++ b/gui/options.cpp @@ -378,9 +378,6 @@ void OptionsDialog::build() { _vsyncCheckbox->setOverride(true); } - _rendererTypePopUp->setEnabled(true); - _rendererTypePopUp->setSelectedTag(Graphics::Renderer::parseTypeCode(ConfMan.get("renderer", _domain))); - _antiAliasPopUp->setEnabled(true); if (ConfMan.hasKey("antialiasing", _domain)) { _antiAliasPopUp->setSelectedTag(ConfMan.getInt("antialiasing", _domain)); @@ -464,6 +461,11 @@ void OptionsDialog::build() { } } + if (_rendererTypePopUp) { + _rendererTypePopUp->setEnabled(true); + _rendererTypePopUp->setSelectedTag(Graphics::Renderer::parseTypeCode(ConfMan.get("renderer", _domain))); + } + // Audio options if (!loadMusicDeviceSetting(_midiPopUp, "music_driver")) _midiPopUp->setSelected(0); @@ -710,11 +712,13 @@ void OptionsDialog::apply() { } } - if (_rendererTypePopUp->getSelectedTag() > 0) { - Graphics::RendererType selected = (Graphics::RendererType) _rendererTypePopUp->getSelectedTag(); - ConfMan.set("renderer", Graphics::Renderer::getTypeCode(selected), _domain); - } else { - ConfMan.removeKey("renderer", _domain); + if (_rendererTypePopUp) { + if (_rendererTypePopUp->getSelectedTag() > 0) { + Graphics::RendererType selected = (Graphics::RendererType) _rendererTypePopUp->getSelectedTag(); + ConfMan.set("renderer", Graphics::Renderer::getTypeCode(selected), _domain); + } else { + ConfMan.removeKey("renderer", _domain); + } } if (_antiAliasPopUp->getSelectedTag() != (uint32)-1) { @@ -1225,11 +1229,14 @@ void OptionsDialog::setGraphicSettingsState(bool enabled) { _gfxPopUp->setEnabled(enabled); _renderModePopUpDesc->setEnabled(enabled); _renderModePopUp->setEnabled(enabled); - _rendererTypePopUpDesc->setEnabled(enabled); - _rendererTypePopUp->setEnabled(enabled); _antiAliasPopUpDesc->setEnabled(enabled); _antiAliasPopUp->setEnabled(enabled); + if (_rendererTypePopUp) { + _rendererTypePopUpDesc->setEnabled(enabled); + _rendererTypePopUp->setEnabled(enabled); + } + if (g_system->hasFeature(OSystem::kFeatureStretchMode)) { _stretchPopUpDesc->setEnabled(enabled); _stretchPopUp->setEnabled(enabled); @@ -1646,21 +1653,23 @@ void OptionsDialog::addGraphicControls(GuiObject *boss, const Common::String &pr if (g_system->hasFeature(OSystem::kFeatureVSync)) _vsyncCheckbox = new CheckboxWidget(boss, prefix + "grVSyncCheckbox", _("V-Sync"), _("Wait for the vertical sync to refresh the screen in order to prevent tearing artifacts")); - if (g_system->getOverlayWidth() > 320) - _rendererTypePopUpDesc = new StaticTextWidget(boss, prefix + "grRendererTypePopupDesc", _("Game 3D Renderer:")); - else - _rendererTypePopUpDesc = new StaticTextWidget(boss, prefix + "grRendererTypePopupDesc", _c("Game 3D Renderer:", "lowres")); - - _rendererTypePopUp = new PopUpWidget(boss, prefix + "grRendererTypePopup"); - _rendererTypePopUp->appendEntry(_(""), Graphics::kRendererTypeDefault); - _rendererTypePopUp->appendEntry(""); Common::Array rt = Graphics::Renderer::listTypes(); - for (Common::Array::iterator it = rt.begin(); - it != rt.end(); ++it) { - if (g_system->getOverlayWidth() > 320) { - _rendererTypePopUp->appendEntry(_(it->description), it->id); - } else { - _rendererTypePopUp->appendEntry(_c(it->description, "lowres"), it->id); + if (!rt.empty()) { + if (g_system->getOverlayWidth() > 320) + _rendererTypePopUpDesc = new StaticTextWidget(boss, prefix + "grRendererTypePopupDesc", _("Game 3D Renderer:")); + else + _rendererTypePopUpDesc = new StaticTextWidget(boss, prefix + "grRendererTypePopupDesc", _c("Game 3D Renderer:", "lowres")); + + _rendererTypePopUp = new PopUpWidget(boss, prefix + "grRendererTypePopup"); + _rendererTypePopUp->appendEntry(_(""), Graphics::kRendererTypeDefault); + _rendererTypePopUp->appendEntry(""); + for (Common::Array::iterator it = rt.begin(); + it != rt.end(); ++it) { + if (g_system->getOverlayWidth() > 320) { + _rendererTypePopUp->appendEntry(_(it->description), it->id); + } else { + _rendererTypePopUp->appendEntry(_c(it->description, "lowres"), it->id); + } } } From c165cfb6e947bf450183b400013ea2d822e15eca Mon Sep 17 00:00:00 2001 From: Cameron Cawley Date: Sun, 5 Feb 2023 22:06:25 +0000 Subject: [PATCH 396/412] GUI: Don't create a popup for anti-aliasing levels if they're not supported --- gui/options.cpp | 56 ++++++++++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/gui/options.cpp b/gui/options.cpp index 133339b4f736..081cfdf7f3d3 100644 --- a/gui/options.cpp +++ b/gui/options.cpp @@ -377,13 +377,6 @@ void OptionsDialog::build() { if (ConfMan.isKeyTemporary("vsync")) _vsyncCheckbox->setOverride(true); } - - _antiAliasPopUp->setEnabled(true); - if (ConfMan.hasKey("antialiasing", _domain)) { - _antiAliasPopUp->setSelectedTag(ConfMan.getInt("antialiasing", _domain)); - } else { - _antiAliasPopUp->setSelectedTag(uint32(-1)); - } } if (_stretchPopUp) { @@ -466,6 +459,15 @@ void OptionsDialog::build() { _rendererTypePopUp->setSelectedTag(Graphics::Renderer::parseTypeCode(ConfMan.get("renderer", _domain))); } + if (_antiAliasPopUp) { + _antiAliasPopUp->setEnabled(true); + if (ConfMan.hasKey("antialiasing", _domain)) { + _antiAliasPopUp->setSelectedTag(ConfMan.getInt("antialiasing", _domain)); + } else { + _antiAliasPopUp->setSelectedTag(uint32(-1)); + } + } + // Audio options if (!loadMusicDeviceSetting(_midiPopUp, "music_driver")) _midiPopUp->setSelected(0); @@ -721,11 +723,13 @@ void OptionsDialog::apply() { } } - if (_antiAliasPopUp->getSelectedTag() != (uint32)-1) { - uint level = _antiAliasPopUp->getSelectedTag(); - ConfMan.setInt("antialiasing", level, _domain); - } else { - ConfMan.removeKey("antialiasing", _domain); + if (_antiAliasPopUp) { + if (_antiAliasPopUp->getSelectedTag() != (uint32)-1) { + uint level = _antiAliasPopUp->getSelectedTag(); + ConfMan.setInt("antialiasing", level, _domain); + } else { + ConfMan.removeKey("antialiasing", _domain); + } } } else { @@ -1229,14 +1233,17 @@ void OptionsDialog::setGraphicSettingsState(bool enabled) { _gfxPopUp->setEnabled(enabled); _renderModePopUpDesc->setEnabled(enabled); _renderModePopUp->setEnabled(enabled); - _antiAliasPopUpDesc->setEnabled(enabled); - _antiAliasPopUp->setEnabled(enabled); if (_rendererTypePopUp) { _rendererTypePopUpDesc->setEnabled(enabled); _rendererTypePopUp->setEnabled(enabled); } + if (_antiAliasPopUp) { + _antiAliasPopUpDesc->setEnabled(enabled); + _antiAliasPopUp->setEnabled(enabled); + } + if (g_system->hasFeature(OSystem::kFeatureStretchMode)) { _stretchPopUpDesc->setEnabled(enabled); _stretchPopUp->setEnabled(enabled); @@ -1673,19 +1680,16 @@ void OptionsDialog::addGraphicControls(GuiObject *boss, const Common::String &pr } } - _antiAliasPopUpDesc = new StaticTextWidget(boss, prefix + "grAntiAliasPopupDesc", _("3D Anti-aliasing:")); - _antiAliasPopUp = new PopUpWidget(boss, prefix + "grAntiAliasPopup"); - _antiAliasPopUp->appendEntry(_(""), uint32(-1)); - _antiAliasPopUp->appendEntry(""); - _antiAliasPopUp->appendEntry(_("Disabled"), 0); const Common::Array levels = g_system->getSupportedAntiAliasingLevels(); - for (uint i = 0; i < levels.size(); i++) { - _antiAliasPopUp->appendEntry(Common::String::format("%dx", levels[i]), levels[i]); - } - if (levels.empty()) { - // Don't show the anti-aliasing selection menu when it is not supported - _antiAliasPopUpDesc->setVisible(false); - _antiAliasPopUp->setVisible(false); + if (!levels.empty()) { + _antiAliasPopUpDesc = new StaticTextWidget(boss, prefix + "grAntiAliasPopupDesc", _("3D Anti-aliasing:")); + _antiAliasPopUp = new PopUpWidget(boss, prefix + "grAntiAliasPopup"); + _antiAliasPopUp->appendEntry(_(""), uint32(-1)); + _antiAliasPopUp->appendEntry(""); + _antiAliasPopUp->appendEntry(_("Disabled"), 0); + for (uint i = 0; i < levels.size(); i++) { + _antiAliasPopUp->appendEntry(Common::String::format("%dx", levels[i]), levels[i]); + } } // Filtering checkbox From d2384b7db3699abbff1a1c38b63e78251c8ca01d Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Sun, 5 Feb 2023 16:36:43 -0800 Subject: [PATCH 397/412] MM: MM1: Fix display of 'H-Orc' race in char info --- devtools/create_mm/files/mm1/strings_en.yml | 80 ++++++++++----------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/devtools/create_mm/files/mm1/strings_en.yml b/devtools/create_mm/files/mm1/strings_en.yml index 10cd46e8237f..f2e302d1f758 100644 --- a/devtools/create_mm/files/mm1/strings_en.yml +++ b/devtools/create_mm/files/mm1/strings_en.yml @@ -491,29 +491,29 @@ enhdialogs: uncurse: "\x01""37uncurse" realign: "\x01""37re-align" stats: - none: "none" - inventory: "-------------------" + none: "None" + inventory: "-------------------" classes: - 1: "knight" - 2: "paladin" - 3: "archer" - 4: "cleric" - 5: "sorcerer" - 6: "robber" + 1: "Knight" + 2: "Paladin" + 3: "Archer" + 4: "Cleric" + 5: "Sorcerer" + 6: "Robber" races: - 1: "human" - 2: "elf" - 3: "dwarf" - 4: "gnome" - 5: "half-orc" + 1: "Human" + 2: "Elf" + 3: "Dwarf" + 4: "Gnome" + 5: "H-Orc" alignments: - 1: "good" - 2: "neut" - 3: "evil" + 1: "Good" + 2: "Neut" + 3: "Evil" sex: - 1: "male" - 2: "female" - 3: "yes please" + 1: "Male" + 2: "Female" + 3: "Yes Please" conditions: good: "good" eradicated: "eradicated" @@ -527,29 +527,29 @@ stats: blinded: "blinded," asleep: "asleep," attributes: - int: "int=" - level: "level=" - age: "age=" - exp: "exp=" - mgt: "mgt=" - per: "per=" - sp: "sp=" - gems: "gems=" - end: "end=" - spd: "spd=" - hp: "hp=" - gold: "gold=" - acy: "acy=" - luc: "luc=" + int: "Int=" + level: "lEvel=" + age: "Age=" + exp: "Exp=" + mgt: "Mgt=" + per: "Per=" + sp: "Xp=" + gems: "Gems=" + end: "End=" + spd: "Spd=" + hp: "Hp=" + gold: "Gold=" + acy: "Acy=" + luc: "Luc=" ac: "ac=" - food: "food=" - cond: "cond=" + food: "Food=" + cond: "Cond=" towns: - 1: "sorpigal" - 2: "portsmith" - 3: "algary" - 4: "dusk" - 5: "erliquin" + 1: "Sorpigal" + 2: "Portsmith" + 3: "Algary" + 4: "Dusk" + 5: "Erliquin" items: 1: "club" 2: "dagger" From 626388a9027216596278bd2fe3b547e9444ab5f9 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Sun, 5 Feb 2023 17:49:34 -0800 Subject: [PATCH 398/412] MM: MM1: Fix some combat messages, party display --- devtools/create_mm/files/mm1/strings_en.yml | 14 +++++++------- engines/mm/mm1/game/combat.cpp | 14 +++++++------- engines/mm/mm1/views/combat.cpp | 11 ++++++++--- engines/mm/mm1/views/quick_ref.cpp | 8 +++----- 4 files changed, 25 insertions(+), 22 deletions(-) diff --git a/devtools/create_mm/files/mm1/strings_en.yml b/devtools/create_mm/files/mm1/strings_en.yml index f2e302d1f758..d6016ba47c5e 100644 --- a/devtools/create_mm/files/mm1/strings_en.yml +++ b/devtools/create_mm/files/mm1/strings_en.yml @@ -392,6 +392,13 @@ dialogs: delay_currently: "(currently= %d)" infiltration: "infiltrates the ranks!" exchange_places: "exchange places with (1-%c)?" + takes: "takes " + point: "point" + points: "points" + of_damage: "of damage!" + goes_down: "goes down!!!" + and_goes_down: "and goes down!!!" + dies: "dies!" status: 0: "(paralyze)" 1: "(webbed) " @@ -873,13 +880,6 @@ monster_spells: casts: "casts " fails_to_cast: "fails to cast a spell" not_affected: "is not affected!" - takes: "takes " - point: "point" - points: "points" - of_damage: "of damage!" - goes_down: "goes down!!!" - and_goes_down: "and goes down!!!" - dies: "dies!" breathes: "breathes" a_curse: "a curse" energy_blast: "energy blast" diff --git a/engines/mm/mm1/game/combat.cpp b/engines/mm/mm1/game/combat.cpp index 8a150b2d4d33..9c7f12eeba33 100644 --- a/engines/mm/mm1/game/combat.cpp +++ b/engines/mm/mm1/game/combat.cpp @@ -1009,7 +1009,7 @@ void Combat::iterateMonsters2() { void Combat::iterateMonsters2Inner() { Encounter &enc = g_globals->_encounters; - Common::String line1 = Common::String::format("|%s| %s", + Common::String line1 = Common::String::format("%s %s", g_globals->_currCharacter->_name, STRING["spells.casts_spell"].c_str()); const Common::String monsterName = _monsterP->_name; @@ -1052,16 +1052,16 @@ void Combat::iterateMonsters2Inner() { } else { Common::String line2 = Common::String::format("%s %s %d %s %s", monsterName.c_str(), - STRING["monster_spells.takes"].c_str(), + STRING["dialogs.combat.takes"].c_str(), _damage, - STRING[_damage == 1 ? "monster_spells.point" : "monster_spells.points"].c_str(), - STRING["monster_spells.of_damage"].c_str() + STRING[_damage == 1 ? "dialogs.combat.point" : "dialogs.combat.points"].c_str(), + STRING["dialogs.combat.of_damage"].c_str() ); msg._lines.push_back(Line(0, 1, line2)); if (_damage >= enc._monsterList[getMonsterIndex()]._hp) { - msg._lines.push_back(Line(0, 2, STRING["monster_spells.and_goes_down"])); + msg._lines.push_back(Line(0, 2, STRING["dialogs.combat.and_goes_down"])); } } @@ -1650,7 +1650,7 @@ Common::String Combat::subtractDamageFromChar() { c._condition |= UNCONSCIOUS; result = Common::String::format("%s %s", c._name, - STRING["monster_spellsState.goes_down"].c_str()); + STRING["dialogs.combat.goes_down"].c_str()); Sound::sound2(SOUND_8); } else { @@ -1658,7 +1658,7 @@ Common::String Combat::subtractDamageFromChar() { c._condition = BAD_CONDITION | DEAD; result = Common::String::format("%s %s", c._name, - STRING["monster_spellsState.dies"].c_str()); + STRING["dialogs.combat.dies"].c_str()); Sound::sound2(SOUND_8); } } diff --git a/engines/mm/mm1/views/combat.cpp b/engines/mm/mm1/views/combat.cpp index ae0a58f5781d..1e4ab7a49cee 100644 --- a/engines/mm/mm1/views/combat.cpp +++ b/engines/mm/mm1/views/combat.cpp @@ -568,9 +568,14 @@ void Combat::writeParty() { clearPartyArea(); for (uint i = 0; i < g_globals->_combatParty.size(); ++i) { - writeChar(1 + 21 * (i % 2), 16 + (i / 2), '1' + i); - writeString(") "); - writeString(g_globals->_combatParty[i]->_name); + const Character &c = *g_globals->_combatParty[i]; + writeString(21 * (i % 2), 16 + (i / 2), + Common::String::format("%c%c) %s", + (c._condition == 0) ? ' ' : '*', + '1' + i, + c._name + ) + ); } } diff --git a/engines/mm/mm1/views/quick_ref.cpp b/engines/mm/mm1/views/quick_ref.cpp index 41d9bdaea08d..cae2c8d38a16 100644 --- a/engines/mm/mm1/views/quick_ref.cpp +++ b/engines/mm/mm1/views/quick_ref.cpp @@ -74,8 +74,8 @@ void QuickRef::draw() { // Print food and conditions of each character for (uint idx = 0; idx < g_globals->_party.size(); ++idx) { - Character &c = g_globals->_party[idx]; - g_globals->_currCharacter = &c; + Character &c = inCombat ? *g_globals->_combatParty[idx] : + g_globals->_party[idx]; writeNumber(0, 9 + idx, idx + 1); _textPos.x++; @@ -135,9 +135,7 @@ bool QuickRef::isInCombat() const { } size_t QuickRef::getPartySize() const { - bool inCombat = isInCombat(); - return inCombat ? g_globals->_combatParty.size() : - g_globals->_party.size(); + return g_globals->_party.size(); } } // namespace Views From 1cb89679dc14d569a1503bff0b5955198942c0e8 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Sun, 5 Feb 2023 18:11:28 -0800 Subject: [PATCH 399/412] MM: MM1: Fix incapicated chars are skipped in combat --- engines/mm/mm1/game/combat.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/engines/mm/mm1/game/combat.cpp b/engines/mm/mm1/game/combat.cpp index 9c7f12eeba33..e6a1d56a1ac0 100644 --- a/engines/mm/mm1/game/combat.cpp +++ b/engines/mm/mm1/game/combat.cpp @@ -281,7 +281,8 @@ void Combat::combatLoop(bool checkMonstersFirst) { _currentChar = i; g_globals->_currCharacter = &c; - if (!(c._condition & (BLINDED | SILENCED | DISEASED | POISONED))) { + if (!(c._condition & (BAD_CONDITION | UNCONSCIOUS | + PARALYZED | ASLEEP))) { // Character is enabled setMode(SELECT_OPTION); return; From c0a6a7d0f61f73d6ddefce462d19e333a00cc8bc Mon Sep 17 00:00:00 2001 From: D G Turner Date: Mon, 6 Feb 2023 02:38:20 +0000 Subject: [PATCH 400/412] EFH: Fix Various GCC Compiler Warnings --- engines/efh/constants.cpp | 192 +++++++++++++++++++------------------- engines/efh/init.cpp | 16 ++-- 2 files changed, 105 insertions(+), 103 deletions(-) diff --git a/engines/efh/constants.cpp b/engines/efh/constants.cpp index a261703b8f4f..1bf4fad0a1ae 100644 --- a/engines/efh/constants.cpp +++ b/engines/efh/constants.cpp @@ -34,102 +34,102 @@ const uint8 kFontExtraLinesArray[96] = { 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 0, 1, 0, 0}; const Font kFontData[96] = { - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x80, 0x00}, - {0xA0, 0xA0, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x50, 0xF8, 0x50, 0xF8, 0x50, 0x00, 0x00}, - {0x20, 0x78, 0xA0, 0x70, 0x28, 0xF0, 0x20, 0x00}, - {0xC8, 0xC8, 0x10, 0x20, 0x40, 0x98, 0x98, 0x00}, - {0x20, 0x50, 0x20, 0x40, 0xA8, 0x90, 0x68, 0x00}, - {0x40, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x40, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x40}, - {0x40, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x40}, - {0x00, 0xA8, 0x70, 0xF8, 0x70, 0xA8, 0x00, 0x00}, - {0x00, 0x20, 0x20, 0xF8, 0x20, 0x20, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x40}, - {0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00}, - {0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00}, - {0x60, 0x90, 0x90, 0x90, 0x90, 0x90, 0x60, 0x00}, - {0x40, 0xC0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00}, - {0x60, 0x90, 0x10, 0x20, 0x40, 0x80, 0xF0, 0x00}, - {0x60, 0x90, 0x10, 0x20, 0x10, 0x90, 0x60, 0x00}, - {0x10, 0x30, 0x50, 0x90, 0xF8, 0x10, 0x10, 0x00}, - {0xF0, 0x80, 0xE0, 0x10, 0x10, 0x90, 0x60, 0x00}, - {0x60, 0x90, 0x80, 0xE0, 0x90, 0x90, 0x60, 0x00}, - {0xF0, 0x10, 0x20, 0x20, 0x40, 0x40, 0x40, 0x00}, - {0x60, 0x90, 0x90, 0x60, 0x90, 0x90, 0x60, 0x00}, - {0x60, 0x90, 0x90, 0x70, 0x10, 0x90, 0x60, 0x00}, - {0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00}, - {0x00, 0x00, 0x20, 0x00, 0x00, 0x20, 0x40, 0x00}, - {0x10, 0x20, 0x40, 0x80, 0x40, 0x20, 0x10, 0x00}, - {0x00, 0x00, 0xF8, 0x00, 0x00, 0xF8, 0x00, 0x00}, - {0x80, 0x40, 0x20, 0x10, 0x20, 0x40, 0x80, 0x00}, - {0x70, 0x88, 0x08, 0x10, 0x20, 0x00, 0x20, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x60, 0x90, 0x90, 0xF0, 0x90, 0x90, 0x90, 0x00}, - {0xE0, 0x90, 0x90, 0xE0, 0x90, 0x90, 0xE0, 0x00}, - {0x60, 0x90, 0x80, 0x80, 0x80, 0x90, 0x60, 0x00}, - {0xE0, 0x90, 0x90, 0x90, 0x90, 0x90, 0xE0, 0x00}, - {0xF0, 0x80, 0x80, 0xE0, 0x80, 0x80, 0xF0, 0x00}, - {0xF0, 0x80, 0x80, 0xE0, 0x80, 0x80, 0x80, 0x00}, - {0x60, 0x90, 0x80, 0xB0, 0x90, 0x90, 0x70, 0x00}, - {0x90, 0x90, 0x90, 0xF0, 0x90, 0x90, 0x90, 0x00}, - {0xE0, 0x40, 0x40, 0x40, 0x40, 0x40, 0xE0, 0x00}, - {0x10, 0x10, 0x10, 0x10, 0x10, 0x90, 0x60, 0x00}, - {0x90, 0x90, 0x90, 0xE0, 0x90, 0x90, 0x90, 0x00}, - {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xF0, 0x00}, - {0x82, 0xC6, 0xAA, 0x92, 0x82, 0x82, 0x82, 0x00}, - {0x88, 0x88, 0xC8, 0xA8, 0x98, 0x88, 0x88, 0x00}, - {0x60, 0x90, 0x90, 0x90, 0x90, 0x90, 0x60, 0x00}, - {0xE0, 0x90, 0x90, 0xE0, 0x80, 0x80, 0x80, 0x00}, - {0x60, 0x90, 0x90, 0x90, 0x90, 0x90, 0x60, 0x10}, - {0xE0, 0x90, 0x90, 0xE0, 0x90, 0x90, 0x90, 0x00}, - {0x60, 0x90, 0x80, 0x60, 0x10, 0x90, 0x60, 0x00}, - {0xF8, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00}, - {0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x60, 0x00}, - {0x88, 0x88, 0x88, 0x50, 0x50, 0x20, 0x20, 0x00}, - {0x82, 0x82, 0x82, 0x92, 0xAA, 0xC6, 0x82, 0x00}, - {0x88, 0x88, 0x50, 0x20, 0x50, 0x88, 0x88, 0x00}, - {0x88, 0x88, 0x50, 0x20, 0x20, 0x20, 0x20, 0x00}, - {0xF8, 0x08, 0x10, 0x20, 0x40, 0x80, 0xF8, 0x00}, - {0xC0, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xC0}, - {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x00}, - {0x60, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x60}, - {0x20, 0x50, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x80, 0x80, 0x40, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x60, 0x10, 0x70, 0x90, 0x70, 0x00}, - {0x80, 0x80, 0xE0, 0x90, 0x90, 0x90, 0xE0, 0x00}, - {0x00, 0x00, 0x60, 0x90, 0x80, 0x90, 0x60, 0x00}, - {0x10, 0x10, 0x70, 0x90, 0x90, 0x90, 0x70, 0x00}, - {0x00, 0x00, 0x60, 0x90, 0xF0, 0x80, 0x60, 0x00}, - {0x30, 0x40, 0xE0, 0x40, 0x40, 0x40, 0x40, 0x00}, - {0x70, 0x90, 0x90, 0x90, 0x70, 0x10, 0xE0, 0x00}, - {0x80, 0x80, 0xE0, 0x90, 0x90, 0x90, 0x90, 0x00}, - {0x80, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00}, - {0x40, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x80}, - {0x80, 0x80, 0x90, 0x90, 0xE0, 0x90, 0x90, 0x00}, - {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00}, - {0x00, 0x00, 0xEC, 0x92, 0x92, 0x92, 0x92, 0x00}, - {0x00, 0x00, 0xE0, 0x90, 0x90, 0x90, 0x90, 0x00}, - {0x00, 0x00, 0x60, 0x90, 0x90, 0x90, 0x60, 0x00}, - {0x00, 0xE0, 0x90, 0x90, 0x90, 0xE0, 0x80, 0x80}, - {0x00, 0x70, 0x90, 0x90, 0x90, 0x70, 0x10, 0x10}, - {0x00, 0x00, 0xB0, 0xC0, 0x80, 0x80, 0x80, 0x00}, - {0x00, 0x00, 0x70, 0x80, 0x60, 0x10, 0xE0, 0x00}, - {0x40, 0x40, 0xE0, 0x40, 0x40, 0x40, 0x40, 0x00}, - {0x00, 0x00, 0x90, 0x90, 0x90, 0x90, 0x70, 0x00}, - {0x00, 0x00, 0x88, 0x50, 0x50, 0x20, 0x20, 0x00}, - {0x00, 0x00, 0x92, 0x92, 0x92, 0x92, 0x6E, 0x00}, - {0x00, 0x00, 0x90, 0x90, 0x60, 0x90, 0x90, 0x00}, - {0x00, 0x90, 0x90, 0x90, 0x90, 0x70, 0x10, 0xE0}, - {0x00, 0x00, 0xF8, 0x10, 0x20, 0x40, 0xF8, 0x00}, - {0x20, 0x40, 0x40, 0x80, 0x40, 0x40, 0x20, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x80, 0x40, 0x40, 0x20, 0x40, 0x40, 0x80, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x80, 0x00}}, + {{0xA0, 0xA0, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x00, 0x50, 0xF8, 0x50, 0xF8, 0x50, 0x00, 0x00}}, + {{0x20, 0x78, 0xA0, 0x70, 0x28, 0xF0, 0x20, 0x00}}, + {{0xC8, 0xC8, 0x10, 0x20, 0x40, 0x98, 0x98, 0x00}}, + {{0x20, 0x50, 0x20, 0x40, 0xA8, 0x90, 0x68, 0x00}}, + {{0x40, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x40, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x40}}, + {{0x40, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x40}}, + {{0x00, 0xA8, 0x70, 0xF8, 0x70, 0xA8, 0x00, 0x00}}, + {{0x00, 0x20, 0x20, 0xF8, 0x20, 0x20, 0x00, 0x00}}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x40}}, + {{0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x00}}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00}}, + {{0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00}}, + {{0x60, 0x90, 0x90, 0x90, 0x90, 0x90, 0x60, 0x00}}, + {{0x40, 0xC0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00}}, + {{0x60, 0x90, 0x10, 0x20, 0x40, 0x80, 0xF0, 0x00}}, + {{0x60, 0x90, 0x10, 0x20, 0x10, 0x90, 0x60, 0x00}}, + {{0x10, 0x30, 0x50, 0x90, 0xF8, 0x10, 0x10, 0x00}}, + {{0xF0, 0x80, 0xE0, 0x10, 0x10, 0x90, 0x60, 0x00}}, + {{0x60, 0x90, 0x80, 0xE0, 0x90, 0x90, 0x60, 0x00}}, + {{0xF0, 0x10, 0x20, 0x20, 0x40, 0x40, 0x40, 0x00}}, + {{0x60, 0x90, 0x90, 0x60, 0x90, 0x90, 0x60, 0x00}}, + {{0x60, 0x90, 0x90, 0x70, 0x10, 0x90, 0x60, 0x00}}, + {{0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00}}, + {{0x00, 0x00, 0x20, 0x00, 0x00, 0x20, 0x40, 0x00}}, + {{0x10, 0x20, 0x40, 0x80, 0x40, 0x20, 0x10, 0x00}}, + {{0x00, 0x00, 0xF8, 0x00, 0x00, 0xF8, 0x00, 0x00}}, + {{0x80, 0x40, 0x20, 0x10, 0x20, 0x40, 0x80, 0x00}}, + {{0x70, 0x88, 0x08, 0x10, 0x20, 0x00, 0x20, 0x00}}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x60, 0x90, 0x90, 0xF0, 0x90, 0x90, 0x90, 0x00}}, + {{0xE0, 0x90, 0x90, 0xE0, 0x90, 0x90, 0xE0, 0x00}}, + {{0x60, 0x90, 0x80, 0x80, 0x80, 0x90, 0x60, 0x00}}, + {{0xE0, 0x90, 0x90, 0x90, 0x90, 0x90, 0xE0, 0x00}}, + {{0xF0, 0x80, 0x80, 0xE0, 0x80, 0x80, 0xF0, 0x00}}, + {{0xF0, 0x80, 0x80, 0xE0, 0x80, 0x80, 0x80, 0x00}}, + {{0x60, 0x90, 0x80, 0xB0, 0x90, 0x90, 0x70, 0x00}}, + {{0x90, 0x90, 0x90, 0xF0, 0x90, 0x90, 0x90, 0x00}}, + {{0xE0, 0x40, 0x40, 0x40, 0x40, 0x40, 0xE0, 0x00}}, + {{0x10, 0x10, 0x10, 0x10, 0x10, 0x90, 0x60, 0x00}}, + {{0x90, 0x90, 0x90, 0xE0, 0x90, 0x90, 0x90, 0x00}}, + {{0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xF0, 0x00}}, + {{0x82, 0xC6, 0xAA, 0x92, 0x82, 0x82, 0x82, 0x00}}, + {{0x88, 0x88, 0xC8, 0xA8, 0x98, 0x88, 0x88, 0x00}}, + {{0x60, 0x90, 0x90, 0x90, 0x90, 0x90, 0x60, 0x00}}, + {{0xE0, 0x90, 0x90, 0xE0, 0x80, 0x80, 0x80, 0x00}}, + {{0x60, 0x90, 0x90, 0x90, 0x90, 0x90, 0x60, 0x10}}, + {{0xE0, 0x90, 0x90, 0xE0, 0x90, 0x90, 0x90, 0x00}}, + {{0x60, 0x90, 0x80, 0x60, 0x10, 0x90, 0x60, 0x00}}, + {{0xF8, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00}}, + {{0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x60, 0x00}}, + {{0x88, 0x88, 0x88, 0x50, 0x50, 0x20, 0x20, 0x00}}, + {{0x82, 0x82, 0x82, 0x92, 0xAA, 0xC6, 0x82, 0x00}}, + {{0x88, 0x88, 0x50, 0x20, 0x50, 0x88, 0x88, 0x00}}, + {{0x88, 0x88, 0x50, 0x20, 0x20, 0x20, 0x20, 0x00}}, + {{0xF8, 0x08, 0x10, 0x20, 0x40, 0x80, 0xF8, 0x00}}, + {{0xC0, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xC0}}, + {{0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x00}}, + {{0x60, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x60}}, + {{0x20, 0x50, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x00, 0x00, 0x80, 0x80, 0x40, 0x00, 0x00, 0x00}}, + {{0x00, 0x00, 0x60, 0x10, 0x70, 0x90, 0x70, 0x00}}, + {{0x80, 0x80, 0xE0, 0x90, 0x90, 0x90, 0xE0, 0x00}}, + {{0x00, 0x00, 0x60, 0x90, 0x80, 0x90, 0x60, 0x00}}, + {{0x10, 0x10, 0x70, 0x90, 0x90, 0x90, 0x70, 0x00}}, + {{0x00, 0x00, 0x60, 0x90, 0xF0, 0x80, 0x60, 0x00}}, + {{0x30, 0x40, 0xE0, 0x40, 0x40, 0x40, 0x40, 0x00}}, + {{0x70, 0x90, 0x90, 0x90, 0x70, 0x10, 0xE0, 0x00}}, + {{0x80, 0x80, 0xE0, 0x90, 0x90, 0x90, 0x90, 0x00}}, + {{0x80, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00}}, + {{0x40, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x80}}, + {{0x80, 0x80, 0x90, 0x90, 0xE0, 0x90, 0x90, 0x00}}, + {{0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00}}, + {{0x00, 0x00, 0xEC, 0x92, 0x92, 0x92, 0x92, 0x00}}, + {{0x00, 0x00, 0xE0, 0x90, 0x90, 0x90, 0x90, 0x00}}, + {{0x00, 0x00, 0x60, 0x90, 0x90, 0x90, 0x60, 0x00}}, + {{0x00, 0xE0, 0x90, 0x90, 0x90, 0xE0, 0x80, 0x80}}, + {{0x00, 0x70, 0x90, 0x90, 0x90, 0x70, 0x10, 0x10}}, + {{0x00, 0x00, 0xB0, 0xC0, 0x80, 0x80, 0x80, 0x00}}, + {{0x00, 0x00, 0x70, 0x80, 0x60, 0x10, 0xE0, 0x00}}, + {{0x40, 0x40, 0xE0, 0x40, 0x40, 0x40, 0x40, 0x00}}, + {{0x00, 0x00, 0x90, 0x90, 0x90, 0x90, 0x70, 0x00}}, + {{0x00, 0x00, 0x88, 0x50, 0x50, 0x20, 0x20, 0x00}}, + {{0x00, 0x00, 0x92, 0x92, 0x92, 0x92, 0x6E, 0x00}}, + {{0x00, 0x00, 0x90, 0x90, 0x60, 0x90, 0x90, 0x00}}, + {{0x00, 0x90, 0x90, 0x90, 0x90, 0x70, 0x10, 0xE0}}, + {{0x00, 0x00, 0xF8, 0x10, 0x20, 0x40, 0xF8, 0x00}}, + {{0x20, 0x40, 0x40, 0x80, 0x40, 0x40, 0x20, 0x00}}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x80, 0x40, 0x40, 0x20, 0x40, 0x40, 0x80, 0x00}}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}} }; const Encounter kEncounters[] { diff --git a/engines/efh/init.cpp b/engines/efh/init.cpp index 448650c72018..b7511a1da811 100644 --- a/engines/efh/init.cpp +++ b/engines/efh/init.cpp @@ -371,21 +371,23 @@ EfhEngine::EfhEngine(OSystem *syst, const ADGameDescription *gd) : Engine(syst), memset(_places, 0, ARRAYSIZE(_places)); for (int i = 0; i < 24; ++i) memset(_curPlace[i], 0, ARRAYSIZE(_curPlace[i])); - memset(_npcBuf, 0, ARRAYSIZE(_npcBuf)); + memset(_npcBuf, 0, ARRAYSIZE(_npcBuf)*sizeof(NPCStruct)); memset(_imp1, 0, ARRAYSIZE(_imp1)); memset(_imp2, 0, ARRAYSIZE(_imp2)); memset(_titleSong, 0, ARRAYSIZE(_titleSong)); - memset(_items, 0, ARRAYSIZE(_items)); - memset(_tileFact, 0, ARRAYSIZE(_tileFact)); - memset(_animInfo, 0, ARRAYSIZE(_animInfo)); + memset(_items, 0, ARRAYSIZE(_items)*sizeof(ItemStruct)); + memset(_tileFact, 0, ARRAYSIZE(_tileFact)*sizeof(TileFactStruct)); + memset(_animInfo, 0, ARRAYSIZE(_animInfo)*sizeof(AnimInfo)); memset(_history, 0, ARRAYSIZE(_history)); for (int i = 0; i < 19; ++i) { memset(_techDataArr[i], 0, ARRAYSIZE(_techDataArr[i])); memset(_mapArr[i], 0, ARRAYSIZE(_mapArr[i])); - memset(_mapMonsters[i], 0, ARRAYSIZE(_mapMonsters[i])); - memset(_mapGameMaps[i], 0, ARRAYSIZE(_mapGameMaps[i])); + memset(_mapMonsters[i], 0, ARRAYSIZE(_mapMonsters[i])*sizeof(MapMonster)); + for (int j = 0; j < 64; ++j) { + memset(_mapGameMaps[i][j], 0, ARRAYSIZE(_mapGameMaps[i][j])); + } } - memset(_tileBankSubFilesArray, 0, ARRAYSIZE(_tileBankSubFilesArray)); + memset(_tileBankSubFilesArray, 0, ARRAYSIZE(_tileBankSubFilesArray)*sizeof(uint8 *)); _regenCounter = 0; // If requested, load a savegame instead of showing the intro From 95bf4b15b355214d754f16642d203c6baddf1f2f Mon Sep 17 00:00:00 2001 From: D G Turner Date: Mon, 6 Feb 2023 03:57:01 +0000 Subject: [PATCH 401/412] EFH: Fix Most Remaining GCC Compiler Warnings Two warnings of -Wcast-qual remain, but these are problematic to fix with major refactoring of script parser. --- engines/efh/efh.cpp | 2 +- engines/efh/fight.cpp | 6 ++++-- engines/efh/menu.cpp | 2 +- engines/efh/script.cpp | 2 +- engines/efh/sound.cpp | 2 +- 5 files changed, 8 insertions(+), 6 deletions(-) diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp index 5c167b68172a..442ea75beb24 100644 --- a/engines/efh/efh.cpp +++ b/engines/efh/efh.cpp @@ -1309,7 +1309,7 @@ int8 EfhEngine::checkMonsterMoveCollisionAndTileTexture(int16 monsterId) { int16 maxSize = _largeMapFlag ? 63 : 23; MapMonster *curMapMonster = &_mapMonsters[_techId][monsterId]; - if (curMapMonster->_posX < 0 || curMapMonster->_posY < 0 || curMapMonster->_posX > maxSize || curMapMonster->_posY > maxSize) + if (curMapMonster->_posX > maxSize || curMapMonster->_posY > maxSize) return 0; if (curMapMonster->_posX == _mapPosX && curMapMonster->_posY == _mapPosY) diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index c36361fb05bb..5c591442758c 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -982,10 +982,10 @@ int16 EfhEngine::determineTeamTarget(int16 charId, int16 unkFied18Val, bool chec case 3: case 2: ++realRange; - // no break on purpose + // fall through case 1: ++realRange; - // no break on purpose + // fall through case 0: ++realRange; break; @@ -1495,6 +1495,8 @@ bool EfhEngine::checkSpecialItemsOnCurrentPlace(int16 itemId) { case 1: if ((itemId >= 0x58 && itemId <= 0x68) || (itemId >= 0x86 && itemId <= 0x89) || (itemId >= 0x74 && itemId <= 0x76) || itemId == 0x8C) retVal = false; + // fall through + // FIXME: Is this intentional? case 2: if ((itemId >= 0x61 && itemId <= 0x63) || (itemId >= 0x74 && itemId <= 0x76) || (itemId >= 0x86 && itemId <= 0x89) || itemId == 0x5B || itemId == 0x5E || itemId == 0x66 || itemId == 0x68 || itemId == 0x8C) retVal = false; diff --git a/engines/efh/menu.cpp b/engines/efh/menu.cpp index a939521a0051..2b2a8c4410bd 100644 --- a/engines/efh/menu.cpp +++ b/engines/efh/menu.cpp @@ -1269,7 +1269,7 @@ int16 EfhEngine::useObject(int16 charId, int16 objectId, int16 teamMonsterId, in uint8 varAE = _items[itemId]._defenseType; uint8 effectPoints = getRandom(_items[itemId]._field19_mapPosX_or_maxDeltaPoints); _npcBuf[_teamChar[teamCharId]._id]._activeScore[varAE] -= effectPoints; - if (_npcBuf[_teamChar[teamCharId]._id]._activeScore[varAE] > 20 || _npcBuf[_teamChar[teamCharId]._id]._activeScore[varAE] < 0) { + if (_npcBuf[_teamChar[teamCharId]._id]._activeScore[varAE] > 20) { _npcBuf[_teamChar[teamCharId]._id]._activeScore[varAE] = 1; } if (effectPoints > 1) diff --git a/engines/efh/script.cpp b/engines/efh/script.cpp index 02710da2989b..1495d9e9c23f 100644 --- a/engines/efh/script.cpp +++ b/engines/efh/script.cpp @@ -477,7 +477,7 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos } } - if (curLine.size() >= 0 && curLineNb < numbLines && !noTextFlag) + if (curLineNb < numbLines && !noTextFlag) displayStringAtTextPos(curLine); if (joiningNpcId != 0xFF) { diff --git a/engines/efh/sound.cpp b/engines/efh/sound.cpp index e0b0181cabe1..757cc4268b77 100644 --- a/engines/efh/sound.cpp +++ b/engines/efh/sound.cpp @@ -24,7 +24,7 @@ namespace Efh { void EfhEngine::songDelay(int delay) { - debugC(3, kDebugEngine, "songDelay %ld", delay); + debugC(3, kDebugEngine, "songDelay %d", delay); int remainingDelay = delay / 2; while (remainingDelay > 0 && !shouldQuit()) { From dba9d52d4079ebbeeffd4a80ea3d1b9be9ad99b1 Mon Sep 17 00:00:00 2001 From: D G Turner Date: Mon, 6 Feb 2023 04:27:49 +0000 Subject: [PATCH 402/412] IMMORTAL: Fix Various GCC Compiler Warnings --- engines/immortal/disk.cpp | 2 ++ engines/immortal/flameSet.cpp | 8 ++++---- engines/immortal/kernal.cpp | 2 +- engines/immortal/level.cpp | 10 +++++----- engines/immortal/logic.cpp | 8 ++++---- 5 files changed, 16 insertions(+), 14 deletions(-) diff --git a/engines/immortal/disk.cpp b/engines/immortal/disk.cpp index 1e706f56f5d5..1a757e0392b1 100644 --- a/engines/immortal/disk.cpp +++ b/engines/immortal/disk.cpp @@ -271,6 +271,8 @@ void ProDOSDisk::getFileEntry(FileEntry *f) { */ void ProDOSDisk::searchDirectory(DirHeader *h, uint16 p, uint16 n, Common::String path) { + // NB: p for previous set, but not currently used. This debug message silences any set-but-unused compiler warnings + debug(10, "searchDirectory(h:%p prev: %d next:%d, path:%s", (void *)h, p, n, path.c_str()); int currPos; int parsedFiles = 0; diff --git a/engines/immortal/flameSet.cpp b/engines/immortal/flameSet.cpp index 8bb4ec3abce6..98842e26b409 100644 --- a/engines/immortal/flameSet.cpp +++ b/engines/immortal/flameSet.cpp @@ -46,7 +46,7 @@ void Room::flameFreeAll() { } void Room::flameDrawAll(uint16 vX, uint16 vY) { - for (int i = 0; i < _fset.size(); i++) { + for (uint i = 0; i < _fset.size(); i++) { // For every flame in the room, add the sprite to the sprite table univAddSprite(vX, vY, _fset[i]._x, _fset[i]._y, g_immortal->_cycPtrs[g_immortal->_cycles[_fset[i]._c]._cycList]._sName, cycleGetFrame(_fset[i]._c), 0); if (cycleAdvance(_fset[i]._c) == true) { @@ -61,7 +61,7 @@ bool Room::roomLighted() { return true; // Very simple, just checks every torch and if any of them are lit, we say the room is lit - for (int i = 0; i < _fset.size(); i++) { + for (uint i = 0; i < _fset.size(); i++) { if (_fset[i]._p != kFlameOff) { return true; } @@ -78,7 +78,7 @@ void Room::lightTorch(uint8 x, uint8 y) { * check both x,y and flame pattern. Neato. */ - for (int i = 0; i < _fset.size(); i++) { + for (uint i = 0; i < _fset.size(); i++) { if (_fset[i]._p == kFlameOff) { if (Utilities::inside(kLightTorchX, x, y, _fset[i]._x + 16, _fset[i]._y + 8)) { _fset[i]._p = kFlameNormal; @@ -89,7 +89,7 @@ void Room::lightTorch(uint8 x, uint8 y) { } void Room::flameSetRoom(Common::Array &allFlames) { - for (int i = 0; i < allFlames.size(); i++) { + for (uint i = 0; i < allFlames.size(); i++) { Flame f; f._p = allFlames[i]._p; f._x = allFlames[i]._x; diff --git a/engines/immortal/kernal.cpp b/engines/immortal/kernal.cpp index 2db5382ed75d..f22568532335 100644 --- a/engines/immortal/kernal.cpp +++ b/engines/immortal/kernal.cpp @@ -900,7 +900,7 @@ void ImmortalEngine::fade(uint16 pal[], int dir, int delay) { // Originally used a branch, but this is functionally identical and much cleaner count = dir * 256; - while ((count >= 0) && (count <= 256)) { + while (count <= 256) { fadePal(pal, count, target); Utilities::delay8(delay); setColors(target); diff --git a/engines/immortal/level.cpp b/engines/immortal/level.cpp index 1fa299e72ae6..5b114de97fa3 100644 --- a/engines/immortal/level.cpp +++ b/engines/immortal/level.cpp @@ -69,16 +69,16 @@ void ImmortalEngine::levelLoadFile(int l) { // Create the rooms and doors, then populate the rooms with their objects and actors - for (int d = 0; d < _stories[l]._doors.size(); d++) { + for (uint d = 0; d < _stories[l]._doors.size(); d++) { doorNew(_stories[l]._doors[d]); } - for (int r = 0; r < _stories[l]._rooms.size(); r++) { + for (uint r = 0; r < _stories[l]._rooms.size(); r++) { _rooms[r] = new Room(_stories[l]._rooms[r]._x, _stories[l]._rooms[r]._y, _stories[l]._rooms[r]._flags); Common::Array allFlames(_stories[l]._flames[r].size()); if (_stories[l]._flames[r].size() > 0) { - for (int f = 0; f < _stories[l]._flames[r].size(); f++) { + for (uint f = 0; f < _stories[l]._flames[r].size(); f++) { SFlame sf; sf._p = _stories[l]._flames[r][f]._p; sf._x = _stories[l]._flames[r][f]._x; @@ -89,13 +89,13 @@ void ImmortalEngine::levelLoadFile(int l) { _allFlames[r] = allFlames; if (_stories[l]._objects[r].size() > 0) { - for (int o = 0; o < _stories[l]._objects[r].size(); o++) { + for (uint o = 0; o < _stories[l]._objects[r].size(); o++) { //objNew(_stories[l]._objects[r][o]); } } if (_stories[l]._monsters[r].size() > 0) { - for (int m = 0; m < _stories[l]._monsters[r].size(); m++) { + for (uint m = 0; m < _stories[l]._monsters[r].size(); m++) { //monstNew(_stories[l]._monsters[r][m]); } } diff --git a/engines/immortal/logic.cpp b/engines/immortal/logic.cpp index 7cf5d0849796..038aa9223b48 100644 --- a/engines/immortal/logic.cpp +++ b/engines/immortal/logic.cpp @@ -49,11 +49,11 @@ void ImmortalEngine::restartLogic() { cycleFreeAll(); levelInit(); //roomInit(); <-- will be run in constructor of room - //monstInit(); <-- room.initMonsters() \ - //objectInit(); <-- room.initObjects() + //monstInit(); <-- room.initMonsters() -| + //objectInit(); <-- room.initObjects() | //doorInit(); <-- room.initDoors() |- probably all get run from room constructor - //sparkInit(); <-- room.initSparks() - //bulletInit(); <-- room.initProjectiles() / + //sparkInit(); <-- room.initSparks() | + //bulletInit(); <-- room.initProjectiles() -| //objectInit(); <-- again? Odd... //genericSpriteInit(); <-- room.initGenSprites() From 22473ec955a8aa018f3a4fc28f0a0afd10112b95 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Sun, 5 Feb 2023 18:49:50 -0800 Subject: [PATCH 403/412] MM: MM1: Fixed SpellsState _condition to be _damage --- engines/mm/mm1/data/spells_state.h | 4 +- engines/mm/mm1/game/combat.cpp | 26 ++++----- engines/mm/mm1/game/spells_monsters.cpp | 78 ++++++++++++------------- engines/mm/mm1/game/spells_party.cpp | 44 +++++++------- 4 files changed, 76 insertions(+), 76 deletions(-) diff --git a/engines/mm/mm1/data/spells_state.h b/engines/mm/mm1/data/spells_state.h index f1d5987fbf40..df567b28d947 100644 --- a/engines/mm/mm1/data/spells_state.h +++ b/engines/mm/mm1/data/spells_state.h @@ -37,7 +37,7 @@ struct SpellsState { // TODO: Is this variable different in different contexts? // In some places it's used to hold a new condition, // but others, like moonRay, uses it to hold Hp - byte _newCondition = 0; + byte _damage = 0; /** * Synchronize data to/from savegames @@ -48,7 +48,7 @@ struct SpellsState { s.syncAsByte(_mmVal5); s.syncAsByte(_mmVal7); s.syncAsByte(_resistanceType); - s.syncAsByte(_newCondition); + s.syncAsByte(_damage); } }; diff --git a/engines/mm/mm1/game/combat.cpp b/engines/mm/mm1/game/combat.cpp index e6a1d56a1ac0..91665bf68ded 100644 --- a/engines/mm/mm1/game/combat.cpp +++ b/engines/mm/mm1/game/combat.cpp @@ -963,9 +963,9 @@ void Combat::iterateMonsters1Inner() { } else { enc._monsterList[getMonsterIndex()]._status |= - g_globals->_spellsState._newCondition; + g_globals->_spellsState._damage; - byte bits = g_globals->_spellsState._newCondition; + byte bits = g_globals->_spellsState._damage; int effectNum; for (effectNum = 0; effectNum < 8; ++effectNum, bits >>= 1) { if (bits & 1) @@ -1015,7 +1015,7 @@ void Combat::iterateMonsters2Inner() { STRING["spells.casts_spell"].c_str()); const Common::String monsterName = _monsterP->_name; - _damage = g_globals->_spellsState._newCondition; + _damage = g_globals->_spellsState._damage; bool affects = !monsterLevelThreshold(); if (affects) { @@ -1161,7 +1161,7 @@ void Combat::summonLightning() { g_globals->_currCharacter->_name, STRING["spells.casts_spell"].c_str()); - ss._newCondition = g_globals->_currCharacter->_level * 2 + 4; + ss._damage = g_globals->_currCharacter->_level * 2 + 4; ss._mmVal1++; ss._mmVal2++; ss._resistanceType = RESISTANCE_ELECTRICITY; @@ -1183,7 +1183,7 @@ void Combat::summonLightning2() { ss._mmVal1 = 1; ss._mmVal2 = 2; ss._resistanceType = RESISTANCE_ELECTRICITY; - ss._newCondition = getRandomNumber(29) + 3; + ss._damage = getRandomNumber(29) + 3; iterateMonsters2(); } @@ -1193,7 +1193,7 @@ void Combat::fireball2() { ss._mmVal1 = 1; ss._mmVal2 = 1; ss._resistanceType = 5; - ss._newCondition = 0; + ss._damage = 0; levelAdjust(); } @@ -1201,7 +1201,7 @@ void Combat::fireball2() { void Combat::levelAdjust() { SpellsState &ss = g_globals->_spellsState; for (uint i = 0; i < g_globals->_currCharacter->_level._current; ++i) - ss._newCondition += getRandomNumber(6); + ss._damage += getRandomNumber(6); iterateMonsters2(); } @@ -1213,7 +1213,7 @@ void Combat::paralyze() { ss._mmVal1++; ss._mmVal2 = 6; ss._resistanceType = _attackersCount; - ss._newCondition = BAD_CONDITION; + ss._damage = BAD_CONDITION; iterateMonsters1(); } @@ -1319,7 +1319,7 @@ void Combat::fireball() { g_globals->_currCharacter->_name, STRING["spells.casts_spell"].c_str()); - ss._newCondition = g_globals->_currCharacter->_level * 2 + 4; + ss._damage = g_globals->_currCharacter->_level * 2 + 4; ss._mmVal1++; ss._mmVal2++; ss._resistanceType++; @@ -1367,7 +1367,7 @@ void Combat::weaken() { resetDestMonster(); ss._mmVal1++; - ss._newCondition = 2; + ss._damage = 2; iterateMonsters2(); } @@ -1379,7 +1379,7 @@ bool Combat::web() { ss._mmVal1++; ss._mmVal2 = 0; ss._resistanceType = 5; - ss._newCondition = UNCONSCIOUS; + ss._damage = UNCONSCIOUS; iterateMonsters1(); return true; @@ -1397,10 +1397,10 @@ bool Combat::acidRain() { ss._mmVal1 = 1; ss._mmVal2 = 3; ss._resistanceType = 15; - ss._newCondition = 0; + ss._damage = 0; for (int i = 0; i < 5; ++i) - ss._newCondition += getRandomNumber(10); + ss._damage += getRandomNumber(10); iterateMonsters2(); return true; diff --git a/engines/mm/mm1/game/spells_monsters.cpp b/engines/mm/mm1/game/spells_monsters.cpp index b3ebf40dc88a..fcb607cfdf56 100644 --- a/engines/mm/mm1/game/spells_monsters.cpp +++ b/engines/mm/mm1/game/spells_monsters.cpp @@ -70,7 +70,7 @@ void SpellsMonsters::castMonsterSpell(const Common::String &monsterName, int spe g_globals->_spellsState._mmVal1 = 0; g_globals->_spellsState._mmVal2 = 0; g_globals->_spellsState._resistanceType = RESISTANCE_MAGIC; - g_globals->_spellsState._newCondition = 0; + g_globals->_spellsState._damage = 0; // All spell messages start with the monster who casts it _lines.clear(); @@ -91,7 +91,7 @@ void SpellsMonsters::spell02_energyBlast() { if (casts()) { add(STRING["monster_spellsState.energy_blast"]); ++g_globals->_spellsState._mmVal1; - g_globals->_spellsState._newCondition = getRandomNumber(16) + 4; + g_globals->_spellsState._damage = getRandomNumber(16) + 4; damageRandomChar(); } } @@ -104,7 +104,7 @@ void SpellsMonsters::spell03_fire() { g_globals->_spellsState._resistanceType = RESISTANCE_FIRE; int count = _remainingMonsters[getMonsterIndex()]->_level; - g_globals->_spellsState._newCondition += count * 6; + g_globals->_spellsState._damage += count * 6; damageRandomChar(); } @@ -114,7 +114,7 @@ void SpellsMonsters::spell04_blindness() { add(STRING["monster_spellsState.blindness"]); ++g_globals->_spellsState._mmVal1; ++g_globals->_spellsState._mmVal2; - g_globals->_spellsState._newCondition = 2; + g_globals->_spellsState._damage = 2; handlePartyEffects(); } @@ -124,7 +124,7 @@ void SpellsMonsters::spell05_sprayPoison() { add(STRING["monster_spellsState.sprays_poison"]); ++g_globals->_spellsState._mmVal2; g_globals->_spellsState._resistanceType = RESISTANCE_POISON; - g_globals->_spellsState._newCondition = POISONED; + g_globals->_spellsState._damage = POISONED; handlePartyEffects(); } @@ -132,7 +132,7 @@ void SpellsMonsters::spell06_sprayAcid() { add(STRING["monster_spellsState.sprays_acid"]); ++g_globals->_spellsState._mmVal2; g_globals->_spellsState._resistanceType = RESISTANCE_ACID; - g_globals->_spellsState._newCondition = getRandomNumber((int)POISONED); + g_globals->_spellsState._damage = getRandomNumber((int)POISONED); add(':'); handlePartyDamage(); @@ -144,7 +144,7 @@ void SpellsMonsters::spell07_sleep() { ++g_globals->_spellsState._mmVal1; ++g_globals->_spellsState._mmVal2; g_globals->_spellsState._resistanceType = RESISTANCE_PSYCHIC; - g_globals->_spellsState._newCondition = ASLEEP; + g_globals->_spellsState._damage = ASLEEP; handlePartyEffects(); } } @@ -155,7 +155,7 @@ void SpellsMonsters::spell08_paralyze() { ++g_globals->_spellsState._mmVal1; ++g_globals->_spellsState._mmVal2; g_globals->_spellsState._resistanceType = RESISTANCE_FEAR; - g_globals->_spellsState._newCondition = PARALYZED; + g_globals->_spellsState._damage = PARALYZED; if (_remainingMonsters[getMonsterIndex()]->_level >= 5) { handlePartyEffects(); @@ -179,7 +179,7 @@ void SpellsMonsters::spell10_lightningBolt() { ++g_globals->_spellsState._mmVal1; ++g_globals->_spellsState._mmVal2; g_globals->_spellsState._resistanceType = RESISTANCE_ELECTRICITY; - g_globals->_spellsState._newCondition = getRandomNumber(37) + 5; + g_globals->_spellsState._damage = getRandomNumber(37) + 5; damageRandomChar(); } } @@ -190,7 +190,7 @@ void SpellsMonsters::spell11_strangeGas() { STRING["monster_spellsState.strange_gas"].c_str())); ++g_globals->_spellsState._mmVal2; g_globals->_spellsState._resistanceType = RESISTANCE_POISON; - g_globals->_spellsState._newCondition = BAD_CONDITION | STONE; + g_globals->_spellsState._damage = BAD_CONDITION | STONE; handlePartyEffects(); } @@ -199,7 +199,7 @@ void SpellsMonsters::spell12_explode() { add(STRING["monster_spellsState.explode"]); ++g_globals->_spellsState._mmVal2; g_globals->_spellsState._resistanceType = RESISTANCE_POISON; - g_globals->_spellsState._newCondition = getRandomNumber( + g_globals->_spellsState._damage = getRandomNumber( _remainingMonsters[getMonsterIndex()]->_level); _remainingMonsters[getMonsterIndex()]->_level = 0; _remainingMonsters[getMonsterIndex()]->_status = MONFLAG_DEAD; @@ -217,9 +217,9 @@ void SpellsMonsters::spell13_fireball() { g_globals->_spellsState._resistanceType = RESISTANCE_FIRE; // This whole condition choice makes no sense - g_globals->_spellsState._newCondition += 6 * + g_globals->_spellsState._damage += 6 * _remainingMonsters[getMonsterIndex()]->_level; - g_globals->_spellsState._newCondition = getRandomNumber(g_globals->_spellsState._newCondition) + 4; + g_globals->_spellsState._damage = getRandomNumber(g_globals->_spellsState._damage) + 4; add(':'); handlePartyDamage(); @@ -234,9 +234,9 @@ void SpellsMonsters::spell14_fireBreath() { g_globals->_spellsState._resistanceType = RESISTANCE_FIRE; // This whole condition choice makes no sense - g_globals->_spellsState._newCondition += 8 * + g_globals->_spellsState._damage += 8 * _remainingMonsters[getMonsterIndex()]->_level; - g_globals->_spellsState._newCondition = getRandomNumber(g_globals->_spellsState._newCondition); + g_globals->_spellsState._damage = getRandomNumber(g_globals->_spellsState._damage); add(':'); handlePartyDamage(); @@ -245,7 +245,7 @@ void SpellsMonsters::spell14_fireBreath() { void SpellsMonsters::spell15_gazes() { add(STRING["monster_spellsState.gazes"]); ++g_globals->_spellsState._mmVal2; - g_globals->_spellsState._newCondition = BAD_CONDITION | STONE; + g_globals->_spellsState._damage = BAD_CONDITION | STONE; chooseCharacter(); writeConditionEffect(); @@ -256,7 +256,7 @@ void SpellsMonsters::spell16_acidArrow() { ++g_globals->_spellsState._mmVal1; ++g_globals->_spellsState._mmVal2; g_globals->_spellsState._resistanceType = RESISTANCE_ACID; - g_globals->_spellsState._newCondition = getRandomNumber(31) + 9; + g_globals->_spellsState._damage = getRandomNumber(31) + 9; damageRandomChar(); } @@ -264,7 +264,7 @@ void SpellsMonsters::spell16_acidArrow() { void SpellsMonsters::spell17_elements() { add(STRING["monster_spellsState.call_elements"]); ++g_globals->_spellsState._mmVal2; - g_globals->_spellsState._newCondition = getRandomNumber(21) + 39; + g_globals->_spellsState._damage = getRandomNumber(21) + 39; damageRandomChar(); } @@ -275,7 +275,7 @@ void SpellsMonsters::spell18_coldBeam() { ++g_globals->_spellsState._mmVal1; ++g_globals->_spellsState._mmVal2; g_globals->_spellsState._resistanceType = RESISTANCE_COLD; - g_globals->_spellsState._newCondition = getRandomNumber(41) + 9; + g_globals->_spellsState._damage = getRandomNumber(41) + 9; damageRandomChar(); } @@ -285,7 +285,7 @@ void SpellsMonsters::spell19_dancingSword() { if (casts()) { add(STRING["monster_spellsState.dancing_sword"]); ++g_globals->_spellsState._mmVal1; - g_globals->_spellsState._newCondition = getRandomNumber(14) + 16; + g_globals->_spellsState._damage = getRandomNumber(14) + 16; add(':'); handlePartyDamage(); @@ -309,7 +309,7 @@ void SpellsMonsters::spell21_fingerOfDeath() { add(STRING["monster_spellsState.finger_of_death"]); ++g_globals->_spellsState._mmVal1; ++g_globals->_spellsState._mmVal2; - g_globals->_spellsState._newCondition = BAD_CONDITION | DEAD; + g_globals->_spellsState._damage = BAD_CONDITION | DEAD; chooseCharacter(); writeConditionEffect(); @@ -321,7 +321,7 @@ void SpellsMonsters::spell22_sunRay() { add(STRING["monster_spellsState.sun_ray"]); ++g_globals->_spellsState._mmVal1; ++g_globals->_spellsState._mmVal2; - g_globals->_spellsState._newCondition = getRandomNumber(51) + 49; + g_globals->_spellsState._damage = getRandomNumber(51) + 49; damageRandomChar(); } @@ -332,7 +332,7 @@ void SpellsMonsters::spell23_disintegration() { add(STRING["monster_spellsState.disintegration"]); ++g_globals->_spellsState._mmVal1; ++g_globals->_spellsState._mmVal2; - g_globals->_spellsState._newCondition = ERADICATED; + g_globals->_spellsState._damage = ERADICATED; chooseCharacter(); writeConditionEffect(); @@ -341,7 +341,7 @@ void SpellsMonsters::spell23_disintegration() { void SpellsMonsters::spell24_commandsEnergy() { add(STRING["monster_spellsState.commands_energy"]); - g_globals->_spellsState._newCondition = SILENCED | PARALYZED | UNCONSCIOUS; + g_globals->_spellsState._damage = SILENCED | PARALYZED | UNCONSCIOUS; damageRandomChar(); } @@ -350,7 +350,7 @@ void SpellsMonsters::spell25_poison() { STRING["monster_spellsState.breathes"].c_str(), STRING["monster_spellsState.poison"].c_str())); g_globals->_spellsState._resistanceType = RESISTANCE_POISON; - g_globals->_spellsState._newCondition = _remainingMonsters[getMonsterIndex()]->_hp; + g_globals->_spellsState._damage = _remainingMonsters[getMonsterIndex()]->_hp; ++g_globals->_spellsState._mmVal2; add(':'); @@ -362,7 +362,7 @@ void SpellsMonsters::spell26_lightning() { STRING["monster_spellsState.breathes"].c_str(), STRING["monster_spellsState.lightning"].c_str())); g_globals->_spellsState._resistanceType = RESISTANCE_ELECTRICITY; - g_globals->_spellsState._newCondition = _remainingMonsters[getMonsterIndex()]->_hp; + g_globals->_spellsState._damage = _remainingMonsters[getMonsterIndex()]->_hp; ++g_globals->_spellsState._mmVal2; add(':'); @@ -374,7 +374,7 @@ void SpellsMonsters::spell27_frost() { STRING["monster_spellsState.breathes"].c_str(), STRING["monster_spellsState.frost"].c_str())); g_globals->_spellsState._resistanceType = RESISTANCE_COLD; - g_globals->_spellsState._newCondition = _remainingMonsters[getMonsterIndex()]->_hp; + g_globals->_spellsState._damage = _remainingMonsters[getMonsterIndex()]->_hp; ++g_globals->_spellsState._mmVal2; add(':'); @@ -386,7 +386,7 @@ void SpellsMonsters::spell28_spikes() { STRING["monster_spellsState.breathes"].c_str(), STRING["monster_spellsState.spikes"].c_str())); g_globals->_spellsState._resistanceType = RESISTANCE_ELECTRICITY; - g_globals->_spellsState._newCondition = _remainingMonsters[getMonsterIndex()]->_hp; + g_globals->_spellsState._damage = _remainingMonsters[getMonsterIndex()]->_hp; ++g_globals->_spellsState._mmVal2; add(':'); @@ -398,7 +398,7 @@ void SpellsMonsters::spell29_acid() { STRING["monster_spellsState.breathes"].c_str(), STRING["monster_spellsState.acid"].c_str())); g_globals->_spellsState._resistanceType = RESISTANCE_ACID; - g_globals->_spellsState._newCondition = _remainingMonsters[getMonsterIndex()]->_hp; + g_globals->_spellsState._damage = _remainingMonsters[getMonsterIndex()]->_hp; ++g_globals->_spellsState._mmVal2; add(':'); @@ -410,7 +410,7 @@ void SpellsMonsters::spell30_fire() { STRING["monster_spellsState.breathes"].c_str(), STRING["monster_spellsState.fire"].c_str())); g_globals->_spellsState._resistanceType = RESISTANCE_FIRE; - g_globals->_spellsState._newCondition = _remainingMonsters[getMonsterIndex()]->_hp; + g_globals->_spellsState._damage = _remainingMonsters[getMonsterIndex()]->_hp; ++g_globals->_spellsState._mmVal2; add(':'); @@ -419,7 +419,7 @@ void SpellsMonsters::spell30_fire() { void SpellsMonsters::spell31_energy() { add(STRING["monster_spellsState.energy"]); - g_globals->_spellsState._newCondition = _remainingMonsters[getMonsterIndex()]->_hp; + g_globals->_spellsState._damage = _remainingMonsters[getMonsterIndex()]->_hp; ++g_globals->_spellsState._mmVal2; add(':'); @@ -429,7 +429,7 @@ void SpellsMonsters::spell31_energy() { void SpellsMonsters::spell32_swarm() { add(STRING["monster_spellsState.swarm"]); ++g_globals->_spellsState._mmVal2; - g_globals->_spellsState._newCondition = getRandomNumber(12); + g_globals->_spellsState._damage = getRandomNumber(12); add(':'); handlePartyDamage(); @@ -481,7 +481,7 @@ bool SpellsMonsters::isCharAffected() const { void SpellsMonsters::handleDamage() { g_globals->_spellsState._mmVal5 = 1; - _damage = g_globals->_spellsState._newCondition; + _damage = g_globals->_spellsState._damage; if (charAffected()) { if (isEffective()) { @@ -640,21 +640,21 @@ void SpellsMonsters::writeConditionEffect() { if (!charAffected() || !isEffective() || !testElementalResistance()) return; - if (g_globals->_spellsState._newCondition == 0) { + if (g_globals->_spellsState._damage == 0) { effectNum = 10; - } else if (g_globals->_spellsState._newCondition & BAD_CONDITION) { - if (!(g_globals->_spellsState._newCondition & (BAD_CONDITION | DEAD))) + } else if (g_globals->_spellsState._damage & BAD_CONDITION) { + if (!(g_globals->_spellsState._damage & (BAD_CONDITION | DEAD))) effectNum = 7; - else if (!(g_globals->_spellsState._newCondition & (BAD_CONDITION | STONE))) + else if (!(g_globals->_spellsState._damage & (BAD_CONDITION | STONE))) effectNum = 8; - else if (g_globals->_spellsState._newCondition == ERADICATED) + else if (g_globals->_spellsState._damage == ERADICATED) effectNum = 9; else effectNum = 10; } else { effectNum = 0; - for (byte bitset = g_globals->_spellsState._newCondition; bitset & 1; + for (byte bitset = g_globals->_spellsState._damage; bitset & 1; ++effectNum, bitset >>= 1) { } } diff --git a/engines/mm/mm1/game/spells_party.cpp b/engines/mm/mm1/game/spells_party.cpp index 52d18e038500..d4803c57c522 100644 --- a/engines/mm/mm1/game/spells_party.cpp +++ b/engines/mm/mm1/game/spells_party.cpp @@ -193,7 +193,7 @@ SpellResult SpellsParty::cleric13_blind() { SpellsState &s = g_globals->_spellsState; s._mmVal1++; s._mmVal2 = 7; - s._newCondition = BLINDED; + s._damage = BLINDED; s._resistanceType = static_cast((int)s._resistanceType + 1); g_globals->_combat->iterateMonsters1(); @@ -253,7 +253,7 @@ SpellResult SpellsParty::cleric22_heroism() { SpellResult SpellsParty::cleric23_pain() { SpellsState &ss = g_globals->_spellsState; - ss._newCondition = getRandomNumber(6) + getRandomNumber(6); + ss._damage = getRandomNumber(6) + getRandomNumber(6); ss._mmVal1++; ss._resistanceType++; ss._mmVal2 = 6; @@ -284,7 +284,7 @@ SpellResult SpellsParty::cleric27_silence() { SpellsState &ss = g_globals->_spellsState; ss._mmVal1++; ss._mmVal2 = 7; - ss._newCondition = SILENCED; + ss._damage = SILENCED; ss._resistanceType++; g_globals->_combat->iterateMonsters1(); @@ -295,7 +295,7 @@ SpellResult SpellsParty::cleric28_suggestion() { SpellsState &ss = g_globals->_spellsState; ss._mmVal1++; ss._mmVal2 = 6; - ss._newCondition = PARALYZED; + ss._damage = PARALYZED; ss._resistanceType++; g_globals->_combat->iterateMonsters1(); @@ -339,7 +339,7 @@ SpellResult SpellsParty::cleric35_produceFlame() { ss._mmVal1++; ss._resistanceType++; ss._mmVal2 = 4; - ss._newCondition = getRandomNumber(6) + + ss._damage = getRandomNumber(6) + getRandomNumber(6) + getRandomNumber(6); g_globals->_combat->iterateMonsters2(); return SR_SUCCESS_SILENT; @@ -349,7 +349,7 @@ SpellResult SpellsParty::cleric36_produceFrost() { SpellsState &ss = g_globals->_spellsState; ss._mmVal1++; ss._mmVal2++; - ss._newCondition = getRandomNumber(6) + + ss._damage = getRandomNumber(6) + getRandomNumber(6) + getRandomNumber(6); g_globals->_combat->iterateMonsters2(); return SR_SUCCESS_SILENT; @@ -436,7 +436,7 @@ SpellResult SpellsParty::cleric51_deadlySwarm() { g_globals->_combat->resetDestMonster(); ss._mmVal1++; ss._mmVal2 = 0; - ss._newCondition = getRandomNumber(10) + getRandomNumber(10); + ss._damage = getRandomNumber(10) + getRandomNumber(10); g_globals->_combat->iterateMonsters2(); return SR_SUCCESS_SILENT; @@ -507,7 +507,7 @@ SpellResult SpellsParty::cleric61_moonRay() { // Damage the monsters g_globals->_combat->resetDestMonster(); - ss._newCondition = hp; + ss._damage = hp; ss._mmVal1++; ss._mmVal2 = 5; @@ -645,7 +645,7 @@ SpellResult SpellsParty::cleric74_resurrection() { SpellResult SpellsParty::cleric75_sunRay() { SpellsState &ss = g_globals->_spellsState; - ss._newCondition = getRandomNumber(51) + 49; + ss._damage = getRandomNumber(51) + 49; ss._mmVal1++; ss._mmVal2++; ss._resistanceType = RESISTANCE_FIRE; @@ -665,7 +665,7 @@ SpellResult SpellsParty::wizard13_energyBlast() { for (int i = 0; i < g_globals->_currCharacter->_level._current; ++i) damage += getRandomNumber(4); - ss._newCondition = MIN(damage, 255); + ss._damage = MIN(damage, 255); ss._mmVal2 = 5; ss._resistanceType++; @@ -675,7 +675,7 @@ SpellResult SpellsParty::wizard13_energyBlast() { SpellResult SpellsParty::wizard14_flameArrow() { SpellsState &ss = g_globals->_spellsState; - ss._newCondition = getRandomNumber(6); + ss._damage = getRandomNumber(6); ss._mmVal1++; ss._mmVal2 = 1; ss._resistanceType++; @@ -699,7 +699,7 @@ SpellResult SpellsParty::wizard18_sleep() { ss._mmVal1++; ss._mmVal2 = 8; ss._resistanceType = RESISTANCE_FEAR; - ss._newCondition = 16; + ss._damage = 16; g_globals->_combat->iterateMonsters1(); return SR_SUCCESS_SILENT; @@ -707,7 +707,7 @@ SpellResult SpellsParty::wizard18_sleep() { SpellResult SpellsParty::wizard21_electricArrow() { SpellsState &ss = g_globals->_spellsState; - ss._newCondition = getRandomNumber(6) + getRandomNumber(6); + ss._damage = getRandomNumber(6) + getRandomNumber(6); ss._mmVal1++; ss._resistanceType++; ss._mmVal2 = 2; @@ -775,7 +775,7 @@ SpellResult SpellsParty::wizard28_scare() { ss._mmVal1++; ss._mmVal2 = 7; ss._resistanceType++; - ss._newCondition = 1; + ss._damage = 1; g_globals->_combat->iterateMonsters1(); return SR_SUCCESS_SILENT; @@ -837,7 +837,7 @@ SpellResult SpellsParty::wizard41_acidArrow() { ss._mmVal1++; ss._resistanceType++; ss._mmVal2 = 3; - ss._newCondition += getRandomNumber(10) + + ss._damage += getRandomNumber(10) + getRandomNumber(10) + getRandomNumber(10); g_globals->_combat->iterateMonsters2(); @@ -850,7 +850,7 @@ SpellResult SpellsParty::wizard42_coldBeam() { ss._resistanceType++; ss._mmVal2 = 4; - ss._newCondition = getRandomNumber(10) + getRandomNumber(10) + + ss._damage = getRandomNumber(10) + getRandomNumber(10) + getRandomNumber(10) + getRandomNumber(10); g_globals->_combat->iterateMonsters2(); @@ -862,7 +862,7 @@ SpellResult SpellsParty::wizard43_feebleMind() { ss._mmVal1++; ss._mmVal2 = 0; ss._resistanceType++; - ss._newCondition = 8; + ss._damage = 8; g_globals->_combat->iterateMonsters1(); return SR_SUCCESS_SILENT; @@ -873,7 +873,7 @@ SpellResult SpellsParty::wizard44_freeze() { ss._mmVal1 = 0; ss._mmVal2 = 6; ss._resistanceType++; - ss._newCondition = 128; + ss._damage = 128; g_globals->_combat->iterateMonsters1(); return SR_SUCCESS_SILENT; @@ -935,7 +935,7 @@ SpellResult SpellsParty::wizard61_dancingSword() { ss._mmVal1 = 0; ss._mmVal2 = 0; - ss._newCondition = getRandomNumber(30); + ss._damage = getRandomNumber(30); g_globals->_combat->iterateMonsters2(); return SR_SUCCESS_SILENT; @@ -984,7 +984,7 @@ SpellResult SpellsParty::wizard73_meteorShower() { ss._mmVal1++; ss._mmVal2 = 5; - ss._newCondition = MIN((int)getRandomNumber(120) + + ss._damage = MIN((int)getRandomNumber(120) + (int)g_globals->_currCharacter->_level._current, 120); g_globals->_combat->iterateMonsters2(); @@ -1005,12 +1005,12 @@ SpellResult SpellsParty::wizard75_prismaticLight() { if (ss._mmVal1 < 50) { uint count = getRandomNumber(4); - ss._newCondition <<= count; + ss._damage <<= count; g_globals->_combat->iterateMonsters2(); } else { uint count = getRandomNumber(8); - ss._newCondition <<= count; + ss._damage <<= count; g_globals->_combat->iterateMonsters1(); } From d94d6545bdeb4b87127ab940a0e9595e93c2410d Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Sun, 5 Feb 2023 21:12:20 -0800 Subject: [PATCH 404/412] MM: MM1: Fix spell result display casting wizard spells --- devtools/create_mm/files/mm1/strings_en.yml | 8 +------- engines/mm/mm1/game/combat.cpp | 4 ++-- engines/mm/mm1/views/combat.cpp | 3 +-- engines/mm/mm1/views/spells/cast_spell.cpp | 2 ++ 4 files changed, 6 insertions(+), 11 deletions(-) diff --git a/devtools/create_mm/files/mm1/strings_en.yml b/devtools/create_mm/files/mm1/strings_en.yml index d6016ba47c5e..fbb6718aba08 100644 --- a/devtools/create_mm/files/mm1/strings_en.yml +++ b/devtools/create_mm/files/mm1/strings_en.yml @@ -383,6 +383,7 @@ dialogs: hit: "hit" misses: "misses" for: "for" + takes: "takes" point: "point" points: "points" of_damage: "of damage!" @@ -392,13 +393,6 @@ dialogs: delay_currently: "(currently= %d)" infiltration: "infiltrates the ranks!" exchange_places: "exchange places with (1-%c)?" - takes: "takes " - point: "point" - points: "points" - of_damage: "of damage!" - goes_down: "goes down!!!" - and_goes_down: "and goes down!!!" - dies: "dies!" status: 0: "(paralyze)" 1: "(webbed) " diff --git a/engines/mm/mm1/game/combat.cpp b/engines/mm/mm1/game/combat.cpp index 91665bf68ded..db69d4a66675 100644 --- a/engines/mm/mm1/game/combat.cpp +++ b/engines/mm/mm1/game/combat.cpp @@ -1031,7 +1031,7 @@ void Combat::iterateMonsters2Inner() { idx = 0; static const byte FLAGS[8] = { - 0x40, 0x20, 0x60, 0x10, 8, 4, 2, 1 + 0x40, 0x20, 0x60, 0x10, 8, 4, 2, 1 }; if ((_monsterP->_field1a & FLAGS[idx]) == FLAGS[idx]) _damage >>= 2; @@ -1083,7 +1083,7 @@ void Combat::iterateMonsters2Inner() { g_globals->_combat->iterateMonsters2Inner(); }; } else { - msg._ynCallback = []() { + msg._timeoutCallback = []() { g_globals->_combat->characterDone(); }; } diff --git a/engines/mm/mm1/views/combat.cpp b/engines/mm/mm1/views/combat.cpp index 1e4ab7a49cee..45c4db65828c 100644 --- a/engines/mm/mm1/views/combat.cpp +++ b/engines/mm/mm1/views/combat.cpp @@ -841,8 +841,7 @@ void Combat::setOption(SelectedOption option) { } void Combat::displaySpellResult(const InfoMessage &msg) { - assert(msg._timeoutCallback || msg._keyCallback); - assert(!msg._delaySeconds || !msg._timeoutCallback); + assert(msg._delaySeconds); _spellResult = msg; setMode(SPELL_RESULT); diff --git a/engines/mm/mm1/views/spells/cast_spell.cpp b/engines/mm/mm1/views/spells/cast_spell.cpp index 6a3ffeea0e3b..46e184ba3256 100644 --- a/engines/mm/mm1/views/spells/cast_spell.cpp +++ b/engines/mm/mm1/views/spells/cast_spell.cpp @@ -215,6 +215,8 @@ void CastSpell::performSpell(Character *chr) { default: // Spell done, but don't display done message + if (isInCombat()) + close(); break; } } From ca769bc3755ec5999690fef74290b4d82f098791 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Sun, 5 Feb 2023 22:18:55 -0800 Subject: [PATCH 405/412] MM: MM1: Debugger command to allow all spells in combat --- engines/mm/mm1/console.cpp | 8 ++++++++ engines/mm/mm1/console.h | 5 +++++ engines/mm/mm1/game/spell_casting.cpp | 7 +++++++ engines/mm/mm1/globals.h | 1 + engines/mm/mm1/views/spells/cast_spell.cpp | 2 +- 5 files changed, 22 insertions(+), 1 deletion(-) diff --git a/engines/mm/mm1/console.cpp b/engines/mm/mm1/console.cpp index 52b504629051..5b2578ac5f6d 100644 --- a/engines/mm/mm1/console.cpp +++ b/engines/mm/mm1/console.cpp @@ -40,6 +40,7 @@ Console::Console() : GUI::Debugger() { registerCmd("pos", WRAP_METHOD(Console, cmdPos)); registerCmd("intangible", WRAP_METHOD(Console, cmdIntangible)); registerCmd("cast", WRAP_METHOD(Console, cmdCast)); + registerCmd("spells", WRAP_METHOD(Console, cmdSpellsAll)); registerCmd("encounter", WRAP_METHOD(Console, cmdEncounter)); registerCmd("encounters", WRAP_METHOD(Console, cmdEncounters)); registerCmd("specials", WRAP_METHOD(Console, cmdSpecials)); @@ -326,6 +327,13 @@ bool Console::cmdCast(int argc, const char **argv) { } } +bool Console::cmdSpellsAll(int argc, const char **argv) { + g_globals->_allSpells = (argc == 2) && !strcmp(argv[1], "on"); + debugPrintf("All spells is %s\n", + g_globals->_allSpells ? "enabled" : "disabled"); + return true; +} + bool Console::cmdEncounter(int argc, const char **argv) { if (argc < 2) { debugPrintf("encounter [, <# monsters>, ]\n"); diff --git a/engines/mm/mm1/console.h b/engines/mm/mm1/console.h index 625e3d3f407d..74b4040d9fca 100644 --- a/engines/mm/mm1/console.h +++ b/engines/mm/mm1/console.h @@ -70,6 +70,11 @@ class Console : public GUI::Debugger, public MM1::Game::SpellCasting { */ bool cmdCast(int argc, const char **argv); + /** + * Enables/disables casting any spell + */ + bool cmdSpellsAll(int argc, const char **argv); + /** * Trigger an encounter */ diff --git a/engines/mm/mm1/game/spell_casting.cpp b/engines/mm/mm1/game/spell_casting.cpp index 7d62de16ac2c..2aeb3bce7bc3 100644 --- a/engines/mm/mm1/game/spell_casting.cpp +++ b/engines/mm/mm1/game/spell_casting.cpp @@ -107,6 +107,13 @@ void SpellCasting::setSpell(Character *chr, int lvl, int num) { int requiredGems = (uint8)SPELLS_SP_GEMS[spellIndex] & 0x7f; if (_spellState == SS_OK) setSpell(spellIndex, requiredSp, requiredGems); + + // Supporting debugger command that enables all spells + if (g_globals->_allSpells && _spellState != SS_COMBAT_ONLY && + _spellState != SS_NONCOMBAT_ONLY && _spellState != SS_OUTDOORS_ONLY) { + _requiredSp = _requiredGems = 0; + _spellState = SS_OK; + } } void SpellCasting::setSpell(int spellIndex, int requiredSp, int requiredGems) { diff --git a/engines/mm/mm1/globals.h b/engines/mm/mm1/globals.h index 99b65a5241d5..c267f0b86f0f 100644 --- a/engines/mm/mm1/globals.h +++ b/engines/mm/mm1/globals.h @@ -62,6 +62,7 @@ class Globals : public GameState { // Console flags bool _intangible = false; bool _encountersOn = true; + bool _allSpells = false; public: // Enhanced mode globals diff --git a/engines/mm/mm1/views/spells/cast_spell.cpp b/engines/mm/mm1/views/spells/cast_spell.cpp index 46e184ba3256..bfed318fb8a5 100644 --- a/engines/mm/mm1/views/spells/cast_spell.cpp +++ b/engines/mm/mm1/views/spells/cast_spell.cpp @@ -132,7 +132,7 @@ void CastSpell::draw() { void CastSpell::spellLevelEntered(uint level) { // Ensure the spell level is valid if (level < 1 || level > 7 || - level > g_globals->_currCharacter->_spellLevel) { + (!g_globals->_allSpells && level > g_globals->_currCharacter->_spellLevel)) { close(); return; } From c124c554e3bb9335717a697b0a40bb7df933ad12 Mon Sep 17 00:00:00 2001 From: Matthew Duggan Date: Mon, 6 Feb 2023 14:09:26 +0900 Subject: [PATCH 406/412] TETRAEDGE: Add some initial features needed for Syberia 2 --- engines/tetraedge/game/character.cpp | 1 + engines/tetraedge/game/character.h | 2 + engines/tetraedge/game/game.cpp | 4 +- engines/tetraedge/game/game.h | 2 +- engines/tetraedge/game/lua_binds.cpp | 62 ++++++++++++++++++++++++++++ engines/tetraedge/game/object3d.cpp | 2 + engines/tetraedge/game/object3d.h | 2 + engines/tetraedge/te/te_core.cpp | 1 + 8 files changed, 74 insertions(+), 2 deletions(-) diff --git a/engines/tetraedge/game/character.cpp b/engines/tetraedge/game/character.cpp index 467e48e42a65..09a7d1181d4e 100644 --- a/engines/tetraedge/game/character.cpp +++ b/engines/tetraedge/game/character.cpp @@ -52,6 +52,7 @@ void Character::CharacterSettings::clear() { _defaultEyes.clear(); _defaultMouth.clear(); _defaultBody.clear(); + _invertNormals = false; } void Character::WalkSettings::clear() { diff --git a/engines/tetraedge/game/character.h b/engines/tetraedge/game/character.h index 7d7014045c0e..a5065199677f 100644 --- a/engines/tetraedge/game/character.h +++ b/engines/tetraedge/game/character.h @@ -70,6 +70,8 @@ class Character : public TeAnimation { Common::String _defaultMouth; // Note: Engine supports more, but in practice only one ever used. Common::String _defaultBody; // Note: Engine supports more, but in practice only one ever used. + bool _invertNormals; + void clear(); }; diff --git a/engines/tetraedge/game/game.cpp b/engines/tetraedge/game/game.cpp index dce51c5f0364..ff85979c44f8 100644 --- a/engines/tetraedge/game/game.cpp +++ b/engines/tetraedge/game/game.cpp @@ -1293,7 +1293,7 @@ void Game::pauseMovie() { sprite->pause(); } -void Game::playMovie(const Common::String &vidPath, const Common::String &musicPath) { +bool Game::playMovie(const Common::String &vidPath, const Common::String &musicPath) { Application *app = g_engine->getApplication(); app->captureFade(); TeButtonLayout *videoBackgroundButton = _inGameGui.buttonLayoutChecked("videoBackgroundButton"); @@ -1312,6 +1312,7 @@ void Game::playMovie(const Common::String &vidPath, const Common::String &musicP _running = false; TeSpriteLayout *videoSpriteLayout = _inGameGui.spriteLayoutChecked("video"); + // TODO: check return value here. videoSpriteLayout->load(vidPath); videoSpriteLayout->setVisible(true); music.play(); @@ -1324,6 +1325,7 @@ void Game::playMovie(const Common::String &vidPath, const Common::String &musicP } app->fade(); + return true; } void Game::playRandomSound(const Common::String &name) { diff --git a/engines/tetraedge/game/game.h b/engines/tetraedge/game/game.h index 97546d619497..b035c4f09308 100644 --- a/engines/tetraedge/game/game.h +++ b/engines/tetraedge/game/game.h @@ -145,7 +145,7 @@ class Game { void pauseMovie(); void pauseSounds() {}; // does nothing? - void playMovie(const Common::String &vidPath, const Common::String &musicPath); + bool playMovie(const Common::String &vidPath, const Common::String &musicPath); void playRandomSound(const Common::String &name); void playSound(const Common::String &name, int param_2, float volume); void removeNoScale2Child(TeLayout *layout); diff --git a/engines/tetraedge/game/lua_binds.cpp b/engines/tetraedge/game/lua_binds.cpp index 0a1483145f04..e73ba4615359 100644 --- a/engines/tetraedge/game/lua_binds.cpp +++ b/engines/tetraedge/game/lua_binds.cpp @@ -82,13 +82,32 @@ static void PlayMovie(const Common::String &vidpath, const Common::String &music game->playMovie(vidpath, musicpath); } +static void PlayMovie(const Common::String &vidpath, const Common::String &musicpath, double f) { + Game *game = g_engine->getGame(); + warning("TODO: handle float value in PlayMovie for Syberia 2"); + + if (!game->playMovie(vidpath, musicpath)) { + warning("[PlayMovie] Movie \"%s\" doesn\'t exist.", vidpath.c_str()); + } + // TODO: call Game::addMoviePlayed +} + + static int tolua_ExportedFunctions_PlayMovie00(lua_State *L) { tolua_Error err; + // Syberia 1 has 2 string args, Syberia 2 adds a double arg. if (tolua_isstring(L, 1, 0, &err) && tolua_isstring(L, 2, 0, &err) && tolua_isnoobj(L, 3, &err)) { Common::String s1(tolua_tostring(L, 1, nullptr)); Common::String s2(tolua_tostring(L, 2, nullptr)); PlayMovie(s1, s2); return 0; + } else if (tolua_isstring(L, 1, 0, &err) && tolua_isstring(L, 2, 0, &err) + && tolua_isnumber(L, 3, 1, &err) && tolua_isnoobj(L, 4, &err)) { + Common::String s1(tolua_tostring(L, 1, nullptr)); + Common::String s2(tolua_tostring(L, 2, nullptr)); + double d1 = tolua_tonumber(L, 3, 1.0); + PlayMovie(s1, s2, d1); + return 0; } error("#ferror in function 'PlayMovie': %d %d %s", err.index, err.array, err.type); } @@ -2038,6 +2057,45 @@ static int tolua_ExportedFunctions_MoveCharacterPlayerTo00(lua_State *L) { error("#ferror in function 'MoveCharacterPlayerTo': %d %d %s", err.index, err.array, err.type); } +static void EnableRunMode(bool val) { + warning("TODO: EnableRunMode %s", val ? "true" : "false"); +} + +static int tolua_ExportedFunctions_EnableRunMode00(lua_State *L) { + tolua_Error err; + if (tolua_isboolean(L, 1, 0, &err) && tolua_isnoobj(L, 2, &err)) { + bool b1 = tolua_toboolean(L, 1, 0); + EnableRunMode(b1); + } + error("#ferror in function 'EnableRunMode': %d %d %s", err.index, err.array, err.type); +} + +static void SetModelPlayer(const Common::String &name) { + Game *game = g_engine->getGame(); + Character *character = game->scene().character(name); + + if (!character) { + warning("[SetModelPlayer] Character not found %s", name.c_str()); + return; + } + + if (character->_model->name() != name) { + game->unloadPlayerCharacter(character->_model->name()); + if (!game->loadPlayerCharacter(name)) { + warning("[SetModelPlayer] Can't load player character"); + } + character->_model->setVisible(true); + } +} + +static int tolua_ExportedFunctions_SetModelPlayer00(lua_State *L) { + tolua_Error err; + if (tolua_isstring(L, 1, 0, &err) && tolua_isnoobj(L, 2, &err)) { + Common::String s1(tolua_tostring(L, 1, 0)); + SetModelPlayer(s1); + } + error("#ferror in function 'SetModelPlayer': %d %d %s", err.index, err.array, err.type); +} // //////////////////////////////////////////////////////////////////////// @@ -2189,6 +2247,10 @@ void LuaOpenBinds(lua_State *L) { tolua_function(L, "AddUnrecalAnim", tolua_ExportedFunctions_AddUnrecalAnim00); tolua_function(L, "UnlockArtwork", tolua_ExportedFunctions_UnlockArtwork00); + // Syberia 2 specific functions. + tolua_function(L, "EnableRunMode", tolua_ExportedFunctions_EnableRunMode00); + tolua_function(L, "SetModelPlayer", tolua_ExportedFunctions_SetModelPlayer00); + tolua_endmodule(L); } diff --git a/engines/tetraedge/game/object3d.cpp b/engines/tetraedge/game/object3d.cpp index c4b3e51809a2..95ba54dbf17e 100644 --- a/engines/tetraedge/game/object3d.cpp +++ b/engines/tetraedge/game/object3d.cpp @@ -82,6 +82,8 @@ void Object3D::ObjectSettings::clear() { _name.clear(); _modelFileName.clear(); _defaultScale = TeVector3f32(); + _originOffset = TeVector3f32(); + _invertNormals = false; } diff --git a/engines/tetraedge/game/object3d.h b/engines/tetraedge/game/object3d.h index bae3d0e36cb1..1cf9ef283433 100644 --- a/engines/tetraedge/game/object3d.h +++ b/engines/tetraedge/game/object3d.h @@ -37,6 +37,8 @@ class Object3D : public TeObject { Common::String _name; Common::String _modelFileName; TeVector3f32 _defaultScale; + TeVector3f32 _originOffset; + bool _invertNormals; void clear(); }; diff --git a/engines/tetraedge/te/te_core.cpp b/engines/tetraedge/te/te_core.cpp index 94a480e5564d..012b8d3fb629 100644 --- a/engines/tetraedge/te/te_core.cpp +++ b/engines/tetraedge/te/te_core.cpp @@ -148,6 +148,7 @@ Common::FSNode TeCore::findFile(const Common::Path &path) { "PC-MacOSX", "PC-PS3-Android-MacOSX", "PC-MacOSX-Android-iPhone-iPad", + "PC-Android-MacOSX-iPhone-iPad", "PC-MacOSX-Xbox360-PS3", "PC-MacOSX-PS3-Xbox360", "PC-MacOSX-Xbox360-PS3/PC-MacOSX", From 3e342beae9c2727a130970e82c8432783d5def1f Mon Sep 17 00:00:00 2001 From: Matthew Duggan Date: Mon, 6 Feb 2023 15:56:18 +0900 Subject: [PATCH 407/412] TETRAEDGE: Fix small coverity-identified issues. --- engines/tetraedge/game/dialog2.cpp | 4 ++-- engines/tetraedge/game/game.cpp | 5 +++-- engines/tetraedge/te/te_curve_anim2.h | 2 +- engines/tetraedge/te/te_free_move_zone.cpp | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/engines/tetraedge/game/dialog2.cpp b/engines/tetraedge/game/dialog2.cpp index dd0e0f9a0d3e..2d762d730919 100644 --- a/engines/tetraedge/game/dialog2.cpp +++ b/engines/tetraedge/game/dialog2.cpp @@ -137,8 +137,8 @@ bool Dialog2::onAnimationDownFinished() { bool Dialog2::onAnimationUpFinished() { // Seems like this just prints a debug value?? - TeButtonLayout *dialogButton = _gui.buttonLayout("dialog"); - dialogButton->anchor(); + //TeButtonLayout *dialogButton = _gui.buttonLayout("dialog"); + //dialogButton->anchor(); return false; } diff --git a/engines/tetraedge/game/game.cpp b/engines/tetraedge/game/game.cpp index ff85979c44f8..905c540563dc 100644 --- a/engines/tetraedge/game/game.cpp +++ b/engines/tetraedge/game/game.cpp @@ -840,6 +840,7 @@ bool Game::loadCharacter(const Common::String &name) { result = _scene.loadCharacter(name); if (result) { character = _scene.character(name); + assert(character); character->_onCharacterAnimFinishedSignal.remove(this, &Game::onCharacterAnimationFinished); character->_onCharacterAnimFinishedSignal.add(this, &Game::onCharacterAnimationFinished); character->onFinished().add(this, &Game::onDisplacementFinished); @@ -1083,10 +1084,10 @@ bool Game::onMouseClick(const Common::Point &pt) { _lastCharMoveMousePos = TeVector2s32(); } - if (app->isLockCursor() || _movePlayerCharacterDisabled) + Character *character = _scene._character; + if (app->isLockCursor() || _movePlayerCharacterDisabled || !character) return false; - Character *character = _scene._character; const Common::String &charAnim = character->curAnimName(); if (charAnim == character->characterSettings()._idleAnimFileName diff --git a/engines/tetraedge/te/te_curve_anim2.h b/engines/tetraedge/te/te_curve_anim2.h index c0ef1f1e512d..062e17bc1823 100644 --- a/engines/tetraedge/te/te_curve_anim2.h +++ b/engines/tetraedge/te/te_curve_anim2.h @@ -37,7 +37,7 @@ class TeCurveAnim2 : public TeAnimation { public: typedef void(T::*TMethod)(const S &); - TeCurveAnim2() : _callbackObj(nullptr), _duration(0), _lastUpdateTime(0) {} + TeCurveAnim2() : _callbackObj(nullptr), _callbackMethod(nullptr), _duration(0), _lastUpdateTime(0) {} virtual ~TeCurveAnim2() {} void setCurve(const Common::Array &curve) { diff --git a/engines/tetraedge/te/te_free_move_zone.cpp b/engines/tetraedge/te/te_free_move_zone.cpp index 3c0e2f9acf10..bfa55b8d9a69 100644 --- a/engines/tetraedge/te/te_free_move_zone.cpp +++ b/engines/tetraedge/te/te_free_move_zone.cpp @@ -34,7 +34,7 @@ namespace Tetraedge { class TeFreeMoveZoneGraph : micropather::Graph { friend class TeFreeMoveZone; - TeFreeMoveZoneGraph() : _owner(nullptr) {} + TeFreeMoveZoneGraph() : _owner(nullptr), _bordersDistance(2048.0f) {} TeVector2s32 _size; Common::Array _flags; From 0c75730dad4b20999cee6161825d7d487979ffa4 Mon Sep 17 00:00:00 2001 From: Matthew Duggan Date: Mon, 6 Feb 2023 16:51:43 +0900 Subject: [PATCH 408/412] TETRAEDGE: Pre-scale color values for TinyGL --- engines/tetraedge/te/te_renderer_tinygl.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/engines/tetraedge/te/te_renderer_tinygl.cpp b/engines/tetraedge/te/te_renderer_tinygl.cpp index a82b25a1055c..055316911d9a 100644 --- a/engines/tetraedge/te/te_renderer_tinygl.cpp +++ b/engines/tetraedge/te/te_renderer_tinygl.cpp @@ -160,7 +160,13 @@ void TeRendererTinyGL::renderTransparentMeshes() { tglVertexPointer(3, TGL_FLOAT, sizeof(TeVector3f32), _transparentMeshVertexes.data()); tglNormalPointer(TGL_FLOAT, sizeof(TeVector3f32), _transparentMeshNormals.data()); tglTexCoordPointer(2, TGL_FLOAT, sizeof(TeVector2f32), _transparentMeshCoords.data()); - tglColorPointer(4, TGL_UNSIGNED_BYTE, sizeof(TeColor), _transparentMeshColors.data()); + // TinyGL doesn't correctly scale BYTE color data, so provide it pre-scaled. + Common::Array colorVals(_transparentMeshColors.size() * 4); + const byte *coldata = reinterpret_cast(_transparentMeshColors.data()); + for (unsigned int i = 0; i < colorVals.size(); i++) { + colorVals[i] = (float)coldata[i] / 255.0f; + } + tglColorPointer(4, TGL_FLOAT, sizeof(float) * 4, colorVals.data()); TeMaterial lastMaterial; TeMatrix4x4 lastMatrix; From 6e9232761f971543dfdcd00b0e2bb58d86f4f0e5 Mon Sep 17 00:00:00 2001 From: Strangerke Date: Mon, 6 Feb 2023 09:11:03 +0100 Subject: [PATCH 409/412] EFH: Fix an accidental fall through pointed by digital, remove a useless check --- engines/efh/fight.cpp | 4 ++-- engines/efh/init.cpp | 12 ++++++------ engines/efh/script.cpp | 11 ++++------- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp index 5c591442758c..eee2174f940c 100644 --- a/engines/efh/fight.cpp +++ b/engines/efh/fight.cpp @@ -1495,11 +1495,11 @@ bool EfhEngine::checkSpecialItemsOnCurrentPlace(int16 itemId) { case 1: if ((itemId >= 0x58 && itemId <= 0x68) || (itemId >= 0x86 && itemId <= 0x89) || (itemId >= 0x74 && itemId <= 0x76) || itemId == 0x8C) retVal = false; - // fall through - // FIXME: Is this intentional? + break; case 2: if ((itemId >= 0x61 && itemId <= 0x63) || (itemId >= 0x74 && itemId <= 0x76) || (itemId >= 0x86 && itemId <= 0x89) || itemId == 0x5B || itemId == 0x5E || itemId == 0x66 || itemId == 0x68 || itemId == 0x8C) retVal = false; + break; default: break; } diff --git a/engines/efh/init.cpp b/engines/efh/init.cpp index b7511a1da811..47bb4409b342 100644 --- a/engines/efh/init.cpp +++ b/engines/efh/init.cpp @@ -371,23 +371,23 @@ EfhEngine::EfhEngine(OSystem *syst, const ADGameDescription *gd) : Engine(syst), memset(_places, 0, ARRAYSIZE(_places)); for (int i = 0; i < 24; ++i) memset(_curPlace[i], 0, ARRAYSIZE(_curPlace[i])); - memset(_npcBuf, 0, ARRAYSIZE(_npcBuf)*sizeof(NPCStruct)); + memset(_npcBuf, 0, ARRAYSIZE(_npcBuf) * sizeof(NPCStruct)); memset(_imp1, 0, ARRAYSIZE(_imp1)); memset(_imp2, 0, ARRAYSIZE(_imp2)); memset(_titleSong, 0, ARRAYSIZE(_titleSong)); - memset(_items, 0, ARRAYSIZE(_items)*sizeof(ItemStruct)); - memset(_tileFact, 0, ARRAYSIZE(_tileFact)*sizeof(TileFactStruct)); - memset(_animInfo, 0, ARRAYSIZE(_animInfo)*sizeof(AnimInfo)); + memset(_items, 0, ARRAYSIZE(_items) * sizeof(ItemStruct)); + memset(_tileFact, 0, ARRAYSIZE(_tileFact) * sizeof(TileFactStruct)); + memset(_animInfo, 0, ARRAYSIZE(_animInfo) * sizeof(AnimInfo)); memset(_history, 0, ARRAYSIZE(_history)); for (int i = 0; i < 19; ++i) { memset(_techDataArr[i], 0, ARRAYSIZE(_techDataArr[i])); memset(_mapArr[i], 0, ARRAYSIZE(_mapArr[i])); - memset(_mapMonsters[i], 0, ARRAYSIZE(_mapMonsters[i])*sizeof(MapMonster)); + memset(_mapMonsters[i], 0, ARRAYSIZE(_mapMonsters[i]) * sizeof(MapMonster)); for (int j = 0; j < 64; ++j) { memset(_mapGameMaps[i][j], 0, ARRAYSIZE(_mapGameMaps[i][j])); } } - memset(_tileBankSubFilesArray, 0, ARRAYSIZE(_tileBankSubFilesArray)*sizeof(uint8 *)); + memset(_tileBankSubFilesArray, 0, ARRAYSIZE(_tileBankSubFilesArray) * sizeof(uint8 *)); _regenCounter = 0; // If requested, load a savegame instead of showing the intro diff --git a/engines/efh/script.cpp b/engines/efh/script.cpp index 1495d9e9c23f..93f20ecf09e7 100644 --- a/engines/efh/script.cpp +++ b/engines/efh/script.cpp @@ -351,13 +351,10 @@ int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 pos buffer = script_readNumberArray(buffer, 1, scriptNumberArray); if (scriptExecuteFlag) { int16 scriptNpcId = scriptNumberArray[0]; - // TODO: This "if" is useless, it's doing just the same loop and if statement. Consider removing it. - if (isNpcATeamMember(scriptNpcId)) { - for (uint counter = 0; counter < 3; ++counter) { - if (_teamChar[counter]._id == scriptNpcId) { - removeCharacterFromTeam(counter); - break; - } + for (uint counter = 0; counter < 3; ++counter) { + if (_teamChar[counter]._id == scriptNpcId) { + removeCharacterFromTeam(counter); + break; } } } From e936bd1c812b4d0b1814db54fc350d9e26e139f9 Mon Sep 17 00:00:00 2001 From: Eugene Sandulenko Date: Mon, 6 Feb 2023 09:30:30 +0100 Subject: [PATCH 410/412] EFH: Actually plug in debug flags --- engines/efh/detection.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/engines/efh/detection.cpp b/engines/efh/detection.cpp index 81f13ff46dd3..cf1192c99305 100644 --- a/engines/efh/detection.cpp +++ b/engines/efh/detection.cpp @@ -75,6 +75,10 @@ class EfhMetaEngineDetection : public AdvancedMetaEngineDetection { const char *getOriginalCopyright() const override { return "Escape From Hell (C) Electronic Arts, 1990"; } + + const DebugChannelDef *getDebugChannels() const override { + return debugFlagList; + } }; } // End of namespace efh From 7e6c8964b85d0acd369644368e505efde0403346 Mon Sep 17 00:00:00 2001 From: Eugene Sandulenko Date: Mon, 6 Feb 2023 09:50:57 +0100 Subject: [PATCH 411/412] DIRECTOR: LINGO: Added BatQT XObject stub --- engines/director/lingo/lingo-object.cpp | 2 + engines/director/lingo/xlibs/batqt.cpp | 94 +++++++++++++++++++++++++ engines/director/lingo/xlibs/batqt.h | 46 ++++++++++++ engines/director/module.mk | 1 + 4 files changed, 143 insertions(+) create mode 100644 engines/director/lingo/xlibs/batqt.cpp create mode 100644 engines/director/lingo/xlibs/batqt.h diff --git a/engines/director/lingo/lingo-object.cpp b/engines/director/lingo/lingo-object.cpp index 155fdd0c1376..8d867ffa4eae 100644 --- a/engines/director/lingo/lingo-object.cpp +++ b/engines/director/lingo/lingo-object.cpp @@ -40,6 +40,7 @@ #include "director/lingo/xlibs/applecdxobj.h" #include "director/lingo/xlibs/askuser.h" #include "director/lingo/xlibs/barakeobj.h" +#include "director/lingo/xlibs/batqt.h" #include "director/lingo/xlibs/cdromxobj.h" #include "director/lingo/xlibs/darkenscreen.h" #include "director/lingo/xlibs/developerStack.h" @@ -150,6 +151,7 @@ static struct XLibProto { { AppleCDXObj::fileNames, AppleCDXObj::open, AppleCDXObj::close, kXObj, 400 }, // D4 { AskUser::fileNames, AskUser::open, AskUser::close, kXObj, 400 }, // D4 { BarakeObj::fileNames, BarakeObj::open, BarakeObj::close, kXObj, 400 }, // D4 + { BatQT::fileNames, BatQT::open, BatQT::close, kXObj, 400 }, // D4 { CDROMXObj::fileNames, CDROMXObj::open, CDROMXObj::close, kXObj, 200 }, // D2 { DarkenScreen::fileNames, DarkenScreen::open, DarkenScreen::close, kXObj, 300 }, // D3 { DeveloperStack::fileNames, DeveloperStack::open, DeveloperStack::close, kXObj, 300 }, // D3 diff --git a/engines/director/lingo/xlibs/batqt.cpp b/engines/director/lingo/xlibs/batqt.cpp new file mode 100644 index 000000000000..68003375aa6f --- /dev/null +++ b/engines/director/lingo/xlibs/batqt.cpp @@ -0,0 +1,94 @@ +/* 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 . + * + */ + +/** + * -- BatQt quicktime factory. 9Aug94 RNB + * BatQt + * I mNew --Creates a new instance of the XObject + * X mDispose --Disposes of XObject instance + * S mName --Returns the XObject name + * I mStatus --Returns an integer status code + * SI mError, code --Returns an error string + * S mLastError --Returns last error string + * ISI mOpen --Opens the specified movie + * IIIS mPlay --Play the movie, after setting parms + * I mStop --Stop the movie + * S mGetTimeRange --Gets the current time range + * S mGetMovieBox --Gets the current bounds box of the movie + * I mGetTime --Gets the current time of the movie + * SI mSetTime --Sets the current time of the movie + * SI mSetVolume --Sets the volume of the movie + * I mLength --Gets the length of the movie + * IIIII mSetMovieBox --Sets the bounding box of the movie + * III mSetTimeRange -- Sets the active segment of the movie + * II mAddCallback -- Adds a callback for the movie + * II mRemoveCallback -- Removes a callback for the movie + * I mResetCallbacks -- Resets the sent status of the callbacks + * XS mSetBatch -- Applies a set of batch commands + * + * USED IN: teamxtreme2-win + */ + +#include "director/director.h" +#include "director/lingo/lingo.h" +#include "director/lingo/lingo-object.h" +#include "director/lingo/xlibs/batqt.h" + + +namespace Director { + +// The name is different from the obj filename. +const char *BatQT::xlibName = "batQT"; +const char *BatQT::fileNames[] = { + "batQT", + nullptr +}; + +static MethodProto xlibMethods[] = { + { "new", BatQT::m_new, 0, 0, 400 }, // D4 + { nullptr, nullptr, 0, 0, 0 } +}; + +void BatQT::open(int type) { + if (type == kXObj) { + BatQTXObject::initMethods(xlibMethods); + BatQTXObject *xobj = new BatQTXObject(kXObj); + g_lingo->exposeXObject(xlibName, xobj); + } +} + +void BatQT::close(int type) { + if (type == kXObj) { + BatQTXObject::cleanupMethods(); + g_lingo->_globalvars[xlibName] = Datum(); + } +} + + +BatQTXObject::BatQTXObject(ObjectType ObjectType) : Object("FindSys") { + _objType = ObjectType; +} + +void BatQT::m_new(int nargs) { + g_lingo->push(g_lingo->_state->me); +} + +} // End of namespace Director diff --git a/engines/director/lingo/xlibs/batqt.h b/engines/director/lingo/xlibs/batqt.h new file mode 100644 index 000000000000..fb75f5b45733 --- /dev/null +++ b/engines/director/lingo/xlibs/batqt.h @@ -0,0 +1,46 @@ +/* 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 . + * + */ + +#ifndef DIRECTOR_LINGO_XLIBS_BATQT_H +#define DIRECTOR_LINGO_XLIBS_BATQT_H + +namespace Director { + +class BatQTXObject : public Object { +public: + BatQTXObject(ObjectType objType); +}; + +namespace BatQT { + +extern const char *xlibName; +extern const char *fileNames[]; + +void open(int type); +void close(int type); + +void m_new(int nargs); + +} // End of namespace BatQT + +} // End of namespace Director + +#endif diff --git a/engines/director/module.mk b/engines/director/module.mk index f5b1e5db1762..7c906719f268 100644 --- a/engines/director/module.mk +++ b/engines/director/module.mk @@ -43,6 +43,7 @@ MODULE_OBJS = \ lingo/xlibs/applecdxobj.o \ lingo/xlibs/askuser.o \ lingo/xlibs/barakeobj.o \ + lingo/xlibs/batqt.o \ lingo/xlibs/cdromxobj.o \ lingo/xlibs/darkenscreen.o \ lingo/xlibs/developerStack.o \ From 57a9a801a62b6c26dd3fb5c05e415e5bcdfa300c Mon Sep 17 00:00:00 2001 From: Eugene Sandulenko Date: Mon, 6 Feb 2023 09:58:48 +0100 Subject: [PATCH 412/412] DIRECTOR: LINGO: Added BlitPict XObject stub --- engines/director/lingo/lingo-object.cpp | 2 + engines/director/lingo/xlibs/blitpict.cpp | 83 +++++++++++++++++++++++ engines/director/lingo/xlibs/blitpict.h | 46 +++++++++++++ engines/director/module.mk | 1 + 4 files changed, 132 insertions(+) create mode 100644 engines/director/lingo/xlibs/blitpict.cpp create mode 100644 engines/director/lingo/xlibs/blitpict.h diff --git a/engines/director/lingo/lingo-object.cpp b/engines/director/lingo/lingo-object.cpp index 8d867ffa4eae..8bca3c3b7543 100644 --- a/engines/director/lingo/lingo-object.cpp +++ b/engines/director/lingo/lingo-object.cpp @@ -41,6 +41,7 @@ #include "director/lingo/xlibs/askuser.h" #include "director/lingo/xlibs/barakeobj.h" #include "director/lingo/xlibs/batqt.h" +#include "director/lingo/xlibs/blitpict.h" #include "director/lingo/xlibs/cdromxobj.h" #include "director/lingo/xlibs/darkenscreen.h" #include "director/lingo/xlibs/developerStack.h" @@ -152,6 +153,7 @@ static struct XLibProto { { AskUser::fileNames, AskUser::open, AskUser::close, kXObj, 400 }, // D4 { BarakeObj::fileNames, BarakeObj::open, BarakeObj::close, kXObj, 400 }, // D4 { BatQT::fileNames, BatQT::open, BatQT::close, kXObj, 400 }, // D4 + { BlitPict::fileNames, BlitPict::open, BlitPict::close, kXObj, 400 }, // D4 { CDROMXObj::fileNames, CDROMXObj::open, CDROMXObj::close, kXObj, 200 }, // D2 { DarkenScreen::fileNames, DarkenScreen::open, DarkenScreen::close, kXObj, 300 }, // D3 { DeveloperStack::fileNames, DeveloperStack::open, DeveloperStack::close, kXObj, 300 }, // D3 diff --git a/engines/director/lingo/xlibs/blitpict.cpp b/engines/director/lingo/xlibs/blitpict.cpp new file mode 100644 index 000000000000..107dd25725c5 --- /dev/null +++ b/engines/director/lingo/xlibs/blitpict.cpp @@ -0,0 +1,83 @@ +/* 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 . + * + */ + +/** + * -- BlitPict effects factory. 29Jun94 RNB + * BlitPict + * I mNew --Creates a new instance of the XObject + * X mDispose --Disposes of XObject instance + * S mName --Returns the XObject name (BlitPict) + * I mStatus --Returns an integer status code + * SI mError, code --Returns an error string + * S mLastError --Returns last error string + * SSIIIII mInit --Initializer + * SOIIII mCopy --Initializes from an existing object + * IIIIIOIIIIIIII mDraw --Draws to a destinitation + * IIIIIIIIIIII mSparkle --Draws a sparkle from a bitmap + * + * USED IN: teamxtreme2-win + */ + +#include "director/director.h" +#include "director/lingo/lingo.h" +#include "director/lingo/lingo-object.h" +#include "director/lingo/xlibs/blitpict.h" + + +namespace Director { + +// The name is different from the obj filename. +const char *BlitPict::xlibName = "BlitPict"; +const char *BlitPict::fileNames[] = { + "BlitPict", + nullptr +}; + +static MethodProto xlibMethods[] = { + { "new", BlitPict::m_new, 0, 0, 400 }, // D4 + { nullptr, nullptr, 0, 0, 0 } +}; + +void BlitPict::open(int type) { + if (type == kXObj) { + BlitPictXObject::initMethods(xlibMethods); + BlitPictXObject *xobj = new BlitPictXObject(kXObj); + g_lingo->exposeXObject(xlibName, xobj); + } +} + +void BlitPict::close(int type) { + if (type == kXObj) { + BlitPictXObject::cleanupMethods(); + g_lingo->_globalvars[xlibName] = Datum(); + } +} + + +BlitPictXObject::BlitPictXObject(ObjectType ObjectType) : Object("BlitPict") { + _objType = ObjectType; +} + +void BlitPict::m_new(int nargs) { + g_lingo->push(g_lingo->_state->me); +} + +} // End of namespace Director diff --git a/engines/director/lingo/xlibs/blitpict.h b/engines/director/lingo/xlibs/blitpict.h new file mode 100644 index 000000000000..11ab59c6c0ab --- /dev/null +++ b/engines/director/lingo/xlibs/blitpict.h @@ -0,0 +1,46 @@ +/* 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 . + * + */ + +#ifndef DIRECTOR_LINGO_XLIBS_BLITPICT_H +#define DIRECTOR_LINGO_XLIBS_BLITPICT_H + +namespace Director { + +class BlitPictXObject : public Object { +public: + BlitPictXObject(ObjectType objType); +}; + +namespace BlitPict { + +extern const char *xlibName; +extern const char *fileNames[]; + +void open(int type); +void close(int type); + +void m_new(int nargs); + +} // End of namespace BlitPict + +} // End of namespace Director + +#endif diff --git a/engines/director/module.mk b/engines/director/module.mk index 7c906719f268..3576a462ce09 100644 --- a/engines/director/module.mk +++ b/engines/director/module.mk @@ -44,6 +44,7 @@ MODULE_OBJS = \ lingo/xlibs/askuser.o \ lingo/xlibs/barakeobj.o \ lingo/xlibs/batqt.o \ + lingo/xlibs/blitpict.o \ lingo/xlibs/cdromxobj.o \ lingo/xlibs/darkenscreen.o \ lingo/xlibs/developerStack.o \