[Scummvm-git-logs] scummvm master -> 878fbe404ca5d8d56a559909a760c1b503305aa2

sev- noreply at scummvm.org
Sun Feb 5 20:59:52 UTC 2023


This automated email contains information about 83 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
650e0ce7a6 IMMORTAL: Initial skeleton for Immortal engine
4c30f05733 IMMORTAL: ProDos disk file support with implementation of Archive
9b7f4f3768 IMMORTAL: Add disk archive object to SearchMan
2d67a8cf0d IMMORTAL: Add check for file data null pointer and fix file name parameter
8ee7878dff IMMORTAL: Volume bitmap stored as byte * instead of Common::Array
566d3b3cd0 IMMORTAL: Translation of source decompression to compression.cpp
3e560a0ca5 IMMORTAL: ProDos -> ProDOS
05bfec4b60 IMMORTAL: unCompress() returns memoryReadStream instead of int, and bitmasks have enum
df41580e05 IMMORTAL: Fix file data offset calculation error in sapling and tree files
3da314ad88 IMMORTAL: Fix incorrect conditional in primary while loop of compression.cpp
0c9b09a41d IMMORTAL: Better comments and additional extension enum entry
432ecfb1cf IMMORTAL: Preliminary translation of game loop from kernal.gs, driver.gs, and logic.gs
e8d06bf6b6 IMMORTAL: Disk.cpp bug fix to parse correct number of files
d77cc8f5db IMMORTAL: Compression is part of engine class, also minor changes to a couple of statements
676cf5f7b5 IMMORTAL: Update to engine skeleton and addition of sprite_list, sprites, misc, and cycle
c5181c75de IMMORTAL: Indentation spaces -> tabs
0310509fa1 IMMORTAL: Minor formatting in disk.h
032377fe77 IMMORTAL: Add wizard data sprite indexes
d475e36f75 IMMORTAL: New functions added to kernal + update to initdatasprite in sprites.cpp
09a1bba0d0 IMMORTAL: Add _playing and _themePaused
db485ce349 IMMORTAL: Fill out much of logic.cpp skeleton
8391e33c71 IMMORTAL: Add SpriteFrame enum
c942b7f095 IMMORTAL: Add drawChr.cpp with function declarations and entry in module.mk
076742aa14 IMMORTAL: Logic skeleton filled out and necessary parts of story.h added
daa43ce02b IMMORTAL: Space/tab formatting
a1b5ea7187 IMMORTAL: Final two functions of Logic skeleton filled out (makecertificate() and miscinit())
09078a9de5 IMMORTAL: MonsterID enum moved to immortal.h
8ecffca966 IMMORTAL: Add level skeleton
8516b39aa1 IMMORTAL: Add story.cpp and related additions to story.h
35d8b166fe IMMORTAL: Level 0 of story.cpp completed, story.h filled out, and related level.cpp revised
bb56b8cdab IMMORTAL: Add skeleton of Room Object
204dda79b0 IMMORTAL: Add static story STR definitions
9410617da4 IMMORTAL: Add util.h and util.cpp, move several misc functions to util.cpp
af28dec2e9 IMMORTAL: Add bitmask.h and move bitmask enums from immortal.h to bitmask.h
b761800cfb IMMORTAL: Add definitions.h and move enums str, motives, and cyc from story.h to definitions.h
63a6fe2851 IMMORTAL: Update room skeleton, add flameSet, Univ, Door, and Bullet
fe6ef5d0d6 IMMORTAL: Spaces -> Tabs
22a3535e34 IMMORTAL: levelLoadFile initializes level doors
3d696d0e01 IMMORTAL: Frame -> Image, and Image/DataSprite/Cycle moved to sprite_list.h
435727b521 IMMORTAL: Util::X -> Immortal::Util::X
8b5b74fc84 IMMORTAL: Move CycID to definitions.h
55be069f92 IMMORTAL: Implement Cycles from Cyc.GS
6ba6e0fa2c IMMORTAL: Translation of Cycle is more accurate with addition of cycPtrs
c0c1d2e781 IMMORTAL: All engine members initialized to values now
1336c89bdf IMMORTAL: Add non-level static Cycle defintions + enum
ef711df128 IMMORTAL: Util -> Utilities, and addition of addSprite to utilities
5940f2312c IMMORTAL: Add univAddSprite to univ.cpp
821a539b6a IMMORTAL: Implement Cycles more accurately, under Room instead of Immortal, except for cycleFreeAll()
d13fbf16a5 IMMORTAL: Implement flameSet.cpp
259e993f68 IMMORTAL: Spaces -> Tabs
4b28cc268d IMMORTAL: Remove redundant namespaces in Utilities
ff06e73d6f IMMORTAL: Room includes reference to sprite data from ImmortalEngine
89cbe5974d IMMORTAL: Initial implementation of superSprites() + adjustment to sprite structs
b27988471c IMMORTAL: Implement utilities::inside() and insideRect()
8d9994ba56 IMMORTAL: Sprite drawing preliminarily implemented
d8944244a1 IMMORTAL: Implement sprite drawing through superSprites()
0467dbdb78 IMMORTAL: Enable sprite drawing in printChr() and drawGauge()
a2bd437c5e IMMORTAL: addSprite() moved out of utilities
cdf322b93a IMMORTAL: BMW is assumed to be in bytes and is converted to pixels for drawing
a3697c3bd5 IMMORTAL: univAddSprite() calls addSprite() through g_immortal instead of Utilities
c996c64b8c IMMORTAL: uint8 -> uint16 for several variables + initStoryStatic moved to story.cpp
5c2163db8e IMMORTAL: Room object utilizes g_immortal instead of passing pointers from engine members
bf95330f2c IMMORTAL: level.cpp no longer passes pointers to room object
7284826303 IMMORTAL: g_engine -> g_immortal + minor adjustments
4ca64366dc IMMORTAL: flameSet and Cycle utilize g_immortal instead of utilities
13ab4219ae IMMORTAL Remove kStrNoDesc because kStrNull exists
9e911f29d6 IMMORTAL: Text rendering through textSub() and associated functions preliminary implementation
d47efc743b IMMORTAL: Preliminary loadMazeGraphics() and loadUniv() functions
a188dced15 IMMORTAL: Formatting and comment adjustments across all several files
3feb762d90 IMMORTAL: Implement loadUniv() and add stub for makeBlisters()
8232bfd367 IMMORTAL: Update disk.cpp to use strncpy() instead of strcpy()
e16f087c54 IMMORTAL: Rewrite loadUniv() based on new understanding of CNM
55590df288 IMMORTAL: Fix whitespace at end of most files
98247630c2 IMMORTAL: Remove unnecessary commented line
9cbe97d557 IMMORTAL: IMMORTAL_IMMORTAL_H -> IMMORTAL_H
4103ebe600 IMMORTAL: Fix formatting for switch statements
7e0c5b39ab IMMORTAL: Fix formatting for casting
8a1c1764af IMMORTAL: Add TODO comments for unimplemented methods
9c2e1a55a8 IMMORTAL: Remove unused debug console channel method
deb3794626 IMMORTAL: Use AStyle to fix indentation and format issues across all files
ffb7ffc6eb IMMORTAL: Pass flameSet list by reference instead of copy
4116c881e6 IMMORTAL: Change loadPalette to use readUint16LE() instead of read()
878fbe404c IMMORTAL: Clean up some of the header dependancies


Commit: 650e0ce7a6db4ba3df12bf73d50cd4d8b6b4d411
    https://github.com/scummvm/scummvm/commit/650e0ce7a6db4ba3df12bf73d50cd4d8b6b4d411
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Initial skeleton for Immortal engine

Changed paths:
  A engines/immortal/configure.engine
  A engines/immortal/credits.pl
  A engines/immortal/detection.cpp
  A engines/immortal/detection.h
  A engines/immortal/detection_tables.h
  A engines/immortal/immortal.cpp
  A engines/immortal/immortal.h
  A engines/immortal/metaengine.cpp
  A engines/immortal/metaengine.h
  A engines/immortal/module.mk


diff --git a/engines/immortal/configure.engine b/engines/immortal/configure.engine
new file mode 100644
index 00000000000..835d5bdc5f6
--- /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 00000000000..c9fc8d7affd
--- /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 00000000000..3f3615cfe76
--- /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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#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 00000000000..fa4c3fcbf9a
--- /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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#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 00000000000..d1d9bfcd430
--- /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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+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 00000000000..b5c664242d8
--- /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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#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 00000000000..291cbc93def
--- /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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#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 00000000000..b736f5f8042
--- /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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#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 00000000000..cb80691c010
--- /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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#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 00000000000..a0aa13f3841
--- /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


Commit: 4c30f057331df05e5d5f481e9eae781b36b7002c
    https://github.com/scummvm/scummvm/commit/4c30f057331df05e5d5f481e9eae781b36b7002c
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: ProDos disk file support with implementation of Archive

Changed paths:
  A engines/immortal/disk.cpp
  A engines/immortal/disk.h
    engines/immortal/module.mk


diff --git a/engines/immortal/disk.cpp b/engines/immortal/disk.cpp
new file mode 100644
index 00000000000..35f516a9582
--- /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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+#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<ProDosFile>(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<byte> volBitmapBlock = Common::Array<byte>(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<Common::String, Common::SharedPtr<ProDosFile>>::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<ProDosFile> 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 00000000000..bc173ec3bf5
--- /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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#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<byte> _volBitmap;             // Not super useful, but could be used with _totalBlocks to check whether the disk is corrupted
+Common::HashMap<Common::String, Common::SharedPtr<ProDosFile>> _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 a0aa13f3841..684f8af133c 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


Commit: 9b7f4f37683254901f06fe0eeaecd0a560284f46
    https://github.com/scummvm/scummvm/commit/9b7f4f37683254901f06fe0eeaecd0a560284f46
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Add disk archive object to SearchMan

Changed paths:
    engines/immortal/immortal.cpp
    engines/immortal/immortal.h


diff --git a/engines/immortal/immortal.cpp b/engines/immortal/immortal.cpp
index b5c664242d8..ffa04323292 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 291cbc93def..fc64b0f2f73 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;


Commit: 2d67a8cf0dae01ea1333ebcc98d06a3798f11e9f
    https://github.com/scummvm/scummvm/commit/2d67a8cf0dae01ea1333ebcc98d06a3798f11e9f
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Add check for file data null pointer and fix file name parameter

Changed paths:
    engines/immortal/disk.cpp
    engines/immortal/disk.h


diff --git a/engines/immortal/disk.cpp b/engines/immortal/disk.cpp
index 35f516a9582..d14713a4591 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<ProDosFile>(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<Common::String, Common::SharedPtr<ProDosFile>>::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<ProDosFile> f = _files.getValOrDefault(name);
+    f->printInfo();
     return f->createReadStream();
 }
 
diff --git a/engines/immortal/disk.h b/engines/immortal/disk.h
index bc173ec3bf5..d51971af997 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 @@ public:
     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 @@ public:
     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<Common::String, Common::SharedPtr<ProDosFile>> _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<Common::String, Common::SharedPtr<ProDosFile>> _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<Common::String, Common::SharedPtr<ProDosFile>> _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<Common::String, Common::SharedPtr<ProDosFile>> _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
 };
 


Commit: 8ee7878dffeab42b7ad0c423109561e2e699ae61
    https://github.com/scummvm/scummvm/commit/8ee7878dffeab42b7ad0c423109561e2e699ae61
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Volume bitmap stored as byte * instead of Common::Array

Changed paths:
    engines/immortal/disk.cpp
    engines/immortal/disk.h


diff --git a/engines/immortal/disk.cpp b/engines/immortal/disk.cpp
index d14713a4591..736c4606557 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<byte> volBitmapBlock = Common::Array<byte>(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 d51971af997..4f8c1ea3599 100644
--- a/engines/immortal/disk.h
+++ b/engines/immortal/disk.h
@@ -124,13 +124,12 @@ public:
     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<byte> _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<Common::String, Common::SharedPtr<ProDosFile>> _files; // Hashmap of files in the volume, where key=Path, Value=ProDosFile
 
     struct Date {


Commit: 566d3b3cd0e082e52c1ec60fad2c0b5bf98bafa3
    https://github.com/scummvm/scummvm/commit/566d3b3cd0e082e52c1ec60fad2c0b5bf98bafa3
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Translation of source decompression to compression.cpp

Changed paths:
  A engines/immortal/compression.cpp
  A engines/immortal/compression.h
    engines/immortal/module.mk


diff --git a/engines/immortal/compression.cpp b/engines/immortal/compression.cpp
new file mode 100644
index 00000000000..16b24467e6e
--- /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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#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 00000000000..8770cb4d430
--- /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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#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 684f8af133c..15d7f541677 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)


Commit: 3e560a0ca5bc0b9e5de24c27b9251eeca3fbf046
    https://github.com/scummvm/scummvm/commit/3e560a0ca5bc0b9e5de24c27b9251eeca3fbf046
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: ProDos -> ProDOS

Changed paths:
    engines/immortal/disk.cpp
    engines/immortal/disk.h


diff --git a/engines/immortal/disk.cpp b/engines/immortal/disk.cpp
index 736c4606557..5979906ca6c 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<ProDosFile>(currFile));
+            _files.setVal(fileName, Common::SharedPtr<ProDOSFile>(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<Common::String, Common::SharedPtr<ProDosFile>>::const_iterator it;
+    Common::HashMap<Common::String, Common::SharedPtr<ProDOSFile>>::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<ProDosFile> f = _files.getValOrDefault(name);
+    Common::SharedPtr<ProDOSFile> f = _files.getValOrDefault(name);
     f->printInfo();
     return f->createReadStream();
 }
diff --git a/engines/immortal/disk.h b/engines/immortal/disk.h
index 4f8c1ea3599..8ab903b7b8e 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 @@ private:
  * 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<Common::String, Common::SharedPtr<ProDosFile>> _files; // Hashmap of files in the volume, where key=Path, Value=ProDosFile
+Common::HashMap<Common::String, Common::SharedPtr<ProDOSFile>> _files; // Hashmap of files in the volume, where key=Path, Value=ProDOSFile
 
     struct Date {
          uint8 _day;
@@ -153,8 +153,8 @@ Common::HashMap<Common::String, Common::SharedPtr<ProDosFile>> _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<Common::String, Common::SharedPtr<ProDosFile>> _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 {


Commit: 05bfec4b60cf34929c5068fc7c17830bf01d0d57
    https://github.com/scummvm/scummvm/commit/05bfec4b60cf34929c5068fc7c17830bf01d0d57
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: unCompress() returns memoryReadStream instead of int, and bitmasks have enum

Changed paths:
    engines/immortal/compression.cpp
    engines/immortal/compression.h


diff --git a/engines/immortal/compression.cpp b/engines/immortal/compression.cpp
index 16b24467e6e..9dd9fbb6857 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 8770cb4d430..96633758e0b 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[]);


Commit: df41580e058580c64b04d77277efb1ce136f6138
    https://github.com/scummvm/scummvm/commit/df41580e058580c64b04d77277efb1ce136f6138
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Fix file data offset calculation error in sapling and tree files

Changed paths:
    engines/immortal/disk.cpp


diff --git a/engines/immortal/disk.cpp b/engines/immortal/disk.cpp
index 5979906ca6c..49c940182be 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);


Commit: 3da314ad88ca59f3e13dd68cf489373327b342c9
    https://github.com/scummvm/scummvm/commit/3da314ad88ca59f3e13dd68cf489373327b342c9
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Fix incorrect conditional in primary while loop of compression.cpp

Changed paths:
    engines/immortal/compression.cpp


diff --git a/engines/immortal/compression.cpp b/engines/immortal/compression.cpp
index 9dd9fbb6857..03cd608c68c 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


Commit: 0c9b09a41d37ae8df342f0ce84a2eb282845ed88
    https://github.com/scummvm/scummvm/commit/0c9b09a41d37ae8df342f0ce84a2eb282845ed88
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Better comments and additional extension enum entry

Changed paths:
    engines/immortal/disk.cpp
    engines/immortal/disk.h


diff --git a/engines/immortal/disk.cpp b/engines/immortal/disk.cpp
index 49c940182be..eb0e82b3991 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<ProDOSFile>(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 8ab903b7b8e..a6045fc4a68 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 @@ public:
     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 @@ private:
 
 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 @@ public:
     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


Commit: 432ecfb1cf9fd2ab4d2bb8f9d0f0e9c3dfedc746
    https://github.com/scummvm/scummvm/commit/432ecfb1cf9fd2ab4d2bb8f9d0f0e9c3dfedc746
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Preliminary translation of game loop from kernal.gs, driver.gs, and logic.gs

Changed paths:
  A engines/immortal/kernal.cpp
  A engines/immortal/logic.cpp
    engines/immortal/immortal.cpp
    engines/immortal/immortal.h
    engines/immortal/module.mk


diff --git a/engines/immortal/immortal.cpp b/engines/immortal/immortal.cpp
index ffa04323292..ba4f80d183d 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 fc64b0f2f73..ced4ac04a64 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 @@ private:
 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<Common::String, Common::File> _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 @@ public:
 		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 @@ public:
 	/* 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 00000000000..284245ff6ad
--- /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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/* 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 00000000000..8a1fd3a7474
--- /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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#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 15d7f541677..b3ba49aaff9 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)


Commit: e8d06bf6b601e81fbfd251f6f2eadb9cd458db24
    https://github.com/scummvm/scummvm/commit/e8d06bf6b601e81fbfd251f6f2eadb9cd458db24
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Disk.cpp bug fix to parse correct number of files

Changed paths:
    engines/immortal/disk.cpp


diff --git a/engines/immortal/disk.cpp b/engines/immortal/disk.cpp
index eb0e82b3991..f92501183c1 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<ProDOSFile>(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 ---");


Commit: d77cc8f5db2d7d34ab8b353bb8743b81cf807aed
    https://github.com/scummvm/scummvm/commit/d77cc8f5db2d7d34ab8b353bb8743b81cf807aed
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Compression is part of engine class, also minor changes to a couple of statements

Changed paths:
  R engines/immortal/compression.h
    engines/immortal/compression.cpp
    engines/immortal/immortal.h


diff --git a/engines/immortal/compression.cpp b/engines/immortal/compression.cpp
index 03cd608c68c..5a9dba9ffa5 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 96633758e0b..00000000000
--- 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 <http://www.gnu.org/licenses/>.
- *
- */
-
-#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 ced4ac04a64..62412401bdf 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 @@ public:
 
 	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<Common::String, Common::File> _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 @@ public:
 	  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 @@ public:
 	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


Commit: 676cf5f7b5bea09bbd97043053fc73d7d3cb6edb
    https://github.com/scummvm/scummvm/commit/676cf5f7b5bea09bbd97043053fc73d7d3cb6edb
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Update to engine skeleton and addition of sprite_list, sprites, misc, and cycle

Changed paths:
  A engines/immortal/cycle.cpp
  A engines/immortal/misc.cpp
  A engines/immortal/sprite_list.h
  A engines/immortal/sprites.cpp
    engines/immortal/immortal.cpp
    engines/immortal/immortal.h
    engines/immortal/kernal.cpp
    engines/immortal/logic.cpp
    engines/immortal/module.mk


diff --git a/engines/immortal/cycle.cpp b/engines/immortal/cycle.cpp
new file mode 100644
index 00000000000..1eb43200ea2
--- /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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#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 ba4f80d183d..13856bca0f3 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 62412401bdf..b3914ddb512 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 @@ public:
 	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 @@ public:
 	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 @@ public:
 	/*
 	 * 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 @@ public:
 	 */
 	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 @@ public:
 	   int _dontResetColors = 0;						// Not sure yet
 
 
-
 	/*
 	 * --- Functions ---
 	 *
@@ -189,19 +210,20 @@ public:
 	 * [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 @@ public:
 	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 @@ public:
 
 	// ??
 	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 @@ public:
 	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 @@ public:
 	 * [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 @@ public:
 
 	// 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 284245ff6ad..79a8dfc8460 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 8a1fd3a7474..750e59a399b 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 00000000000..3457ccb0a3e
--- /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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#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 b3ba49aaff9..fa12eb2f94f 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 00000000000..a385db5bd17
--- /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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#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 00000000000..0329cf6a420
--- /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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+


Commit: c5181c75defb6ca4ac1217a67e56761960e043ef
    https://github.com/scummvm/scummvm/commit/c5181c75defb6ca4ac1217a67e56761960e043ef
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Indentation spaces -> tabs

Changed paths:
    engines/immortal/compression.cpp
    engines/immortal/credits.pl
    engines/immortal/cycle.cpp
    engines/immortal/disk.cpp
    engines/immortal/disk.h
    engines/immortal/immortal.cpp
    engines/immortal/immortal.h
    engines/immortal/kernal.cpp
    engines/immortal/logic.cpp
    engines/immortal/metaengine.cpp
    engines/immortal/misc.cpp
    engines/immortal/sprite_list.h
    engines/immortal/sprites.cpp


diff --git a/engines/immortal/compression.cpp b/engines/immortal/compression.cpp
index 5a9dba9ffa5..aa0b2eae8cf 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 c9fc8d7affd..59b13cf59b4 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 1eb43200ea2..c02570f93d6 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 f92501183c1..340a07d409e 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<ProDOSFile>(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<ProDOSFile>(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<Common::String, Common::SharedPtr<ProDOSFile>>::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<Common::String, Common::SharedPtr<ProDOSFile>>::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<ProDOSFile> f = _files.getValOrDefault(name);
-    f->printInfo();
-    return f->createReadStream();
+	Common::String name = path.toString();
+	if (!_files.contains(name)) {
+		return nullptr;
+	}
+	Common::SharedPtr<ProDOSFile> f = _files.getValOrDefault(name);
+	f->printInfo();
+	return f->createReadStream();
 }
 
 } // namespace Immortal
diff --git a/engines/immortal/disk.h b/engines/immortal/disk.h
index a6045fc4a68..030fbb00f88 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 @@ private:
 
 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<Common::String, Common::SharedPtr<ProDOSFile>> _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 13856bca0f3..c07bcfdda3d 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 b3914ddb512..3c6203e9979 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 @@ public:
 	 * '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 @@ public:
 	 * [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 @@ public:
 
 	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 79a8dfc8460..043d7065858 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 750e59a399b..c7061c8b529 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 b736f5f8042..1448f05a663 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 3457ccb0a3e..f55680f21fa 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 a385db5bd17..656e8a12e34 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 0329cf6a420..1bad636a672 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;
 }
 
 


Commit: 0310509fa1f3612a6e726789451866a5515d7795
    https://github.com/scummvm/scummvm/commit/0310509fa1f3612a6e726789451866a5515d7795
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Minor formatting in disk.h

Changed paths:
    engines/immortal/disk.h


diff --git a/engines/immortal/disk.h b/engines/immortal/disk.h
index 030fbb00f88..2d581c969c4 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 @@ public:
 	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,


Commit: 032377fe775a8d2f8a357f46281172def1915c9d
    https://github.com/scummvm/scummvm/commit/032377fe775a8d2f8a357f46281172def1915c9d
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Add wizard data sprite indexes

Changed paths:
    engines/immortal/sprite_list.h


diff --git a/engines/immortal/sprite_list.h b/engines/immortal/sprite_list.h
index 656e8a12e34..2411936dcf8 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,


Commit: d475e36f7541a5c19d7019b994a861f3d24640bd
    https://github.com/scummvm/scummvm/commit/d475e36f7541a5c19d7019b994a861f3d24640bd
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: New functions added to kernal + update to initdatasprite in sprites.cpp

Changed paths:
    engines/immortal/immortal.h
    engines/immortal/kernal.cpp
    engines/immortal/sprites.cpp


diff --git a/engines/immortal/immortal.h b/engines/immortal/immortal.h
index 3c6203e9979..fc489eacb28 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<Frame> _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 @@ public:
 	/*
 	 * 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 @@ public:
 	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 @@ public:
 	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 @@ public:
 	// 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 @@ public:
 	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 @@ public:
 	 * [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 @@ public:
 	void myDelay();
 
 	// Text printing
-	void textPrint(int num);
+	bool textPrint(const Common::String s);
 	void textSub();
 	void textEnd();
 	void textMiddle();
@@ -357,7 +511,6 @@ public:
 	// Screen related
 	void inside(int p, int p2, int a);
 	void insideRect(int p, int r);
-	void updateHitGuage();
 
 
 	/*
@@ -374,6 +527,31 @@ public:
 	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 043d7065858..8e5deb0d82a 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 1bad636a672..ae93b2f4258 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<Frame> 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
 


Commit: 09a1bba0d0586210f1f78d43d761a7be47bb362f
    https://github.com/scummvm/scummvm/commit/09a1bba0d0586210f1f78d43d761a7be47bb362f
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Add _playing and _themePaused

Changed paths:
    engines/immortal/immortal.cpp


diff --git a/engines/immortal/immortal.cpp b/engines/immortal/immortal.cpp
index c07bcfdda3d..623a5cdc3dc 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
 


Commit: db485ce3493610a321e04c6de4216b5ee221fe91
    https://github.com/scummvm/scummvm/commit/db485ce3493610a321e04c6de4216b5ee221fe91
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Fill out much of logic.cpp skeleton

Changed paths:
    engines/immortal/logic.cpp
    engines/immortal/misc.cpp
    engines/immortal/module.mk


diff --git a/engines/immortal/logic.cpp b/engines/immortal/logic.cpp
index c7061c8b529..52b3c425d65 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<int? *>();
+	// 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 f55680f21fa..8f49b224363 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 fa12eb2f94f..6e2c6e8c62c 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
 


Commit: 8391e33c71126f0a7586808a87aacc1f22a3c693
    https://github.com/scummvm/scummvm/commit/8391e33c71126f0a7586808a87aacc1f22a3c693
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Add SpriteFrame enum

Changed paths:
    engines/immortal/sprite_list.h


diff --git a/engines/immortal/sprite_list.h b/engines/immortal/sprite_list.h
index 2411936dcf8..b4e80963e62 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,


Commit: c942b7f0957cd626fade9287e0ccee684e78e246
    https://github.com/scummvm/scummvm/commit/c942b7f0957cd626fade9287e0ccee684e78e246
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Add drawChr.cpp with function declarations and entry in module.mk

Changed paths:
  A engines/immortal/drawChr.cpp
    engines/immortal/module.mk


diff --git a/engines/immortal/drawChr.cpp b/engines/immortal/drawChr.cpp
new file mode 100644
index 00000000000..7ef77391543
--- /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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#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 6e2c6e8c62c..18b5dfdf28b 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)


Commit: 076742aa14fe55251fcaa7137c7ff1872e1063cc
    https://github.com/scummvm/scummvm/commit/076742aa14fe55251fcaa7137c7ff1872e1063cc
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Logic skeleton filled out and necessary parts of story.h added

Changed paths:
  A engines/immortal/story.h
    engines/immortal/immortal.h
    engines/immortal/kernal.cpp
    engines/immortal/logic.cpp
    engines/immortal/misc.cpp


diff --git a/engines/immortal/immortal.h b/engines/immortal/immortal.h
index fc489eacb28..584e7dc0f77 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 @@ public:
 	 */
 
 	// 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 @@ public:
 	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 @@ public:
 	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 @@ public:
 	  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 @@ public:
 		   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 @@ public:
 	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 @@ public:
 	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 @@ public:
 	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 @@ public:
 
 	// 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 @@ public:
 
 	// 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 @@ public:
 	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 8e5deb0d82a..79b15bfb514 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 52b3c425d65..d8191ae7881 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 8f49b224363..39a86565558 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 00000000000..644bbb13bc6
--- /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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#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


Commit: daa43ce02b56588c96a4e5eca164fdb0cc8a81f6
    https://github.com/scummvm/scummvm/commit/daa43ce02b56588c96a4e5eca164fdb0cc8a81f6
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Space/tab formatting

Changed paths:
    engines/immortal/compression.cpp
    engines/immortal/metaengine.cpp
    engines/immortal/misc.cpp


diff --git a/engines/immortal/compression.cpp b/engines/immortal/compression.cpp
index aa0b2eae8cf..0f39f6ff806 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 1448f05a663..95fcb9ece99 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 39a86565558..fadbb9f4d6f 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) {}


Commit: a1b5ea7187d48cc3f7559d242ab5ab0addc57f97
    https://github.com/scummvm/scummvm/commit/a1b5ea7187d48cc3f7559d242ab5ab0addc57f97
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Final two functions of Logic skeleton filled out (makecertificate() and miscinit())

Changed paths:
    engines/immortal/immortal.h
    engines/immortal/logic.cpp
    engines/immortal/misc.cpp


diff --git a/engines/immortal/immortal.h b/engines/immortal/immortal.h
index 584e7dc0f77..3f86e6764dc 100644
--- a/engines/immortal/immortal.h
+++ b/engines/immortal/immortal.h
@@ -202,7 +202,7 @@ public:
 	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 @@ public:
 	 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 @@ public:
 	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 d8191ae7881..2a577a1e169 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 fadbb9f4d6f..379e2571c1c 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() {}


Commit: 09078a9de521e1825e1ea4ac9ef240779e9007a9
    https://github.com/scummvm/scummvm/commit/09078a9de521e1825e1ea4ac9ef240779e9007a9
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: MonsterID enum moved to immortal.h

Changed paths:
    engines/immortal/immortal.h
    engines/immortal/story.h


diff --git a/engines/immortal/immortal.h b/engines/immortal/immortal.h
index 3f86e6764dc..d56022d9bce 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 644bbb13bc6..bfd5d5435e7 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,


Commit: 8ecffca96630f151dc7ac82be7dcb099a6433ae0
    https://github.com/scummvm/scummvm/commit/8ecffca96630f151dc7ac82be7dcb099a6433ae0
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Add level skeleton

Changed paths:
  A engines/immortal/level.cpp
    engines/immortal/immortal.h
    engines/immortal/kernal.cpp
    engines/immortal/logic.cpp
    engines/immortal/module.mk
    engines/immortal/story.h


diff --git a/engines/immortal/immortal.h b/engines/immortal/immortal.h
index d56022d9bce..913e6d2fac7 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 @@ public:
 	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 @@ public:
 	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 @@ public:
 	  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 @@ public:
 	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 @@ public:
 
 
 	/*
-	 * [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 @@ public:
 	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 @@ public:
 
 	// 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 79b15bfb514..50f9fa16caf 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 00000000000..878bbf0c5dc
--- /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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#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 2a577a1e169..ebeea26369a 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 18b5dfdf28b..db9aab28f48 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 bfd5d5435e7..42f0d009ea8 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;


Commit: 8516b39aa1a50722b74a03526f87d6b222d7d687
    https://github.com/scummvm/scummvm/commit/8516b39aa1a50722b74a03526f87d6b222d7d687
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Add story.cpp and related additions to story.h

Changed paths:
  A engines/immortal/story.cpp
    engines/immortal/immortal.h
    engines/immortal/level.cpp
    engines/immortal/module.mk
    engines/immortal/story.h


diff --git a/engines/immortal/immortal.h b/engines/immortal/immortal.h
index 913e6d2fac7..3296f741ea4 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 @@ public:
 						   			  		"Congratulations!&&Play again?@",
 						   			  		"Enter certificate:&-=",
 						   			  		"Game Over&&Play again?@"};
-
 	// Screen constants
 	const int kResH 	  = 320;
 	const int kResV 	  = 200;
@@ -296,9 +304,10 @@ public:
 	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 @@ public:
 	  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 @@ public:
 	  int _lastType;
 	  int _roomCellX;
 	  int _roomCellY;
-	Story _stories[8];
 	Room *_rooms[kMaxRooms];							// Rooms within the level
 
 	// Debug members
@@ -578,6 +589,13 @@ public:
 	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 878bbf0c5dc..1569990829d 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 db9aab28f48..6c460cff60a 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 00000000000..a32b149c3a9
--- /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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/* [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 42f0d009ea8..3524a3c3270 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
+
+
+
+
+
+
+
+
+
+
+


Commit: 35d8b166fe0f5d3631dee0c115b83f5da1a4d122
    https://github.com/scummvm/scummvm/commit/35d8b166fe0f5d3631dee0c115b83f5da1a4d122
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Level 0 of story.cpp completed, story.h filled out, and related level.cpp revised

Changed paths:
    engines/immortal/cycle.cpp
    engines/immortal/immortal.h
    engines/immortal/level.cpp
    engines/immortal/sprite_list.h
    engines/immortal/story.cpp
    engines/immortal/story.h


diff --git a/engines/immortal/cycle.cpp b/engines/immortal/cycle.cpp
index c02570f93d6..e0a07d5cbde 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 3296f741ea4..856616dafae 100644
--- a/engines/immortal/immortal.h
+++ b/engines/immortal/immortal.h
@@ -578,6 +578,7 @@ public:
 	// Init
 	void levelInitAtStartOfGameOnly();
 	void levelInit();
+	//void levelGetCount <-- lda count
 
 	// Main
 	void levelStory(int l);
@@ -588,6 +589,9 @@ public:
 	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 1569990829d..91c3aa43b2b 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 b4e80963e62..a0829331250 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 a32b149c3a9..f35d7b8f3b8 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<int> ladders{-1, -1, kStoryNull, 2, 0, univRoom, (704 / 64),(544 / 32)};
+	_stories[0]._ladders = ladders;
+
+	/* All of the rooms
+	 */
+	Common::Array<SRoom> 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<SDoor> 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<SFlame> f5{SFlame(512 - 384,   (240 + 32) - 256, kFlameOff),    SFlame(672 - 384, (240 + 32) - 256, kFlameOff)};
+	Common::Array<SFlame> f7{SFlame(576 - 384,   (112 + 32) - 256, kFlameNormal), SFlame(576 - 384, (112 + 32) - 256, kFlameNormal),
+							 SFlame(928 - 384,   (48 + 32) - 256,  kFlameNormal)};
+	Common::Array<SFlame> f8{SFlame(800 - 640,   (144 + 32) - 160, kFlameNormal)};
+	Common::Array<SFlame> f9{SFlame(768 - 768,   (304 + 32) - 224, kFlameNormal), SFlame((928 - 768), (304 + 32) - 224, kFlameNormal),
+							 SFlame(1024 - 768,  (240 + 32) - 224, kFlameNormal)};
+	Common::Array<SFlame> 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<SFlame> fD{SFlame(1024 - 960,  (496 + 32) - 512, kFlameNormal)};
+	Common::Array<SFlame> fE{SFlame(1184 - 1024,  432 - 352, 	   kFlameCandle)};
+	Common::Array<SFlame> fF{SFlame(1024 - 896,  (144 + 32) - 64,  kFlameNormal)};
+	CArray2D<SFlame> 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<uint8> noTraps{};
+	Common::Array<uint8> o5Traps{0,0x80,0,0,0,0,0,5};
+	Common::Array<uint8> o7Traps{0,0x80,15,5,3,0,0,0};
+	Common::Array<uint8> o8Traps{0,0x80,0,0,0,0,0,3};
+
+	Common::Array<SObj> noObj{};
+	Common::Array<SObj> 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<SObj> o7{SObj(145,  138,  kTypeTrap,     kNoFrame,         kObjIsRunning + kObjIsInvisible, o7Traps)};
+	Common::Array<SObj> o8{SObj(kZip, kZip, kTypeTrap,     kNoFrame,         kObjIsRunning + kObjIsInvisible, o8Traps)};
+	Common::Array<SObj> 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<SObj> 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<SObj> 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<Motive> progShade{kMotiveRoomCombat, kMotiveShadeFind, kMotiveShadeLoose, kMotiveEngage, kMotiveUpdateGoal, kMotiveFollow, kMotiveShadeHesitate};
+	Common::Array<Motive> progEasy{kMotiveEasyRoomCombat, kMotiveFind8, kMotiveLoose4, kMotiveEngage, kMotiveUpdateGoal, kMotiveFollow};
+	Common::Array<Motive> progUlindor{kMotiveDefensiveCombat, kMotiveEngage, kMotiveUlinTalk, kMotiveGive, kMotiveUseUpMonster};
+	Common::Array<Motive> progGoblin5{kMotiveAliveRoomCombat, kMotiveFindAlways, kMotiveLoose4, kMotiveEngage, kMotiveUpdateGoal, kMotiveFollow};
+	Common::Array<Motive> progPlayer{kMotivePlayerCombat, kMotiveJoystick, kMotivePlayerDoor};
+	Common::Array<Motive> progWill2{kMotiveRoomCombat, kMotivewaittalk2, kMotiveFindAlways, kMotiveGetDisturbed, kMotiveLoose32, kMotiveUpdateGoal, kMotiveIfNot1Skip1, kMotiveFollow, kMotiveEngage};
+
+	Common::Array<SMonster> noMonst{};
+	Common::Array<SMonster> m5{SMonster(448,  344, 12, kMonstPlayer,  kMonstA + kMonstIsEngage + kMonstIsTough, progShade,   kShadow),
+					  		   SMonster(590,  381, 12, kMonstPlayer,  kMonstA + kMonstIsEngage + kMonstIsTough, progShade,   kShadow)};
+	Common::Array<SMonster> 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<SMonster> mE{SMonster(1136, 464, 15, kMonstMonster, kMonstPlayer + kMonstIsEngage,            progPlayer,  kWizard0)};
+	Common::Array<SMonster> mF{SMonster(1182, 116, 5,  kMonstPlayer,  kMonstA + kMonstIsEngage,                 progWill2,   kGoblin5)};
+	CArray2D<SMonster> 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 3524a3c3270..332e93b990e 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<class T> using CArray2D = Common::Array<Common::Array<T>>;
+
 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<uint8> _traps;
+
+	SObj(uint8 x, uint8 y, SObjType t, SpriteFrame s, uint8 f, Common::Array<uint8> 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<Motive> _program;
+
+	SMonster(uint8 x, uint8 y, uint8 h, MonsterFlag m, uint8 f, Common::Array<Motive> 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<int> _ladders;
+Common::Array<SRoom> _rooms;
+Common::Array<SDoor> _doors;
+    CArray2D<SFlame> _flames;
+      CArray2D<SObj> _objects;
+  CArray2D<SMonster> _monsters;
 };
 
 } // namespace immortal


Commit: bb56b8cdab463dfa5b1df402dea95dd27ad68e80
    https://github.com/scummvm/scummvm/commit/bb56b8cdab463dfa5b1df402dea95dd27ad68e80
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Add skeleton of Room Object

Changed paths:
  A engines/immortal/room.cpp
  A engines/immortal/room.h
    engines/immortal/immortal.h
    engines/immortal/level.cpp
    engines/immortal/module.mk
    engines/immortal/story.h


diff --git a/engines/immortal/immortal.h b/engines/immortal/immortal.h
index 856616dafae..cfb0ffe64f1 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 @@ public:
 	 */
 
 	// 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 @@ public:
 						   			  		"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 @@ public:
 							  		  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 @@ public:
 
 	/*
 	 * [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 91c3aa43b2b..0a18afd44f6 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 6c460cff60a..ac6c8f3bed0 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 00000000000..dc6f49db2ad
--- /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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#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<Monster> Room::getMonsterList() {
+	return _monsters;
+}
+
+Common::Array<Object> 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 00000000000..8c07a7f0161
--- /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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/* --- 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<Flame>   _fset;
+Common::Array<Monster> _monsters;
+Common::Array<Object>  _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<Monster> getMonsterList();
+Common::Array<Object> 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 332e93b990e..472415a0c35 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
 


Commit: 204dda79b0a3aa26f1d44ac71b173e2a6eb96541
    https://github.com/scummvm/scummvm/commit/204dda79b0a3aa26f1d44ac71b173e2a6eb96541
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Add static story STR definitions

Changed paths:
    engines/immortal/immortal.cpp
    engines/immortal/immortal.h
    engines/immortal/kernal.cpp
    engines/immortal/level.cpp
    engines/immortal/logic.cpp
    engines/immortal/story.cpp
    engines/immortal/story.h


diff --git a/engines/immortal/immortal.cpp b/engines/immortal/immortal.cpp
index 623a5cdc3dc..c75105de413 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 cfb0ffe64f1..eef656df82e 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 @@ public:
 	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 @@ public:
 	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 @@ public:
 	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<Common::String> _strPtrs;				// Str should really be a char array, but inserting frame values will be stupid so it's just a string instead
+	Common::Array<Motive>		  _motivePtrs;
+	Common::Array<Damage>		  _damagePtrs;
+	Common::Array<Use>			  _usePtrs;
+	Common::Array<Pickup>		  _pickupPtrs;
+	CArray2D<Motive>			  _programPtrs;
+	Common::Array<ObjType>		  _objTypePtrs;
 
 	// Screen members
 	  byte *_window;									// Bitmap of the window around the game
@@ -467,6 +476,7 @@ public:
 
 	// 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 @@ public:
 	 * [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 50f9fa16caf..cb2a03365c1 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<Common::String> 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<Motive>   m{};
+	_motivePtrs = m;
+
+	Common::Array<Damage>   d{};
+	_damagePtrs = d;
+
+	Common::Array<Use>      u{};
+	_usePtrs = u;
+
+	Common::Array<Pickup>   p{};
+	_pickupPtrs = p;
+
+	CArray2D<Motive>       pr{};
+	_programPtrs = pr;
+
+	Common::Array<ObjType>  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 0a18afd44f6..59ff8739c1f 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 ebeea26369a..6e04edbbb91 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 f35d7b8f3b8..875b3f5857d 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 472415a0c35..70e8fd48e49 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;


Commit: 9410617da4c0c024515d668bbf9f7bf910f00a1e
    https://github.com/scummvm/scummvm/commit/9410617da4c0c024515d668bbf9f7bf910f00a1e
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Add util.h and util.cpp, move several misc functions to util.cpp

Changed paths:
  A engines/immortal/util.cpp
  A engines/immortal/util.h
    engines/immortal/immortal.h
    engines/immortal/kernal.cpp
    engines/immortal/misc.cpp


diff --git a/engines/immortal/immortal.h b/engines/immortal/immortal.h
index eef656df82e..3287f2a0b69 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 @@ public:
 	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 @@ public:
 	// 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 @@ public:
 	  int _roomCellX;
 	  int _roomCellY;
 	Room *_rooms[kMaxRooms];							// Rooms within the level
+	Common::Array<SFlame> _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 @@ public:
 		Sprite  _sprites[kMaxSprites];					// All the sprites shown on screen
 	DataSprite  _dataSprites[kFont + 1];				// All the sprite data, indexed by SpriteFile
 	Common::Array<Common::String> _strPtrs;				// Str should really be a char array, but inserting frame values will be stupid so it's just a string instead
-	Common::Array<Motive>		  _motivePtrs;
-	Common::Array<Damage>		  _damagePtrs;
-	Common::Array<Use>			  _usePtrs;
-	Common::Array<Pickup>		  _pickupPtrs;
-	CArray2D<Motive>			  _programPtrs;
-	Common::Array<ObjType>		  _objTypePtrs;
+	Common::Array<Motive>  _motivePtrs;
+	Common::Array<Damage>  _damagePtrs;
+	Common::Array<Use>	   _usePtrs;
+	Common::Array<Pickup>  _pickupPtrs;
+	CArray2D<Motive>	   _programPtrs;
+	Common::Array<ObjType> _objTypePtrs;
 
 	// Screen members
 	  byte *_window;									// Bitmap of the window around the game
@@ -403,6 +402,8 @@ public:
     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 @@ public:
 	 */
 
 	// 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 @@ public:
 	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 @@ public:
 
 
 	/*
-	 * [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 @@ public:
 
 
 	/*
-	 * [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 cb2a03365c1..778248aa4b9 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 379e2571c1c..79e77585dd9 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 00000000000..0b6bc866ede
--- /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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#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 00000000000..ba7ef1df514
--- /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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#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


Commit: af28dec2e9d808e8f08a1bd71a0de32e22341de5
    https://github.com/scummvm/scummvm/commit/af28dec2e9d808e8f08a1bd71a0de32e22341de5
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Add bitmask.h and move bitmask enums from immortal.h to bitmask.h

Changed paths:
  A engines/immortal/bitmask.h


diff --git a/engines/immortal/bitmask.h b/engines/immortal/bitmask.h
new file mode 100644
index 00000000000..e1b7f6a4982
--- /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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#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


Commit: b761800cfb0562ecbb45ef3a778556dd0f76ac1a
    https://github.com/scummvm/scummvm/commit/b761800cfb0562ecbb45ef3a778556dd0f76ac1a
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Add definitions.h and move enums str, motives, and cyc from story.h to definitions.h

Changed paths:
  A engines/immortal/definitions.h
    engines/immortal/story.h


diff --git a/engines/immortal/definitions.h b/engines/immortal/definitions.h
new file mode 100644
index 00000000000..73082333927
--- /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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#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 70e8fd48e49..8787bf3ecdf 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<class T> using CArray2D = Common::Array<Common::Array<T>>;
 
-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<uint8> _traps;
-
+	SObj() {}
 	SObj(uint8 x, uint8 y, SObjType t, SpriteFrame s, uint8 f, Common::Array<uint8> traps) {
  		    _x = x;
  		    _y = y;
@@ -365,15 +218,15 @@ MonsterFlag _madAt = kMonstIsNone;
 	    uint8 _flags = 0;
  SpriteName _sprite = kCandle;
 Common::Array<Motive> _program;
-
+	SMonster() {}
 	SMonster(uint8 x, uint8 y, uint8 h, MonsterFlag m, uint8 f, Common::Array<Motive> 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;
 	}
 };
 


Commit: 63a6fe2851adf3c3b948a073cdb29db1e65849ed
    https://github.com/scummvm/scummvm/commit/63a6fe2851adf3c3b948a073cdb29db1e65849ed
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Update room skeleton, add flameSet, Univ, Door, and Bullet

Changed paths:
  A engines/immortal/bullet.cpp
  A engines/immortal/door.cpp
  A engines/immortal/flameSet.cpp
  A engines/immortal/univ.cpp
    engines/immortal/cycle.cpp
    engines/immortal/level.cpp
    engines/immortal/module.mk
    engines/immortal/room.cpp
    engines/immortal/room.h


diff --git a/engines/immortal/bullet.cpp b/engines/immortal/bullet.cpp
new file mode 100644
index 00000000000..e8770ec881e
--- /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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/* [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 e0a07d5cbde..eeac6188208 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 00000000000..1e93da60e60
--- /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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/* [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 00000000000..70169845ce5
--- /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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/* [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<SFlame> 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 59ff8739c1f..35139a967ea 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<SFlame> 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 ac6c8f3bed0..16713fcb935 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 dc6f49db2ad..320624f1695 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 8c07a7f0161..7b7fb846382 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 @@ public:
 	Room(uint8 x, uint8 y, RoomFlag f);
 	~Room() {}
 
+	/*
+	 * --- Data ---
+	 *
+	 */
+
+	// Constants
+	const uint8 kLightTorchX = 10;
+
 Common::Array<Flame>   _fset;
 Common::Array<Monster> _monsters;
 Common::Array<Object>  _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<Object>  _objects;
 	void addObject();
 	void removeObject();
 	void removeMonster();
-
-Common::Array<Monster> getMonsterList();
-Common::Array<Object> getObjectList();
-
+	Common::Array<Monster> getMonsterList();
+	Common::Array<Object> getObjectList();
 	void getXY(uint16 &x, uint16 &y);
 	void getCell(uint16 &x, uint16 &y);
+
+
+	/*
+	 * [flameSet.cpp] Functions from flameSet.GS
+	 */
+
+	void flameSetRoom(Common::Array<SFlame>);
+	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 00000000000..7349cdbff8a
--- /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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "immortal/immortal.h"
+
+namespace Immortal {
+
+
+} // namespace immortal
\ No newline at end of file


Commit: fe6ef5d0d681b7032cc5a2af94adaeb6a2db193e
    https://github.com/scummvm/scummvm/commit/fe6ef5d0d681b7032cc5a2af94adaeb6a2db193e
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Spaces -> Tabs

Changed paths:
    engines/immortal/bitmask.h
    engines/immortal/definitions.h
    engines/immortal/door.cpp
    engines/immortal/flameSet.cpp
    engines/immortal/misc.cpp


diff --git a/engines/immortal/bitmask.h b/engines/immortal/bitmask.h
index e1b7f6a4982..d9b5ba1509a 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 73082333927..1991d790c36 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 1e93da60e60..b31a7d5fd4f 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 70169845ce5..fe335010cf4 100644
--- a/engines/immortal/flameSet.cpp
+++ b/engines/immortal/flameSet.cpp
@@ -36,15 +36,15 @@
 namespace Immortal {
 
 void Room::flameSetRoom(Common::Array<SFlame> 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 79e77585dd9..2eb393c2265 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() {}


Commit: 22a3535e34d4789d8e19edbda7ed7c805f94fcc8
    https://github.com/scummvm/scummvm/commit/22a3535e34d4789d8e19edbda7ed7c805f94fcc8
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: levelLoadFile initializes level doors

Changed paths:
    engines/immortal/door.cpp
    engines/immortal/immortal.h
    engines/immortal/level.cpp
    engines/immortal/story.cpp
    engines/immortal/story.h


diff --git a/engines/immortal/door.cpp b/engines/immortal/door.cpp
index b31a7d5fd4f..a97820658bc 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 3287f2a0b69..927ad250d1e 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 @@ public:
 	  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 @@ public:
 	Common::Array<SFlame> _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<Door> _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 35139a967ea..b125d6ed6b3 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<SFlame> 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 875b3f5857d..e7c1424e45a 100644
--- a/engines/immortal/story.cpp
+++ b/engines/immortal/story.cpp
@@ -102,10 +102,10 @@ void ImmortalEngine::initStoryDynamic() {
 
 	/* All of the doors
 	 */
-	Common::Array<SDoor> 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<SDoor> 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 8787bf3ecdf..bcb20a001c5 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;


Commit: 3d696d0e01618c609b9308e6dd8f9a489b6cb797
    https://github.com/scummvm/scummvm/commit/3d696d0e01618c609b9308e6dd8f9a489b6cb797
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Frame -> Image, and Image/DataSprite/Cycle moved to sprite_list.h

Changed paths:
    engines/immortal/immortal.h
    engines/immortal/sprite_list.h
    engines/immortal/sprites.cpp
    engines/immortal/story.h


diff --git a/engines/immortal/immortal.h b/engines/immortal/immortal.h
index 927ad250d1e..a063b7a67b7 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<Frame> _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 @@ public:
 
 	// 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<Common::String> _strPtrs;				// Str should really be a char array, but inserting frame values will be stupid so it's just a string instead
 	Common::Array<Motive>  _motivePtrs;
 	Common::Array<Damage>  _damagePtrs;
@@ -402,7 +387,6 @@ public:
     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 a0829331250..345f31d5e3d 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<Image> _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 ae93b2f4258..83bec3c409e 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<Frame> frames;
+	Common::Array<Image> 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 bcb20a001c5..aa86734c7e9 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<class T> using CArray2D = Common::Array<Common::Array<T>>;
 
@@ -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 {
 };


Commit: 435727b52112d72a7626af4280c9377307ce7df1
    https://github.com/scummvm/scummvm/commit/435727b52112d72a7626af4280c9377307ce7df1
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Util::X -> Immortal::Util::X

Changed paths:
    engines/immortal/util.cpp


diff --git a/engines/immortal/util.cpp b/engines/immortal/util.cpp
index 0b6bc866ede..0bc671a6fbd 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


Commit: 8b5b74fc848834040ccba9bf53b3f8fb32fee60a
    https://github.com/scummvm/scummvm/commit/8b5b74fc848834040ccba9bf53b3f8fb32fee60a
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Move CycID to definitions.h

Changed paths:
    engines/immortal/definitions.h


diff --git a/engines/immortal/definitions.h b/engines/immortal/definitions.h
index 1991d790c36..db0a40c8112 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


Commit: 55be069f923191e9030d4e4d88d52bd8a240f698
    https://github.com/scummvm/scummvm/commit/55be069f923191e9030d4e4d88d52bd8a240f698
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Implement Cycles from Cyc.GS

Changed paths:
    engines/immortal/cycle.cpp
    engines/immortal/kernal.cpp
    engines/immortal/logic.cpp
    engines/immortal/room.h


diff --git a/engines/immortal/cycle.cpp b/engines/immortal/cycle.cpp
index eeac6188208..bd11ee480c0 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 778248aa4b9..fa8e0ea5697 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 6e04edbbb91..2379914705e 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<int? *>();
-	// 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 7b7fb846382..58f893182b8 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<Object>  _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<Object>  _objects;
 	 * [flameSet.cpp] Functions from flameSet.GS
 	 */
 
+	void flameInit();
 	void flameSetRoom(Common::Array<SFlame>);
 	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


Commit: 6ba6e0fa2cddab1c0d7b558aae74db4946b2eaa9
    https://github.com/scummvm/scummvm/commit/6ba6e0fa2cddab1c0d7b558aae74db4946b2eaa9
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Translation of Cycle is more accurate with addition of cycPtrs

Changed paths:
    engines/immortal/cycle.cpp
    engines/immortal/immortal.h
    engines/immortal/sprite_list.h
    engines/immortal/story.h


diff --git a/engines/immortal/cycle.cpp b/engines/immortal/cycle.cpp
index bd11ee480c0..4a43b28be70 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 a063b7a67b7..994325e1354 100644
--- a/engines/immortal/immortal.h
+++ b/engines/immortal/immortal.h
@@ -353,15 +353,16 @@ public:
 	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<Common::String> _strPtrs;				// Str should really be a char array, but inserting frame values will be stupid so it's just a string instead
 	Common::Array<Motive>  _motivePtrs;
 	Common::Array<Damage>  _damagePtrs;
 	Common::Array<Use>	   _usePtrs;
 	Common::Array<Pickup>  _pickupPtrs;
+	Common::Array<SCycle>  _cycPtrs;
 	CArray2D<Motive>	   _programPtrs;
 	Common::Array<ObjType> _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 345f31d5e3d..7633becd4b7 100644
--- a/engines/immortal/sprite_list.h
+++ b/engines/immortal/sprite_list.h
@@ -41,10 +41,8 @@ Common::Array<Image> _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 aa86734c7e9..759bcb9e8a6 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;


Commit: c0c1d2e781dc6332d1f628fcdf82e69148a0fc1e
    https://github.com/scummvm/scummvm/commit/c0c1d2e781dc6332d1f628fcdf82e69148a0fc1e
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: All engine members initialized to values now

Changed paths:
    engines/immortal/immortal.h


diff --git a/engines/immortal/immortal.h b/engines/immortal/immortal.h
index 994325e1354..4f71404eee5 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 @@ public:
 	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 @@ public:
 	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 @@ public:
 	 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 @@ public:
 	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<SFlame> _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 @@ public:
 	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<Common::String> _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 @@ public:
 	Common::Array<Damage>  _damagePtrs;
 	Common::Array<Use>	   _usePtrs;
 	Common::Array<Pickup>  _pickupPtrs;
-	Common::Array<SCycle>  _cycPtrs;
+	Common::Array<SCycle>  _cycPtrs;					// This is not actually a set of pointers, but it is serving the function of what was called cycPtrs in the source
 	CArray2D<Motive>	   _programPtrs;
 	Common::Array<ObjType> _objTypePtrs;
 
@@ -377,15 +353,15 @@ public:
     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 ---
 	 *


Commit: 1336c89bdffb36b092a3010c66623b504ff0cec3
    https://github.com/scummvm/scummvm/commit/1336c89bdffb36b092a3010c66623b504ff0cec3
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Add non-level static Cycle defintions + enum

Changed paths:
    engines/immortal/definitions.h
    engines/immortal/kernal.cpp


diff --git a/engines/immortal/definitions.h b/engines/immortal/definitions.h
index db0a40c8112..8de52483cc6 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 fa8e0ea5697..044fde879b0 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<int> cyc0{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,-1};
+	Common::Array<int> cyc1{15,16,17,18,19,20,21,22,-1};
+	Common::Array<int> cyc2{0,1,2,-1};
+	Common::Array<int> cyc3{3,4,5,-1};
+	Common::Array<int> cyc4{6,7,8,9,10,-1};
+	Common::Array<int> cyc5{11,12,13,14,15,-1};
+	Common::Array<int> cyc6{16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,-1};
+	Common::Array<int> cyc7{0,1,2,3,4,-1};
+	Common::Array<int> cyc8{5,1+5,2+5,3+5,4+5,-1};
+	Common::Array<int> cyc9{10,1+10,2+10,3+10,4+10,-1};
+	Common::Array<int> cyc10{15,1+15,2+15,3+15,4+15,-1};
+	Common::Array<int> 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<int> cyc12{0,1,2,3,4,5,6,7,8,9,-1};
+	Common::Array<int> 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<int> 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<int> cyc15{55, -1};
+	Common::Array<int> 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<int> cyc17{0,1,0,-1};
+	Common::Array<int> cyc18{0,1,2,4,5,6,7,8,9,10,11,12,2,1,-1};
+	Common::Array<int> cyc19{0,0,1,2,13,14,15,16,4,2,3,-1};
+	Common::Array<int> cyc20{0,1,2,3,20,21,22,23,24,25,26,27,5,4,3,-1};
+	Common::Array<int> cyc21{0,1,2,3,-1};
+	Common::Array<int> cyc22{0,17,18,19,3,-1};
+	Common::Array<int> cyc23{0,1,-1};
+	Common::Array<int> cyc24{28,28,28,28,-1};
+	Common::Array<int> cyc25{15,16,15,16,15,1+15,1+15,-1};
+	Common::Array<int> cyc26{10+15,11+15,12+15,13+15,14+15,15+15,16+15,-1};
+	Common::Array<int> cyc27{2+15,3+15,4+15,5+15,-1};
+	Common::Array<int> cyc28{6+15,7+15,8+15,9+15,-1};
+	Common::Array<int> 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<int> cyc30{0,1,2,3,3,3,3,4,5,6,-1};
+	Common::Array<int> cyc31{0,1,2,3,4,5,6,7,8,-1};
+
+	Common::Array<SCycle> 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<Motive>   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


Commit: ef711df128f889f1b425710216f54db5d2d6b0be
    https://github.com/scummvm/scummvm/commit/ef711df128f889f1b425710216f54db5d2d6b0be
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Util -> Utilities, and addition of addSprite to utilities

Changed paths:
  A engines/immortal/utilities.cpp
  A engines/immortal/utilities.h
  R engines/immortal/bitmask.h
  R engines/immortal/util.cpp
  R engines/immortal/util.h
    engines/immortal/module.mk


diff --git a/engines/immortal/bitmask.h b/engines/immortal/bitmask.h
deleted file mode 100644
index d9b5ba1509a..00000000000
--- 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 <http://www.gnu.org/licenses/>.
- *
- */
-
-#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 16713fcb935..3812d27981c 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 0bc671a6fbd..00000000000
--- 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 <http://www.gnu.org/licenses/>.
- *
- */
-
-#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 ba7ef1df514..00000000000
--- 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 <http://www.gnu.org/licenses/>.
- *
- */
-
-#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 00000000000..84c71b78ed2
--- /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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#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 00000000000..c41d1668b75
--- /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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#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


Commit: 5940f2312c1340ae5e7bb152964cf9cfa496db18
    https://github.com/scummvm/scummvm/commit/5940f2312c1340ae5e7bb152964cf9cfa496db18
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Add univAddSprite to univ.cpp

Changed paths:
    engines/immortal/room.h
    engines/immortal/univ.cpp


diff --git a/engines/immortal/room.h b/engines/immortal/room.h
index 58f893182b8..910101f211f 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<SCycle> p);
 	~Room() {}
 
 	/*
@@ -115,8 +116,15 @@ public:
 	 */
 
 	// Constants
-	const uint8 kLightTorchX = 10;
+	const uint8 kLightTorchX  = 10;
+	const uint8 kMaxFlameCycs = 16;
+
+	// Other
+	 Sprite *_sprites;
+	  Cycle *_cycles;
+DataSprite *_dataSprites;
 
+Common::Array<SCycle>  _cycPtrs;
 Common::Array<Flame>   _fset;
 Common::Array<Monster> _monsters;
 Common::Array<Object>  _objects;
@@ -136,6 +144,10 @@ Common::Array<Object>  _objects;
 	 *
 	 */
 
+	uint32 getRandomNumber(uint maxNum) {
+		return _randomSource.getRandomNumber(maxNum);
+	}
+
 	/*
 	 * [room.cpp] Functions from Room.GS
 	 */
@@ -145,7 +157,7 @@ Common::Array<Object>  _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<Object>  _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<SFlame>);
-	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<SFlame>);
+    int flameGetCyc(Flame *f, int first);
 
 	/*
 	 * [bullet.cpp] Functions from Bullet.GS
@@ -182,6 +222,11 @@ Common::Array<Object>  _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 7349cdbff8a..f52997c0b2f 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


Commit: 821a539b6a7e863971156f0f2ba8914c7ceeecef
    https://github.com/scummvm/scummvm/commit/821a539b6a7e863971156f0f2ba8914c7ceeecef
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Implement Cycles more accurately, under Room instead of Immortal, except for cycleFreeAll()

Changed paths:
    engines/immortal/cycle.cpp
    engines/immortal/immortal.h
    engines/immortal/level.cpp
    engines/immortal/room.cpp
    engines/immortal/sprite_list.h
    engines/immortal/story.h


diff --git a/engines/immortal/cycle.cpp b/engines/immortal/cycle.cpp
index 4a43b28be70..12b339090ba 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 4f71404eee5..0dcfe60b77a 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 @@ public:
 	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 @@ public:
 							  		  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 @@ public:
 	// 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 @@ public:
 	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 @@ public:
     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 b125d6ed6b3..93e776c3c24 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<SFlame> 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 320624f1695..9ffdcc286c7 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<SCycle> 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 7633becd4b7..ad0a9af44be 100644
--- a/engines/immortal/sprite_list.h
+++ b/engines/immortal/sprite_list.h
@@ -39,10 +39,13 @@ struct DataSprite {
 Common::Array<Image> _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 759bcb9e8a6..0fb02e69ac2 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<int> _frames;
 	   SCycle() {}
-	   SCycle(DataSprite *d, bool r, int *f) {
-	   		_dSprite = d;
+	   SCycle(SpriteName s, bool r, Common::Array<int> f) {
+	   		_sName = s;
 	   		_repeat = r;
 	   		_frames = f;
 	   }


Commit: d13fbf16a5163638b7f8c81cfa7e4af928f910f1
    https://github.com/scummvm/scummvm/commit/d13fbf16a5163638b7f8c81cfa7e4af928f910f1
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Implement flameSet.cpp

Changed paths:
    engines/immortal/flameSet.cpp


diff --git a/engines/immortal/flameSet.cpp b/engines/immortal/flameSet.cpp
index fe335010cf4..994147d01aa 100644
--- a/engines/immortal/flameSet.cpp
+++ b/engines/immortal/flameSet.cpp
@@ -35,23 +35,30 @@
 
 namespace Immortal {
 
-void Room::flameSetRoom(Common::Array<SFlame> 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<SFlame> 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


Commit: 259e993f680ec3a7dfed1749bca93298af5a5077
    https://github.com/scummvm/scummvm/commit/259e993f680ec3a7dfed1749bca93298af5a5077
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Spaces -> Tabs

Changed paths:
    engines/immortal/univ.cpp
    engines/immortal/utilities.h


diff --git a/engines/immortal/univ.cpp b/engines/immortal/univ.cpp
index f52997c0b2f..91629b24253 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 c41d1668b75..6da4088a2e4 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 {


Commit: 4b28cc268d216f26821eb3c770ecb67c07bfd9a7
    https://github.com/scummvm/scummvm/commit/4b28cc268d216f26821eb3c770ecb67c07bfd9a7
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Remove redundant namespaces in Utilities

Changed paths:
    engines/immortal/utilities.cpp
    engines/immortal/utilities.h


diff --git a/engines/immortal/utilities.cpp b/engines/immortal/utilities.cpp
index 84c71b78ed2..21ca9e13810 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 6da4088a2e4..0c8304f22f2 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
 


Commit: ff06e73d6f24ad501b037deae2c3ab0131963200
    https://github.com/scummvm/scummvm/commit/ff06e73d6f24ad501b037deae2c3ab0131963200
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Room includes reference to sprite data from ImmortalEngine

Changed paths:
    engines/immortal/level.cpp
    engines/immortal/room.cpp
    engines/immortal/room.h


diff --git a/engines/immortal/level.cpp b/engines/immortal/level.cpp
index 93e776c3c24..92510e2022f 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<SFlame> 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 9ffdcc286c7..a66573f2e83 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<SCycle> p)
+Room::Room(uint8 x, uint8 y, RoomFlag f, Sprite *s, DataSprite *d, Cycle *c, Common::Array<SCycle> 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 910101f211f..b663329a3a4 100644
--- a/engines/immortal/room.h
+++ b/engines/immortal/room.h
@@ -107,7 +107,7 @@ private:
 	Common::RandomSource _randomSource;
 
 public:
-	Room(uint8 x, uint8 y, RoomFlag f, Sprite *s, DataSprite *d, Cycle *c, Common::Array<SCycle> p);
+	Room(uint8 x, uint8 y, RoomFlag f, Sprite *s, DataSprite *d, Cycle *c, Common::Array<SCycle> p, int *n);
 	~Room() {}
 
 	/*
@@ -120,8 +120,9 @@ public:
 	const uint8 kMaxFlameCycs = 16;
 
 	// Other
-	 Sprite *_sprites;
-	  Cycle *_cycles;
+	   int *_numSprites;
+	Sprite *_sprites;
+	 Cycle *_cycles;
 DataSprite *_dataSprites;
 
 Common::Array<SCycle>  _cycPtrs;
@@ -157,7 +158,7 @@ Common::Array<Object>  _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);
 };
 
 


Commit: 89cbe5974d13b70f4729dd23047802903c15221e
    https://github.com/scummvm/scummvm/commit/89cbe5974d13b70f4729dd23047802903c15221e
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Initial implementation of superSprites() + adjustment to sprite structs

Changed paths:
    engines/immortal/cycle.cpp
    engines/immortal/flameSet.cpp
    engines/immortal/immortal.cpp
    engines/immortal/immortal.h
    engines/immortal/kernal.cpp
    engines/immortal/room.cpp
    engines/immortal/sprite_list.h
    engines/immortal/sprites.cpp
    engines/immortal/story.h
    engines/immortal/univ.cpp


diff --git a/engines/immortal/cycle.cpp b/engines/immortal/cycle.cpp
index 12b339090ba..f2da5503c5f 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 994147d01aa..c861cb67220 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 c75105de413..e6b638da1d7 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 0dcfe60b77a..703b97478e4 100644
--- a/engines/immortal/immortal.h
+++ b/engines/immortal/immortal.h
@@ -358,6 +358,9 @@ public:
     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 044fde879b0..c36e0f0d5bd 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 a66573f2e83..94107bc405b 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 ad0a9af44be..d80c37fa4aa 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<class T> using CArray2D = Common::Array<Common::Array<T>>;
+
 struct Image {
-	uint16  _deltaX;
-	uint16  _deltaY;
-	uint16  _rectX;
-	uint16  _rectY;
-	  byte *_bitmap;
+	uint16 _deltaX;
+	uint16 _deltaY;
+	uint16 _rectW;
+	uint16 _rectH;
+Common::Array<uint16> _scanWidth;
+Common::Array<uint16> _deltaPos;
+CArray2D<byte> _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<Image> _images;
 };
 
diff --git a/engines/immortal/sprites.cpp b/engines/immortal/sprites.cpp
index 83bec3c409e..1d471cd63d6 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<byte> 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 0fb02e69ac2..eeea16426e5 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<class T> using CArray2D = Common::Array<Common::Array<T>>;
-
 // 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 91629b24253..aef1aa889b6 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


Commit: b27988471cda4bb7427e18335ad36ca63b4c9b76
    https://github.com/scummvm/scummvm/commit/b27988471cda4bb7427e18335ad36ca63b4c9b76
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Implement utilities::inside() and insideRect()

Changed paths:
    engines/immortal/utilities.cpp
    engines/immortal/utilities.h


diff --git a/engines/immortal/utilities.cpp b/engines/immortal/utilities.cpp
index 21ca9e13810..4719a189eb0 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 0c8304f22f2..9ddd1844884 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


Commit: 8d9994ba56a61854af6aff98876683761299e9e8
    https://github.com/scummvm/scummvm/commit/8d9994ba56a61854af6aff98876683761299e9e8
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Sprite drawing preliminarily implemented

Changed paths:
    engines/immortal/immortal.cpp
    engines/immortal/immortal.h
    engines/immortal/sprites.cpp


diff --git a/engines/immortal/immortal.cpp b/engines/immortal/immortal.cpp
index e6b638da1d7..fd55add4e92 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 703b97478e4..02b2d5e45de 100644
--- a/engines/immortal/immortal.h
+++ b/engines/immortal/immortal.h
@@ -232,7 +232,7 @@ public:
 	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 1d471cd63d6..45e442eb3f4 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;


Commit: d8944244a1ea9610544a5cfb58b8b7cda946f132
    https://github.com/scummvm/scummvm/commit/d8944244a1ea9610544a5cfb58b8b7cda946f132
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Implement sprite drawing through superSprites()

Changed paths:
    engines/immortal/immortal.h
    engines/immortal/sprites.cpp


diff --git a/engines/immortal/immortal.h b/engines/immortal/immortal.h
index 02b2d5e45de..fe20b7cfa18 100644
--- a/engines/immortal/immortal.h
+++ b/engines/immortal/immortal.h
@@ -189,21 +189,21 @@ public:
 	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 @@ public:
 	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 45e442eb3f4..3a982a91699 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);
 	}
 
 }


Commit: 0467dbdb78162944f178ceebff169b9b4936b67d
    https://github.com/scummvm/scummvm/commit/0467dbdb78162944f178ceebff169b9b4936b67d
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Enable sprite drawing in printChr() and drawGauge()

Changed paths:
    engines/immortal/kernal.cpp
    engines/immortal/logic.cpp


diff --git a/engines/immortal/kernal.cpp b/engines/immortal/kernal.cpp
index c36e0f0d5bd..9344ac283cf 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 2379914705e..97319375a06 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);
 			}


Commit: a2bd437c5e10e0d1fa19e86347d0725c3bcb7da7
    https://github.com/scummvm/scummvm/commit/a2bd437c5e10e0d1fa19e86347d0725c3bcb7da7
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: addSprite() moved out of utilities

Changed paths:
    engines/immortal/utilities.cpp
    engines/immortal/utilities.h


diff --git a/engines/immortal/utilities.cpp b/engines/immortal/utilities.cpp
index 4719a189eb0..50957dede5e 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 9ddd1844884..c40904d8aa6 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
 


Commit: cdf322b93a71883b5ddb03ffa299184733d09d13
    https://github.com/scummvm/scummvm/commit/cdf322b93a71883b5ddb03ffa299184733d09d13
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: BMW is assumed to be in bytes and is converted to pixels for drawing

Changed paths:
    engines/immortal/sprites.cpp


diff --git a/engines/immortal/sprites.cpp b/engines/immortal/sprites.cpp
index 3a982a91699..31969a8e0a1 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<byte> 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;


Commit: a3697c3bd52f6799dec458b6ef72de164ede616d
    https://github.com/scummvm/scummvm/commit/a3697c3bd52f6799dec458b6ef72de164ede616d
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: univAddSprite() calls addSprite() through g_immortal instead of Utilities

Changed paths:
    engines/immortal/univ.cpp


diff --git a/engines/immortal/univ.cpp b/engines/immortal/univ.cpp
index aef1aa889b6..33a8861c846 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


Commit: c996c64b8c6fb578fbe6cf8991aeb6d7f064fba4
    https://github.com/scummvm/scummvm/commit/c996c64b8c6fb578fbe6cf8991aeb6d7f064fba4
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: uint8 -> uint16 for several variables + initStoryStatic moved to story.cpp

Changed paths:
    engines/immortal/story.cpp
    engines/immortal/story.h


diff --git a/engines/immortal/story.cpp b/engines/immortal/story.cpp
index e7c1424e45a..51dd0443784 100644
--- a/engines/immortal/story.cpp
+++ b/engines/immortal/story.cpp
@@ -47,6 +47,180 @@
 
 namespace Immortal {
 
+void ImmortalEngine::initStoryStatic() {
+	Common::Array<Common::String> 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<int> cyc0{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,-1};
+	Common::Array<int> cyc1{15,16,17,18,19,20,21,22,-1};
+	Common::Array<int> cyc2{0,1,2,-1};
+	Common::Array<int> cyc3{3,4,5,-1};
+	Common::Array<int> cyc4{6,7,8,9,10,-1};
+	Common::Array<int> cyc5{11,12,13,14,15,-1};
+	Common::Array<int> cyc6{16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,-1};
+	Common::Array<int> cyc7{0,1,2,3,4,-1};
+	Common::Array<int> cyc8{5,1+5,2+5,3+5,4+5,-1};
+	Common::Array<int> cyc9{10,1+10,2+10,3+10,4+10,-1};
+	Common::Array<int> cyc10{15,1+15,2+15,3+15,4+15,-1};
+	Common::Array<int> 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<int> cyc12{0,1,2,3,4,5,6,7,8,9,-1};
+	Common::Array<int> 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<int> 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<int> cyc15{55, -1};
+	Common::Array<int> 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<int> cyc17{0,1,0,-1};
+	Common::Array<int> cyc18{0,1,2,4,5,6,7,8,9,10,11,12,2,1,-1};
+	Common::Array<int> cyc19{0,0,1,2,13,14,15,16,4,2,3,-1};
+	Common::Array<int> cyc20{0,1,2,3,20,21,22,23,24,25,26,27,5,4,3,-1};
+	Common::Array<int> cyc21{0,1,2,3,-1};
+	Common::Array<int> cyc22{0,17,18,19,3,-1};
+	Common::Array<int> cyc23{0,1,-1};
+	Common::Array<int> cyc24{28,28,28,28,-1};
+	Common::Array<int> cyc25{15,16,15,16,15,1+15,1+15,-1};
+	Common::Array<int> cyc26{10+15,11+15,12+15,13+15,14+15,15+15,16+15,-1};
+	Common::Array<int> cyc27{2+15,3+15,4+15,5+15,-1};
+	Common::Array<int> cyc28{6+15,7+15,8+15,9+15,-1};
+	Common::Array<int> 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<int> cyc30{0,1,2,3,3,3,3,4,5,6,-1};
+	Common::Array<int> cyc31{0,1,2,3,4,5,6,7,8,-1};
+
+	Common::Array<SCycle> 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<Motive>   m{};
+	_motivePtrs = m;
+
+	Common::Array<Damage>   d{};
+	_damagePtrs = d;
+
+	Common::Array<Use>      u{};
+	_usePtrs = u;
+
+	Common::Array<Pickup>   p{};
+	_pickupPtrs = p;
+
+	CArray2D<Motive>       pr{};
+	_programPtrs = pr;
+
+	Common::Array<ObjType>  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 eeea16426e5..4b369dbeb3f 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<int> _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<uint8> _traps;
 	SObj() {}
-	SObj(uint8 x, uint8 y, SObjType t, SpriteFrame s, uint8 f, Common::Array<uint8> traps) {
+	SObj(uint16 x, uint16 y, SObjType t, SpriteFrame s, uint8 f, Common::Array<uint8> traps) {
  		    _x = x;
  		    _y = y;
  		 _type = t;
@@ -210,15 +210,15 @@ Common::Array<uint8> _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<Motive> _program;
 	SMonster() {}
-	SMonster(uint8 x, uint8 y, uint8 h, MonsterFlag m, uint8 f, Common::Array<Motive> p, SpriteName s) {
+	SMonster(uint16 x, uint16 y, uint16 h, MonsterFlag m, uint8 f, Common::Array<Motive> 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<int> _ladders;
 Common::Array<SRoom> _rooms;


Commit: 5c2163db8e182846ef3a9791ba7319e827d34014
    https://github.com/scummvm/scummvm/commit/5c2163db8e182846ef3a9791ba7319e827d34014
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Room object utilizes g_immortal instead of passing pointers from engine members

Changed paths:
    engines/immortal/room.cpp
    engines/immortal/room.h


diff --git a/engines/immortal/room.cpp b/engines/immortal/room.cpp
index 94107bc405b..5351375162d 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<SCycle> 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 b663329a3a4..7cc9937117b 100644
--- a/engines/immortal/room.h
+++ b/engines/immortal/room.h
@@ -107,7 +107,7 @@ private:
 	Common::RandomSource _randomSource;
 
 public:
-	Room(uint8 x, uint8 y, RoomFlag f, Sprite *s, DataSprite *d, Cycle *c, Common::Array<SCycle> p, int *n);
+	Room(uint8 x, uint8 y, RoomFlag f);
 	~Room() {}
 
 	/*
@@ -119,26 +119,20 @@ public:
 	const uint8 kLightTorchX  = 10;
 	const uint8 kMaxFlameCycs = 16;
 
-	// Other
-	   int *_numSprites;
-	Sprite *_sprites;
-	 Cycle *_cycles;
-DataSprite *_dataSprites;
-
 Common::Array<SCycle>  _cycPtrs;
 Common::Array<Flame>   _fset;
 Common::Array<Monster> _monsters;
 Common::Array<Object>  _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<SFlame>);
     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


Commit: bf95330f2cff88ae447f3e6e7054e74fded60177
    https://github.com/scummvm/scummvm/commit/bf95330f2cff88ae447f3e6e7054e74fded60177
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: level.cpp no longer passes pointers to room object

Changed paths:
    engines/immortal/level.cpp


diff --git a/engines/immortal/level.cpp b/engines/immortal/level.cpp
index 92510e2022f..61b17098756 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<SFlame> 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);
 }
 


Commit: 7284826303a1e1b61ff2739ec29c004b16a45515
    https://github.com/scummvm/scummvm/commit/7284826303a1e1b61ff2739ec29c004b16a45515
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: g_engine -> g_immortal + minor adjustments

Changed paths:
    engines/immortal/immortal.cpp
    engines/immortal/immortal.h


diff --git a/engines/immortal/immortal.cpp b/engines/immortal/immortal.cpp
index fd55add4e92..e3ce80031ed 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 fe20b7cfa18..fce55cf9ea6 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 @@ public:
 	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 @@ public:
 	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 @@ public:
 	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 @@ public:
 	Common::Array<ObjType> _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
 


Commit: 4ca64366dc0fc695431075fbff5466aec93dcee7
    https://github.com/scummvm/scummvm/commit/4ca64366dc0fc695431075fbff5466aec93dcee7
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: flameSet and Cycle utilize g_immortal instead of utilities

Changed paths:
    engines/immortal/cycle.cpp
    engines/immortal/flameSet.cpp


diff --git a/engines/immortal/cycle.cpp b/engines/immortal/cycle.cpp
index f2da5503c5f..bec8a6eba79 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 c861cb67220..32e973c0734 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;
 
 			}


Commit: 13ab4219aea5780acbe5f75bcf7ea5beeb237737
    https://github.com/scummvm/scummvm/commit/13ab4219aea5780acbe5f75bcf7ea5beeb237737
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL Remove kStrNoDesc because kStrNull exists

Changed paths:
    engines/immortal/definitions.h


diff --git a/engines/immortal/definitions.h b/engines/immortal/definitions.h
index 8de52483cc6..de431f4c9e5 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,


Commit: 9e911f29d61a1371f0eb13451691f9b8b800ed44
    https://github.com/scummvm/scummvm/commit/9e911f29d61a1371f0eb13451691f9b8b800ed44
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Text rendering through textSub() and associated functions preliminary implementation

Changed paths:
    engines/immortal/kernal.cpp
    engines/immortal/logic.cpp
    engines/immortal/misc.cpp


diff --git a/engines/immortal/kernal.cpp b/engines/immortal/kernal.cpp
index 9344ac283cf..643ee850878 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<Common::String> 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<int> cyc0{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,-1};
-	Common::Array<int> cyc1{15,16,17,18,19,20,21,22,-1};
-	Common::Array<int> cyc2{0,1,2,-1};
-	Common::Array<int> cyc3{3,4,5,-1};
-	Common::Array<int> cyc4{6,7,8,9,10,-1};
-	Common::Array<int> cyc5{11,12,13,14,15,-1};
-	Common::Array<int> cyc6{16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,-1};
-	Common::Array<int> cyc7{0,1,2,3,4,-1};
-	Common::Array<int> cyc8{5,1+5,2+5,3+5,4+5,-1};
-	Common::Array<int> cyc9{10,1+10,2+10,3+10,4+10,-1};
-	Common::Array<int> cyc10{15,1+15,2+15,3+15,4+15,-1};
-	Common::Array<int> 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<int> cyc12{0,1,2,3,4,5,6,7,8,9,-1};
-	Common::Array<int> 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<int> 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<int> cyc15{55, -1};
-	Common::Array<int> 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<int> cyc17{0,1,0,-1};
-	Common::Array<int> cyc18{0,1,2,4,5,6,7,8,9,10,11,12,2,1,-1};
-	Common::Array<int> cyc19{0,0,1,2,13,14,15,16,4,2,3,-1};
-	Common::Array<int> cyc20{0,1,2,3,20,21,22,23,24,25,26,27,5,4,3,-1};
-	Common::Array<int> cyc21{0,1,2,3,-1};
-	Common::Array<int> cyc22{0,17,18,19,3,-1};
-	Common::Array<int> cyc23{0,1,-1};
-	Common::Array<int> cyc24{28,28,28,28,-1};
-	Common::Array<int> cyc25{15,16,15,16,15,1+15,1+15,-1};
-	Common::Array<int> cyc26{10+15,11+15,12+15,13+15,14+15,15+15,16+15,-1};
-	Common::Array<int> cyc27{2+15,3+15,4+15,5+15,-1};
-	Common::Array<int> cyc28{6+15,7+15,8+15,9+15,-1};
-	Common::Array<int> 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<int> cyc30{0,1,2,3,3,3,3,4,5,6,-1};
-	Common::Array<int> cyc31{0,1,2,3,4,5,6,7,8,-1};
-
-	Common::Array<SCycle> 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<Motive>   m{};
-	_motivePtrs = m;
-
-	Common::Array<Damage>   d{};
-	_damagePtrs = d;
-
-	Common::Array<Use>      u{};
-	_usePtrs = u;
-
-	Common::Array<Pickup>   p{};
-	_pickupPtrs = p;
-
-	CArray2D<Motive>       pr{};
-	_programPtrs = pr;
-
-	Common::Array<ObjType>  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 97319375a06..0a0c9311915 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 2eb393c2265..450380b51c6 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
 
 


Commit: d47efc743b9f6cda805d185f1a7f16342c5464b5
    https://github.com/scummvm/scummvm/commit/d47efc743b9f6cda805d185f1a7f16342c5464b5
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Preliminary loadMazeGraphics() and loadUniv() functions

Changed paths:
    engines/immortal/kernal.cpp


diff --git a/engines/immortal/kernal.cpp b/engines/immortal/kernal.cpp
index 643ee850878..97a898771db 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;	


Commit: a188dced1516eeec2bab993050e0f8bf4bf41d46
    https://github.com/scummvm/scummvm/commit/a188dced1516eeec2bab993050e0f8bf4bf41d46
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Formatting and comment adjustments across all several files

Changed paths:
    engines/immortal/cycle.cpp
    engines/immortal/disk.cpp
    engines/immortal/disk.h
    engines/immortal/door.cpp
    engines/immortal/drawChr.cpp
    engines/immortal/flameSet.cpp
    engines/immortal/immortal.cpp
    engines/immortal/immortal.h
    engines/immortal/level.cpp
    engines/immortal/logic.cpp
    engines/immortal/misc.cpp
    engines/immortal/module.mk
    engines/immortal/room.h
    engines/immortal/sprite_list.h
    engines/immortal/sprites.cpp
    engines/immortal/story.cpp
    engines/immortal/story.h
    engines/immortal/utilities.cpp


diff --git a/engines/immortal/cycle.cpp b/engines/immortal/cycle.cpp
index bec8a6eba79..7d505a7a0fc 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 340a07d409e..be6103e6c30 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<ProDOSFile>(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<ProDOSFile> f = _files.getValOrDefault(name);
-	f->printInfo();
 	return f->createReadStream();
 }
 
diff --git a/engines/immortal/disk.h b/engines/immortal/disk.h
index 2d581c969c4..57c057a8eb2 100644
--- a/engines/immortal/disk.h
+++ b/engines/immortal/disk.h
@@ -95,12 +95,12 @@ public:
 	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 @@ public:
 	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<Common::String, Common::SharedPtr<ProDOSFile>> _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 a97820658bc..ee905d84e98 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 7ef77391543..9a8b8e711cc 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 32e973c0734..89732a91fde 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<SFlame> 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 e3ce80031ed..a47301a3cf2 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 fce55cf9ea6..7ff63fc7591 100644
--- a/engines/immortal/immortal.h
+++ b/engines/immortal/immortal.h
@@ -226,9 +226,9 @@ public:
 	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 @@ public:
 									  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 @@ public:
 	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 @@ public:
 
 	// 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 @@ public:
 
 	// 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 61b17098756..47822b23d18 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 0a0c9311915..20106566dd4 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 450380b51c6..38fe11f6cc1 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 3812d27981c..3d98cfe2729 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 7cc9937117b..97c25fba2f1 100644
--- a/engines/immortal/room.h
+++ b/engines/immortal/room.h
@@ -119,20 +119,21 @@ public:
 	const uint8 kLightTorchX  = 10;
 	const uint8 kMaxFlameCycs = 16;
 
-Common::Array<SCycle>  _cycPtrs;
-Common::Array<Flame>   _fset;
-Common::Array<Monster> _monsters;
-Common::Array<Object>  _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<SCycle>  _cycPtrs;
+	Common::Array<Flame>   _fset;
+	Common::Array<Monster> _monsters;
+	Common::Array<Object>  _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<Object>  _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<SFlame>);
-    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 d80c37fa4aa..26d6fb5ab6e 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<uint16> _scanWidth;
-Common::Array<uint16> _deltaPos;
-CArray2D<byte> _bitmap;
+	Common::Array<uint16> _scanWidth;
+	Common::Array<uint16> _deltaPos;
+	CArray2D<byte> _bitmap;
 };
 
 struct DataSprite {
 	uint16 _cenX;                      					// These are the base center positions
 	uint16 _cenY;
 	uint16 _numImages;
-Common::Array<Image> _images;
+	Common::Array<Image> _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 31969a8e0a1..c8c61f8ade5 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 51dd0443784..c0b39350a10 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<int> cyc0{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,-1};
 	Common::Array<int> cyc1{15,16,17,18,19,20,21,22,-1};
 	Common::Array<int> cyc2{0,1,2,-1};
@@ -158,9 +158,9 @@ void ImmortalEngine::initStoryStatic() {
 	Common::Array<int> cyc5{11,12,13,14,15,-1};
 	Common::Array<int> cyc6{16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,-1};
 	Common::Array<int> cyc7{0,1,2,3,4,-1};
-	Common::Array<int> cyc8{5,1+5,2+5,3+5,4+5,-1};
-	Common::Array<int> cyc9{10,1+10,2+10,3+10,4+10,-1};
-	Common::Array<int> cyc10{15,1+15,2+15,3+15,4+15,-1};
+	Common::Array<int> cyc8{5,1 + 5,2 + 5,3 + 5,4 + 5,-1};
+	Common::Array<int> cyc9{10,1 + 10,2 + 10,3 + 10,4 + 10,-1};
+	Common::Array<int> cyc10{15,1 + 15,2 + 15,3 + 15,4 + 15,-1};
 	Common::Array<int> 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<int> cyc12{0,1,2,3,4,5,6,7,8,9,-1};
 	Common::Array<int> 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<int> cyc22{0,17,18,19,3,-1};
 	Common::Array<int> cyc23{0,1,-1};
 	Common::Array<int> cyc24{28,28,28,28,-1};
-	Common::Array<int> cyc25{15,16,15,16,15,1+15,1+15,-1};
-	Common::Array<int> cyc26{10+15,11+15,12+15,13+15,14+15,15+15,16+15,-1};
-	Common::Array<int> cyc27{2+15,3+15,4+15,5+15,-1};
-	Common::Array<int> cyc28{6+15,7+15,8+15,9+15,-1};
+	Common::Array<int> cyc25{15,16,15,16,15,1 + 15,1 + 15,-1};
+	Common::Array<int> cyc26{10 + 15,11+ 15,12 + 15,13 + 15,14 + 15,15 + 15,16 + 15,-1};
+	Common::Array<int> cyc27{2 + 15,3 + 15,4 + 15,5 + 15,-1};
+	Common::Array<int> cyc28{6 + 15,7 + 15,8 + 15,9 + 15,-1};
 	Common::Array<int> 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<int> cyc30{0,1,2,3,3,3,3,4,5,6,-1};
 	Common::Array<int> cyc31{0,1,2,3,4,5,6,7,8,-1};
@@ -277,9 +277,9 @@ void ImmortalEngine::initStoryDynamic() {
 	/* All of the doors
 	 */
 	Common::Array<SDoor> 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<SObj> noObj{};
 	Common::Array<SObj> 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<SObj> o7{SObj(145,  138,  kTypeTrap,     kNoFrame,         kObjIsRunning + kObjIsInvisible, o7Traps)};
 	Common::Array<SObj> o8{SObj(kZip, kZip, kTypeTrap,     kNoFrame,         kObjIsRunning + kObjIsInvisible, o8Traps)};
 	Common::Array<SObj> 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<SObj> 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<SObj> objects{o5, o7, o8, o9, noObj, noObj, oE, noObj};
 	_stories[0]._objects = objects;
 
@@ -341,15 +341,19 @@ void ImmortalEngine::initStoryDynamic() {
 
 	Common::Array<SMonster> noMonst{};
 	Common::Array<SMonster> 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<SMonster> 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<SMonster> mE{SMonster(1136, 464, 15, kMonstMonster, kMonstPlayer + kMonstIsEngage,            progPlayer,  kWizard0)};
 	Common::Array<SMonster> mF{SMonster(1182, 116, 5,  kMonstPlayer,  kMonstA + kMonstIsEngage,                 progWill2,   kGoblin5)};
 	CArray2D<SMonster> 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 4b369dbeb3f..6bd87d1400f 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<int> _frames;
+	SpriteName  _sName;
+	Common::Array<int> _frames;
+	bool  _repeat;
 	   SCycle() {}
 	   SCycle(SpriteName s, bool r, Common::Array<int> 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<uint8> _traps;
+	uint16 _x = 0;
+	uint16 _y = 0;
+	uint8 _flags = 0;
+
+	SObjType _type = kTypeTrap;
+	SpriteFrame _frame = kNoFrame;
+	Common::Array<uint8> _traps;
 	SObj() {}
 	SObj(uint16 x, uint16 y, SObjType t, SpriteFrame s, uint8 f, Common::Array<uint8> 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<Motive> _program;
+	uint16 _x = 0;
+	uint16 _y = 0;
+	uint16 _hits = 0;
+	uint8 _flags = 0;
+
+	MonsterFlag _madAt = kMonstIsNone;
+	SpriteName _sprite = kCandle;
+	Common::Array<Motive> _program;
 	SMonster() {}
 	SMonster(uint16 x, uint16 y, uint16 h, MonsterFlag m, uint8 f, Common::Array<Motive> 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<int> _ladders;
-Common::Array<SRoom> _rooms;
-Common::Array<SDoor> _doors;
-    CArray2D<SFlame> _flames;
-      CArray2D<SObj> _objects;
-  CArray2D<SMonster> _monsters;
+	int _level = 0;
+	int _part  = 1;
+
+	uint16 _initialUnivX = 0;
+	uint16 _initialUnivY = 0;
+	uint16 _playerPointX = 0;
+	uint16 _playerPointY = 0;
+
+	  Common::Array<int> _ladders;
+	Common::Array<SRoom> _rooms;
+	Common::Array<SDoor> _doors;
+	    CArray2D<SFlame> _flames;
+		  CArray2D<SObj> _objects;
+ 	  CArray2D<SMonster> _monsters;
 };
 
 } // namespace immortal
diff --git a/engines/immortal/utilities.cpp b/engines/immortal/utilities.cpp
index 50957dede5e..0825510193d 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;
 	}
 


Commit: 3feb762d90017a7e2046a54451ee700f4a3ff6f8
    https://github.com/scummvm/scummvm/commit/3feb762d90017a7e2046a54451ee700f4a3ff6f8
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Implement loadUniv() and add stub for makeBlisters()

Changed paths:
    engines/immortal/immortal.h
    engines/immortal/kernal.cpp


diff --git a/engines/immortal/immortal.h b/engines/immortal/immortal.h
index 7ff63fc7591..954963bde22 100644
--- a/engines/immortal/immortal.h
+++ b/engines/immortal/immortal.h
@@ -382,11 +382,29 @@ public:
 	CArray2D<Motive>	   _programPtrs;
 	Common::Array<ObjType> _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<uint16> _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<uint16> _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 97a898771db..741ae1af6e4 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*");


Commit: 8232bfd367f8145a1f35f5f8f9c63e1e1fd0874b
    https://github.com/scummvm/scummvm/commit/8232bfd367f8145a1f35f5f8f9c63e1e1fd0874b
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Update disk.cpp to use strncpy() instead of strcpy()

Changed paths:
    engines/immortal/disk.cpp


diff --git a/engines/immortal/disk.cpp b/engines/immortal/disk.cpp
index be6103e6c30..dac2d02260d 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 */


Commit: e16f087c544ae5d121244f61466c5a9b5d08f8c5
    https://github.com/scummvm/scummvm/commit/e16f087c544ae5d121244f61466c5a9b5d08f8c5
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Rewrite loadUniv() based on new understanding of CNM

Changed paths:
    engines/immortal/drawChr.cpp
    engines/immortal/immortal.h
    engines/immortal/kernal.cpp


diff --git a/engines/immortal/drawChr.cpp b/engines/immortal/drawChr.cpp
index 9a8b8e711cc..6f0cfe87a17 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 954963bde22..47b0207876f 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 @@ public:
 	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 @@ public:
 									  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 @@ public:
 	CArray2D<Motive>	   _programPtrs;
 	Common::Array<ObjType> _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<uint16> _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<uint16> _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 741ae1af6e4..9a83108d65f 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) {


Commit: 55590df288f0d00b7172383724a2c1bd8e2423ef
    https://github.com/scummvm/scummvm/commit/55590df288f0d00b7172383724a2c1bd8e2423ef
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Fix whitespace at end of most files

Changed paths:
    engines/immortal/bullet.cpp
    engines/immortal/cycle.cpp
    engines/immortal/definitions.h
    engines/immortal/disk.cpp
    engines/immortal/disk.h
    engines/immortal/door.cpp
    engines/immortal/drawChr.cpp
    engines/immortal/flameSet.cpp
    engines/immortal/kernal.cpp
    engines/immortal/level.cpp
    engines/immortal/logic.cpp
    engines/immortal/misc.cpp
    engines/immortal/room.cpp
    engines/immortal/room.h
    engines/immortal/sprite_list.h
    engines/immortal/sprites.cpp
    engines/immortal/story.cpp
    engines/immortal/story.h
    engines/immortal/univ.cpp
    engines/immortal/utilities.cpp
    engines/immortal/utilities.h


diff --git a/engines/immortal/bullet.cpp b/engines/immortal/bullet.cpp
index e8770ec881e..e17e84c29f1 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 7d505a7a0fc..83d5cda2177 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 de431f4c9e5..d19c3debad6 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 dac2d02260d..e52a96c390c 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 57c057a8eb2..41292574db5 100644
--- a/engines/immortal/disk.h
+++ b/engines/immortal/disk.h
@@ -213,36 +213,3 @@ Common::HashMap<Common::String, Common::SharedPtr<ProDOSFile>> _files; // Hashma
 } // namespace Immortal
 
 #endif
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/engines/immortal/door.cpp b/engines/immortal/door.cpp
index ee905d84e98..f93487620b4 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 6f0cfe87a17..b898849b113 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 89732a91fde..e3c0ca2ba7f 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 9a83108d65f..e03a47597db 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 47822b23d18..5d297ba8e70 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 20106566dd4..6a7b5349d23 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 38fe11f6cc1..6a10b596c46 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 5351375162d..47de77211fb 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 97c25fba2f1..5811b589e4d 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 26d6fb5ab6e..3ef3e1307e1 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 c8c61f8ade5..170c8131b1d 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 c0b39350a10..0d598f82b24 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 6bd87d1400f..f201c8ae0e4 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 33a8861c846..9458d645f1e 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 0825510193d..46d098a2fb0 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 c40904d8aa6..d1a1fcd064f 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


Commit: 98247630c2c720008f693b95a17734e88553c60c
    https://github.com/scummvm/scummvm/commit/98247630c2c720008f693b95a17734e88553c60c
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Remove unnecessary commented line

Changed paths:
    engines/immortal/compression.cpp


diff --git a/engines/immortal/compression.cpp b/engines/immortal/compression.cpp
index 0f39f6ff806..696a635b7db 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
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-


Commit: 9cbe97d557da566cf6121c177e566a264a520b3e
    https://github.com/scummvm/scummvm/commit/9cbe97d557da566cf6121c177e566a264a520b3e
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: IMMORTAL_IMMORTAL_H -> IMMORTAL_H

Changed paths:
    engines/immortal/immortal.h


diff --git a/engines/immortal/immortal.h b/engines/immortal/immortal.h
index 47b0207876f..7b40f084f6e 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"


Commit: 4103ebe6003f3c2f9b2d2a54caa61eee42b3985f
    https://github.com/scummvm/scummvm/commit/4103ebe6003f3c2f9b2d2a54caa61eee42b3985f
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Fix formatting for switch statements

Changed paths:
    engines/immortal/flameSet.cpp
    engines/immortal/kernal.cpp
    engines/immortal/logic.cpp
    engines/immortal/misc.cpp


diff --git a/engines/immortal/flameSet.cpp b/engines/immortal/flameSet.cpp
index e3c0ca2ba7f..dcb4c9f4307 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 e03a47597db..6c565fae9ff 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 6a7b5349d23..21d8f0a2fb0 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 6a10b596c46..938488fb84f 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--;


Commit: 7e0c5b39abc444aa88d9e32bdf655b32d7f7da9b
    https://github.com/scummvm/scummvm/commit/7e0c5b39abc444aa88d9e32bdf655b32d7f7da9b
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Fix formatting for casting

Changed paths:
    engines/immortal/kernal.cpp


diff --git a/engines/immortal/kernal.cpp b/engines/immortal/kernal.cpp
index 6c565fae9ff..7677cafab60 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++) {


Commit: 8a1c1764afb84ec3bcd4960c9c4e70c9c5402a58
    https://github.com/scummvm/scummvm/commit/8a1c1764afb84ec3bcd4960c9c4e70c9c5402a58
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Add TODO comments for unimplemented methods

Changed paths:
    engines/immortal/door.cpp


diff --git a/engines/immortal/door.cpp b/engines/immortal/door.cpp
index f93487620b4..187268dab31 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() {}


Commit: 9c2e1a55a8c00abdd14d8a42a1f7bf4f2d55c554
    https://github.com/scummvm/scummvm/commit/9c2e1a55a8c00abdd14d8a42a1f7bf4f2d55c554
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Remove unused debug console channel method

Changed paths:
    engines/immortal/detection.cpp
    engines/immortal/detection.h


diff --git a/engines/immortal/detection.cpp b/engines/immortal/detection.cpp
index 3f3615cfe76..ce19d7f2b7d 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 fa4c3fcbf9a..69699995ce4 100644
--- a/engines/immortal/detection.h
+++ b/engines/immortal/detection.h
@@ -54,9 +54,6 @@ public:
 		return "(c)1990 Will Harvey & Electronic Arts";
 	}
 
-	const DebugChannelDef *getDebugChannels() const override {
-		return debugFlagList;
-	}
 };
 
 #endif


Commit: deb379462670a49dd76d12d6fe8d5d31a821ef52
    https://github.com/scummvm/scummvm/commit/deb379462670a49dd76d12d6fe8d5d31a821ef52
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Use AStyle to fix indentation and format issues across all files

Changed paths:
    engines/immortal/compression.cpp
    engines/immortal/cycle.cpp
    engines/immortal/disk.cpp
    engines/immortal/disk.h
    engines/immortal/flameSet.cpp
    engines/immortal/immortal.cpp
    engines/immortal/immortal.h
    engines/immortal/kernal.cpp
    engines/immortal/level.cpp
    engines/immortal/logic.cpp
    engines/immortal/metaengine.cpp
    engines/immortal/misc.cpp
    engines/immortal/room.h
    engines/immortal/sprite_list.h
    engines/immortal/sprites.cpp
    engines/immortal/story.cpp
    engines/immortal/story.h
    engines/immortal/utilities.cpp


diff --git a/engines/immortal/compression.cpp b/engines/immortal/compression.cpp
index 696a635b7db..08d7055149e 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 83d5cda2177..8441e1cd7b7 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 e52a96c390c..5767aefac6c 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<ProDOSFile>(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 41292574db5..284e0f794a0 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 @@ public:
 	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 @@ public:
 	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<Common::String, Common::SharedPtr<ProDOSFile>> _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<Common::String, Common::SharedPtr<ProDOSFile>> _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 dcb4c9f4307..f9a7964f8d3 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 a47301a3cf2..e7c5ca7913b 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 7b40f084f6e..2e2b520b490 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 @@ public:
 	/* 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 @@ public:
 	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<SFlame> _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<SFlame> _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<Door> _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<Common::String> _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<Common::String> _strPtrs;             // Str should really be a char array, but inserting frame values will be stupid so it's just a string instead
 	Common::Array<Motive>  _motivePtrs;
 	Common::Array<Damage>  _damagePtrs;
-	Common::Array<Use>	   _usePtrs;
+	Common::Array<Use>     _usePtrs;
 	Common::Array<Pickup>  _pickupPtrs;
-	Common::Array<SCycle>  _cycPtrs;					// This is not actually a set of pointers, but it is serving the function of what was called cycPtrs in the source
-	CArray2D<Motive>	   _programPtrs;
+	Common::Array<SCycle>  _cycPtrs;                    // This is not actually a set of pointers, but it is serving the function of what was called cycPtrs in the source
+	CArray2D<Motive>       _programPtrs;
 	Common::Array<ObjType> _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 7677cafab60..00f0d27ed3d 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 5d297ba8e70..2010da59ca3 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 21d8f0a2fb0..7cf5d084979 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 95fcb9ece99..70d628b02b9 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 938488fb84f..12465ac9ff8 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 5811b589e4d..df968d68c4e 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 @@ public:
 
 	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 @@ public:
 
 	//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 @@ public:
 	 */
 
 	// 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<SFlame>);
-	 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 3ef3e1307e1..e301a5089ac 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<Image> _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 170c8131b1d..d997fdf1db2 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 0d598f82b24..d86c6d345f5 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<Common::String> 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<int> cyc0{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,-1};
-	Common::Array<int> cyc1{15,16,17,18,19,20,21,22,-1};
-	Common::Array<int> cyc2{0,1,2,-1};
-	Common::Array<int> cyc3{3,4,5,-1};
-	Common::Array<int> cyc4{6,7,8,9,10,-1};
-	Common::Array<int> cyc5{11,12,13,14,15,-1};
-	Common::Array<int> cyc6{16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,-1};
-	Common::Array<int> cyc7{0,1,2,3,4,-1};
-	Common::Array<int> cyc8{5,1 + 5,2 + 5,3 + 5,4 + 5,-1};
-	Common::Array<int> cyc9{10,1 + 10,2 + 10,3 + 10,4 + 10,-1};
-	Common::Array<int> cyc10{15,1 + 15,2 + 15,3 + 15,4 + 15,-1};
-	Common::Array<int> 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<int> cyc12{0,1,2,3,4,5,6,7,8,9,-1};
-	Common::Array<int> 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<int> 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<int> cyc0{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, -1};
+	Common::Array<int> cyc1{15, 16, 17, 18, 19, 20, 21, 22, -1};
+	Common::Array<int> cyc2{0, 1, 2, -1};
+	Common::Array<int> cyc3{3, 4, 5, -1};
+	Common::Array<int> cyc4{6, 7, 8, 9, 10, -1};
+	Common::Array<int> cyc5{11, 12, 13, 14, 15, -1};
+	Common::Array<int> cyc6{16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, -1};
+	Common::Array<int> cyc7{0, 1, 2, 3, 4, -1};
+	Common::Array<int> cyc8{5, 1 + 5, 2 + 5, 3 + 5, 4 + 5, -1};
+	Common::Array<int> cyc9{10, 1 + 10, 2 + 10, 3 + 10, 4 + 10, -1};
+	Common::Array<int> cyc10{15, 1 + 15, 2 + 15, 3 + 15, 4 + 15, -1};
+	Common::Array<int> 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<int> cyc12{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1};
+	Common::Array<int> 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<int> 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<int> cyc15{55, -1};
-	Common::Array<int> 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<int> cyc17{0,1,0,-1};
-	Common::Array<int> cyc18{0,1,2,4,5,6,7,8,9,10,11,12,2,1,-1};
-	Common::Array<int> cyc19{0,0,1,2,13,14,15,16,4,2,3,-1};
-	Common::Array<int> cyc20{0,1,2,3,20,21,22,23,24,25,26,27,5,4,3,-1};
-	Common::Array<int> cyc21{0,1,2,3,-1};
-	Common::Array<int> cyc22{0,17,18,19,3,-1};
-	Common::Array<int> cyc23{0,1,-1};
-	Common::Array<int> cyc24{28,28,28,28,-1};
-	Common::Array<int> cyc25{15,16,15,16,15,1 + 15,1 + 15,-1};
-	Common::Array<int> cyc26{10 + 15,11+ 15,12 + 15,13 + 15,14 + 15,15 + 15,16 + 15,-1};
-	Common::Array<int> cyc27{2 + 15,3 + 15,4 + 15,5 + 15,-1};
-	Common::Array<int> cyc28{6 + 15,7 + 15,8 + 15,9 + 15,-1};
-	Common::Array<int> 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<int> cyc30{0,1,2,3,3,3,3,4,5,6,-1};
-	Common::Array<int> cyc31{0,1,2,3,4,5,6,7,8,-1};
+	Common::Array<int> 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<int> cyc17{0, 1, 0, -1};
+	Common::Array<int> cyc18{0, 1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 2, 1, -1};
+	Common::Array<int> cyc19{0, 0, 1, 2, 13, 14, 15, 16, 4, 2, 3, -1};
+	Common::Array<int> cyc20{0, 1, 2, 3, 20, 21, 22, 23, 24, 25, 26, 27, 5, 4, 3, -1};
+	Common::Array<int> cyc21{0, 1, 2, 3, -1};
+	Common::Array<int> cyc22{0, 17, 18, 19, 3, -1};
+	Common::Array<int> cyc23{0, 1, -1};
+	Common::Array<int> cyc24{28, 28, 28, 28, -1};
+	Common::Array<int> cyc25{15, 16, 15, 16, 15, 1 + 15, 1 + 15, -1};
+	Common::Array<int> cyc26{10 + 15, 11 + 15, 12 + 15, 13 + 15, 14 + 15, 15 + 15, 16 + 15, -1};
+	Common::Array<int> cyc27{2 + 15, 3 + 15, 4 + 15, 5 + 15, -1};
+	Common::Array<int> cyc28{6 + 15, 7 + 15, 8 + 15, 9 + 15, -1};
+	Common::Array<int> 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<int> cyc30{0, 1, 2, 3, 3, 3, 3, 4, 5, 6, -1};
+	Common::Array<int> cyc31{0, 1, 2, 3, 4, 5, 6, 7, 8, -1};
 
-	Common::Array<SCycle> 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<SCycle> 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<Motive>   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<int> ladders{-1, -1, kStoryNull, 2, 0, univRoom, (704 / 64),(544 / 32)};
+	Common::Array<int> ladders{-1, -1, kStoryNull, 2, 0, univRoom, (704 / 64), (544 / 32)};
 	_stories[0]._ladders = ladders;
 
 	/* All of the rooms
 	 */
 	Common::Array<SRoom> 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<SDoor> 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<SFlame> f5{SFlame(512 - 384,   (240 + 32) - 256, kFlameOff),    SFlame(672 - 384, (240 + 32) - 256, kFlameOff)};
-	Common::Array<SFlame> f7{SFlame(576 - 384,   (112 + 32) - 256, kFlameNormal), SFlame(576 - 384, (112 + 32) - 256, kFlameNormal),
-							 SFlame(928 - 384,   (48 + 32) - 256,  kFlameNormal)};
-	Common::Array<SFlame> f8{SFlame(800 - 640,   (144 + 32) - 160, kFlameNormal)};
-	Common::Array<SFlame> f9{SFlame(768 - 768,   (304 + 32) - 224, kFlameNormal), SFlame((928 - 768), (304 + 32) - 224, kFlameNormal),
-							 SFlame(1024 - 768,  (240 + 32) - 224, kFlameNormal)};
-	Common::Array<SFlame> 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<SFlame> fD{SFlame(1024 - 960,  (496 + 32) - 512, kFlameNormal)};
-	Common::Array<SFlame> fE{SFlame(1184 - 1024,  432 - 352, 	   kFlameCandle)};
-	Common::Array<SFlame> fF{SFlame(1024 - 896,  (144 + 32) - 64,  kFlameNormal)};
+	Common::Array<SFlame> f5{SFlame(512 - 384, (240 + 32) - 256, kFlameOff),    SFlame(672 - 384, (240 + 32) - 256, kFlameOff)};
+	Common::Array<SFlame> f7{SFlame(576 - 384, (112 + 32) - 256, kFlameNormal), SFlame(576 - 384, (112 + 32) - 256, kFlameNormal),
+	                         SFlame(928 - 384, (48 + 32) - 256,  kFlameNormal)};
+	Common::Array<SFlame> f8{SFlame(800 - 640, (144 + 32) - 160, kFlameNormal)};
+	Common::Array<SFlame> f9{SFlame(768 - 768, (304 + 32) - 224, kFlameNormal), SFlame((928 - 768), (304 + 32) - 224, kFlameNormal),
+	                         SFlame(1024 - 768, (240 + 32) - 224, kFlameNormal)};
+	Common::Array<SFlame> 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<SFlame> fD{SFlame(1024 - 960, (496 + 32) - 512, kFlameNormal)};
+	Common::Array<SFlame> fE{SFlame(1184 - 1024,  432 - 352,       kFlameCandle)};
+	Common::Array<SFlame> fF{SFlame(1024 - 896, (144 + 32) - 64,  kFlameNormal)};
 	CArray2D<SFlame> 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<uint8> noTraps{};
-	Common::Array<uint8> o5Traps{0,0x80,0,0,0,0,0,5};
-	Common::Array<uint8> o7Traps{0,0x80,15,5,3,0,0,0};
-	Common::Array<uint8> o8Traps{0,0x80,0,0,0,0,0,3};
+	Common::Array<uint8> o5Traps{0, 0x80, 0, 0, 0, 0, 0, 5};
+	Common::Array<uint8> o7Traps{0, 0x80, 15, 5, 3, 0, 0, 0};
+	Common::Array<uint8> o8Traps{0, 0x80, 0, 0, 0, 0, 0, 3};
 
 	Common::Array<SObj> noObj{};
 	Common::Array<SObj> 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<SObj> o7{SObj(145,  138,  kTypeTrap,     kNoFrame,         kObjIsRunning + kObjIsInvisible, o7Traps)};
 	Common::Array<SObj> o8{SObj(kZip, kZip, kTypeTrap,     kNoFrame,         kObjIsRunning + kObjIsInvisible, o8Traps)};
 	Common::Array<SObj> 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<SObj> 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<SObj> objects{o5, o7, o8, o9, noObj, noObj, oE, noObj};
 	_stories[0]._objects = objects;
 
@@ -341,10 +341,10 @@ void ImmortalEngine::initStoryDynamic() {
 
 	Common::Array<SMonster> noMonst{};
 	Common::Array<SMonster> 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<SMonster> 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<SMonster> mE{SMonster(1136, 464, 15, kMonstMonster, kMonstPlayer + kMonstIsEngage,            progPlayer,  kWizard0)};
 	Common::Array<SMonster> mF{SMonster(1182, 116, 5,  kMonstPlayer,  kMonstA + kMonstIsEngage,                 progWill2,   kGoblin5)};
 	CArray2D<SMonster> monsters{m5, noMonst, noMonst, m9, noMonst, noMonst, mE, mF};
diff --git a/engines/immortal/story.h b/engines/immortal/story.h
index f201c8ae0e4..b3cfd1732aa 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<int> _frames;
 	bool  _repeat;
-	   SCycle() {}
-	   SCycle(SpriteName s, bool r, Common::Array<int> f) {
-			_sName  = s;
-			_repeat = r;
-			_frames = f;
-	   }
+	SCycle() {}
+	SCycle(SpriteName s, bool r, Common::Array<int> 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<uint8> _traps;
 	SObj() {}
 	SObj(uint16 x, uint16 y, SObjType t, SpriteFrame s, uint8 f, Common::Array<uint8> 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<Motive> _program;
 	SMonster() {}
 	SMonster(uint16 x, uint16 y, uint16 h, MonsterFlag m, uint8 f, Common::Array<Motive> 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<int> _ladders;
+	Common::Array<int> _ladders;
 	Common::Array<SRoom> _rooms;
 	Common::Array<SDoor> _doors;
-	    CArray2D<SFlame> _flames;
-		  CArray2D<SObj> _objects;
- 	  CArray2D<SMonster> _monsters;
+	CArray2D<SFlame> _flames;
+	CArray2D<SObj> _objects;
+	CArray2D<SMonster> _monsters;
 };
 
 } // namespace immortal
diff --git a/engines/immortal/utilities.cpp b/engines/immortal/utilities.cpp
index 46d098a2fb0..03e5107fc4e 100644
--- a/engines/immortal/utilities.cpp
+++ b/engines/immortal/utilities.cpp
@@ -23,7 +23,7 @@
 
 namespace Immortal {
 
-/* 
+/*
  *
  * -----             -----
  * ----- General Use -----


Commit: ffb7ffc6eb71431d0a79a34837b232ce40c99d71
    https://github.com/scummvm/scummvm/commit/ffb7ffc6eb71431d0a79a34837b232ce40c99d71
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Pass flameSet list by reference instead of copy

Changed paths:
    engines/immortal/flameSet.cpp
    engines/immortal/room.h


diff --git a/engines/immortal/flameSet.cpp b/engines/immortal/flameSet.cpp
index f9a7964f8d3..a5f48744881 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<SFlame> allFlames) {
+void Room::flameSetRoom(Common::Array<SFlame> &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 df968d68c4e..0f26e364f2c 100644
--- a/engines/immortal/room.h
+++ b/engines/immortal/room.h
@@ -204,7 +204,7 @@ public:
 	bool roomLighted();
 	void lightTorch(uint8 x, uint8 y);
 	void flameFreeAll();
-	void flameSetRoom(Common::Array<SFlame>);
+	void flameSetRoom(Common::Array<SFlame> &allFlames);
 	int flameGetCyc(Flame *f, int first);
 
 	/*


Commit: 4116c881e628a2e9b405f959cb9b4353be6d27d5
    https://github.com/scummvm/scummvm/commit/4116c881e628a2e9b405f959cb9b4353be6d27d5
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Change loadPalette to use readUint16LE() instead of read()

Changed paths:
    engines/immortal/kernal.cpp


diff --git a/engines/immortal/kernal.cpp b/engines/immortal/kernal.cpp
index 00f0d27ed3d..2db5382ed75 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();
 }
 


Commit: 878fbe404ca5d8d56a559909a760c1b503305aa2
    https://github.com/scummvm/scummvm/commit/878fbe404ca5d8d56a559909a760c1b503305aa2
Author: Quote58 (michael.hayman54 at gmail.com)
Date: 2023-02-05T21:59:12+01:00

Commit Message:
IMMORTAL: Clean up some of the header dependancies

Changed paths:
    engines/immortal/disk.cpp
    engines/immortal/immortal.cpp
    engines/immortal/immortal.h
    engines/immortal/level.cpp
    engines/immortal/room.h
    engines/immortal/utilities.h


diff --git a/engines/immortal/disk.cpp b/engines/immortal/disk.cpp
index 5767aefac6c..1e706f56f5d 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 e7c5ca7913b..90b19ca8d3a 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 2e2b520b490..d56dfe8875b 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 2010da59ca3..67a92b702d9 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 0f26e364f2c..b6bf67833e7 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 d1a1fcd064f..79e76efebf1 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 {




More information about the Scummvm-git-logs mailing list