[Scummvm-git-logs] scummvm master -> 3334871e3aed4fad155fc6a47cbc8aab50848909

sev- noreply at scummvm.org
Sun May 12 13:08:47 UTC 2024


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

Summary:
31dc92fc4a SCUMM HE: Start working on random maps for Moonbase.
b2a158b7c4 SCUMM HE: Add Spiff Moonbase map generator.
aa79a9b687 SCUMM HE: Slightly working stat generation.
f2a8a7e2bd SCUMM HE: Moonbase maps now generated.
31f57b7dc1 SCUMM HE: Fix compile error on Windows.
bcecb72c21 SCUMM HE: Remove debug mapSize.
fbf837b91e SCUMM HE: Use float based random generation.
15e9ae85e5 SCUMM HE: Use MSVCRT's RNG algorithm.
8879b9c8dd SCUMM HE: Correct value now being used for tileSet
73e87c52c6 SCUMM HE: Fix the chance of invalid tileset.
f5f703a159 SCUMM HE: Fixed crash when generating map
77270646ed SCUMM HE: Remove no-longer used include.
b60bb0ec64 SCUMM HE: Added Katton generator.
79a5e12ed1 SCUMM HE: Fix generated map names.
9a6a4efa82 SCUMM HE: Fix compile errors on Windows.
b60f4d4069 SCUMM HE: Save generated map alongside replays.
8a6dacc607 SCUMM HE: Add toggle setting for generated maps.
2e2e2c41be SCUMM HE: GUI: Add map generator dialog and bump theme version.
289e181de0 SCUMM HE: Use new map generator dialog.
71d2c5ff61 SCUMM HE: Add map generator dialog to POTFILES.
f4c94c7b3a SCUMM HE: Hook up map generator to multiplayer.
2727e3eaf7 SCUMM HE: Only save map config on clicking "Generate".
a3eb710f7a SCUMM HE: Fix map not generating when relaying data.
8f5e44f89c SCUMM HE: Compute MD5s for maps and verify over network.
6e86d298d5 SCUMM HE: Use own network version number.
80d8e3efb4 SCUMM HE: Fix network map verification
6d1d9e8b68 SCUMM HE: Fixed MD5 mismatch bug
fcaa53b253 SCUMM HE: Fixed MD5 mismatch issue on Katton maps
6b80c4c581 COMMON: Add Base64 encoding/decoding
c5c09eece8 SCUMM HE: Use Base64 to transfer map data
267bfc9d03 COMMON: Base64 string validation.
4d3f6b7064 SCUMM HE: Fix compiling with HE v71+ disabled.
5d462c5b9c SCUMM HE: Set debug level for printing Base64 output to 2.
814dc28d35 SCUMM HE: Fix crash with no-water Katton maps
58f6e5ebe4 SCUMM HE: Fix header defines.
ebebbb2b74 SCUMM HE: Rename "cornerSum"
2d5eb18c57  SCUMM HE: Add an underscroll to all class variables.
95d12c7730 SCUMM HE: Drop typedefs in `map_mif.h`
9aacce282a SCUMM HE: Write a char variable as byte.
78e34c18ab NEWS: Mention Moonbase Commander map generator
3334871e3a SCUMM HE: Renamed constants to prevent clashing.


Commit: 31dc92fc4a7147e550b5eab35594908712f74de6
    https://github.com/scummvm/scummvm/commit/31dc92fc4a7147e550b5eab35594908712f74de6
Author: Little Cat (toontownlittlecat at gmail.com)
Date: 2024-05-12T15:08:27+02:00

Commit Message:
SCUMM HE: Start working on random maps for Moonbase.

Changed paths:
  A engines/scumm/he/moonbase/map_data.h
  A engines/scumm/he/moonbase/map_main.cpp
  A engines/scumm/he/moonbase/map_main.h
    engines/scumm/he/intern_he.h
    engines/scumm/he/moonbase/moonbase.cpp
    engines/scumm/he/moonbase/moonbase.h
    engines/scumm/he/script_v100he.cpp
    engines/scumm/he/script_v60he.cpp
    engines/scumm/module.mk
    engines/scumm/scumm.cpp


diff --git a/engines/scumm/he/intern_he.h b/engines/scumm/he/intern_he.h
index 9a14cf7b548..73e926bf5c0 100644
--- a/engines/scumm/he/intern_he.h
+++ b/engines/scumm/he/intern_he.h
@@ -42,9 +42,12 @@ class LogicHE;
 class MoviePlayer;
 class Sprite;
 class CUP_Player;
+
+class Moonbase;
 #endif
 
 class ScummEngine_v60he : public ScummEngine_v6 {
+	friend class Moonbase;
 protected:
 	enum SubOpType {
 		SO_ACTOR_DEFAULT_CLIPPED = 30,
@@ -74,6 +77,9 @@ public:
 	void setHETimer(int timer);
 	void pauseHETimers(bool pause);
 
+public:
+	Moonbase *_moonbase;
+
 public:
 	ScummEngine_v60he(OSystem *syst, const DetectorResult &dr);
 	~ScummEngine_v60he() override;
@@ -263,11 +269,9 @@ class Net;
 class Lobby;
 #endif
 #endif
-class Moonbase;
 
 class ScummEngine_v71he : public ScummEngine_v70he {
 	friend class Wiz;
-	friend class Moonbase;
 	friend class Gdi;
 
 protected:
@@ -816,7 +820,6 @@ protected:
 class ScummEngine_v100he : public ScummEngine_v99he {
 friend class AI;
 friend class Moonbase;
-friend class Net;
 
 // The following engine versions use sub opcodes from this version
 friend class ScummEngine_v71he;
@@ -1034,9 +1037,6 @@ protected:
 		SO_WAIT_FOR_SENTENCE = 131,
 	};
 
-public:
-	Moonbase *_moonbase;
-
 public:
 	ScummEngine_v100he(OSystem *syst, const DetectorResult &dr);
 	~ScummEngine_v100he() override;
diff --git a/engines/scumm/he/moonbase/map_data.h b/engines/scumm/he/moonbase/map_data.h
new file mode 100644
index 00000000000..fa019711d66
--- /dev/null
+++ b/engines/scumm/he/moonbase/map_data.h
@@ -0,0 +1,391 @@
+/* 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 SCUMM_HE_MOONBASE_MAP_DATA
+#define SCUMM_HE_MOONBASE_MAP_DATA
+
+// This header contains file data used by the map generator, mostly
+// the Template.thm and Template.wiz data taken from the Moonbase Console
+// source repository.  Gzipped manually and then converted using
+// https://notisrac.github.io/FileToCArray/ (https://github.com/notisrac/FileToCArray)
+
+// Template.thm.gz (Map Icon).
+// (https://github.com/michaelbarlow7/moonbase-console/blob/master/MoonbaseConsole/Template.thm)
+const byte Template_thm[] = {
+  0x1f, 0x8b, 0x08, 0x08, 0x5f, 0x3e, 0x4b, 0x65, 0x00, 0x03, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61,
+  0x74, 0x65, 0x2e, 0x74, 0x68, 0x6d, 0x00, 0xad, 0x97, 0x0f, 0x7c, 0x13, 0xd5, 0x1d, 0xc0, 0x7f,
+  0x97, 0x5c, 0xe1, 0xaa, 0x87, 0x1c, 0x5b, 0x26, 0x99, 0x2b, 0xa3, 0x2d, 0x4d, 0xd7, 0xac, 0x89,
+  0x23, 0xdb, 0x3a, 0x44, 0x40, 0xe8, 0x41, 0x5b, 0xe8, 0x54, 0x58, 0x90, 0x16, 0x3b, 0xd0, 0x6e,
+  0xa9, 0xb6, 0x25, 0xb2, 0xb9, 0x76, 0x0e, 0x59, 0x27, 0x64, 0x72, 0x20, 0xd0, 0x14, 0x50, 0xa2,
+  0x73, 0xac, 0x52, 0x98, 0x1e, 0xca, 0xd2, 0xb3, 0xab, 0x10, 0xb6, 0x39, 0x43, 0xbb, 0xd5, 0xa5,
+  0xfc, 0x0d, 0x0a, 0x18, 0x14, 0x24, 0xa5, 0x73, 0x7a, 0x9b, 0x28, 0x61, 0x75, 0xa5, 0xb8, 0xcd,
+  0x3d, 0xdf, 0xbb, 0x97, 0x4b, 0xd2, 0xd2, 0x7e, 0x3e, 0xeb, 0x3e, 0xbb, 0x5f, 0xaf, 0xef, 0xe5,
+  0xcf, 0xfb, 0xde, 0xef, 0xef, 0x7b, 0xbf, 0x14, 0x96, 0x2f, 0xa8, 0x00, 0x10, 0x0e, 0xe1, 0x61,
+  0x3e, 0x00, 0x98, 0x0c, 0xf8, 0x5f, 0x5e, 0xfc, 0x76, 0x96, 0x88, 0x8b, 0x01, 0x8c, 0x1c, 0x90,
+  0xcb, 0x8f, 0x05, 0xfc, 0x7e, 0xbf, 0x36, 0xf3, 0x97, 0x93, 0x69, 0x39, 0xb9, 0x10, 0x96, 0x72,
+  0x84, 0x90, 0x36, 0x43, 0xda, 0x0d, 0x30, 0x13, 0x60, 0x19, 0xc0, 0x23, 0x00, 0xcf, 0x00, 0x1c,
+  0x04, 0x88, 0x02, 0x20, 0xfb, 0x54, 0x74, 0x7b, 0x35, 0x5a, 0xd5, 0x82, 0xf6, 0x9f, 0x41, 0xbd,
+  0x7d, 0x48, 0xac, 0xf7, 0x8a, 0x0d, 0xb2, 0x28, 0xc9, 0xa2, 0x57, 0xc9, 0x19, 0x0b, 0x33, 0x4d,
+  0xb0, 0x24, 0x0b, 0x56, 0xde, 0x0c, 0x1b, 0x66, 0x40, 0xcb, 0x02, 0x68, 0xab, 0x14, 0x3a, 0x56,
+  0x65, 0x9e, 0xd8, 0x32, 0xb5, 0x47, 0x9e, 0x13, 0x7b, 0x65, 0x11, 0x3a, 0x5d, 0x89, 0x8e, 0x00,
+  0x06, 0xbb, 0xdc, 0x52, 0x2f, 0x64, 0x89, 0x00, 0xd5, 0x00, 0x4d, 0x00, 0xfb, 0x00, 0xde, 0xc2,
+  0x68, 0xfc, 0x97, 0x6f, 0x43, 0xe5, 0x4b, 0xd1, 0xba, 0xf5, 0xa8, 0xad, 0x1d, 0x9d, 0x8b, 0xe2,
+  0x6f, 0xa2, 0x08, 0x20, 0x05, 0x90, 0x04, 0x08, 0x2b, 0x32, 0x1b, 0xe0, 0x3e, 0x80, 0x46, 0x80,
+  0x97, 0x00, 0xde, 0x24, 0x0b, 0xec, 0x28, 0xbf, 0x02, 0x95, 0x3f, 0x86, 0xd6, 0xed, 0x47, 0x6d,
+  0xbd, 0xe8, 0x9c, 0x0d, 0x2e, 0xdd, 0x0d, 0xaf, 0x6e, 0x80, 0x1d, 0xfb, 0xe0, 0xc1, 0x5e, 0x28,
+  0x29, 0x86, 0x15, 0xcb, 0x60, 0x6d, 0x1d, 0xf8, 0x36, 0xc1, 0xde, 0x16, 0x38, 0x78, 0x00, 0x4e,
+  0x77, 0xe5, 0xbf, 0xfd, 0x5a, 0xf9, 0xbb, 0xe7, 0xd7, 0x7d, 0xf8, 0x7e, 0xdb, 0x95, 0xab, 0xe7,
+  0x10, 0xe4, 0x9d, 0x00, 0x67, 0x37, 0xd4, 0x3d, 0x0e, 0x4f, 0xb9, 0x61, 0xef, 0x2c, 0x66, 0x42,
+  0x9e, 0x29, 0x77, 0x66, 0xde, 0xcc, 0x45, 0x33, 0x9c, 0x55, 0x0b, 0x6b, 0x1e, 0x76, 0xad, 0x69,
+  0x5a, 0xf3, 0xe4, 0xee, 0x1d, 0xad, 0x81, 0x03, 0x5d, 0x87, 0x4f, 0x9e, 0x3d, 0x7f, 0xa9, 0xaf,
+  0x6f, 0x76, 0x2f, 0xdc, 0xfb, 0x1e, 0xac, 0xbd, 0x08, 0x2d, 0x97, 0xa1, 0xa3, 0x1f, 0x22, 0xe1,
+  0x70, 0x2c, 0xa6, 0x06, 0x02, 0xde, 0x50, 0x38, 0x5c, 0x2f, 0x2b, 0xc1, 0xa8, 0x2a, 0xfa, 0x94,
+  0x50, 0x54, 0x55, 0x22, 0x6a, 0x7d, 0xb3, 0xe2, 0xf6, 0xc9, 0x4e, 0xaf, 0xec, 0x93, 0x15, 0x39,
+  0x14, 0x11, 0x5d, 0xf5, 0xd8, 0x3f, 0xea, 0x00, 0xf2, 0x05, 0x42, 0xc4, 0x63, 0x92, 0xec, 0x6a,
+  0x0e, 0xd6, 0xcb, 0x21, 0x67, 0x83, 0xcf, 0xea, 0xf6, 0x49, 0x72, 0xb0, 0xa2, 0x5e, 0x72, 0x7a,
+  0x03, 0xc1, 0xe8, 0x80, 0x12, 0x56, 0xdd, 0x5e, 0x19, 0xbb, 0xd4, 0x17, 0x8c, 0x4a, 0x81, 0x68,
+  0x54, 0x8d, 0x45, 0x63, 0x28, 0xa2, 0x0e, 0x78, 0xe5, 0xa0, 0x1a, 0x1b, 0x08, 0x47, 0xa2, 0xa2,
+  0xdb, 0xe7, 0xf2, 0x06, 0x1d, 0x15, 0xf8, 0x8d, 0xa8, 0x12, 0x46, 0xe1, 0xe8, 0x80, 0x1c, 0x08,
+  0x87, 0xa3, 0xc8, 0xdd, 0xd0, 0xec, 0x95, 0x23, 0x4e, 0x97, 0xd4, 0x1c, 0x44, 0x8e, 0xd2, 0x86,
+  0x50, 0x58, 0x95, 0x9a, 0x07, 0x22, 0x51, 0x24, 0x2b, 0xe1, 0x50, 0x18, 0x49, 0xde, 0x60, 0x85,
+  0xab, 0x19, 0xe3, 0xbc, 0x5e, 0x5f, 0x24, 0xa2, 0x2a, 0x4a, 0x24, 0x18, 0x8c, 0x29, 0x8a, 0x2a,
+  0x35, 0xc8, 0xd1, 0xc8, 0x40, 0xbd, 0x4b, 0xae, 0x28, 0xf5, 0x4a, 0xee, 0xa0, 0xec, 0x0b, 0x05,
+  0x65, 0x35, 0xd0, 0x1c, 0x6d, 0x70, 0xc9, 0xcd, 0x0d, 0x21, 0xc9, 0x25, 0xd7, 0x3b, 0x7d, 0x5e,
+  0x97, 0x12, 0x0d, 0xc5, 0x22, 0x41, 0x55, 0x0d, 0xc7, 0x22, 0x81, 0x08, 0x8a, 0x0d, 0xe0, 0x64,
+  0x02, 0x60, 0x01, 0xd2, 0x00, 0xc6, 0x00, 0x8c, 0x05, 0xc0, 0xa9, 0x95, 0x0e, 0x70, 0x1d, 0xc0,
+  0xf5, 0x00, 0x3c, 0xc0, 0x38, 0x80, 0x1b, 0x00, 0xc6, 0x9f, 0xe8, 0x86, 0x3d, 0x3b, 0x61, 0xcd,
+  0x43, 0x30, 0x77, 0x2e, 0xf4, 0xf4, 0xf4, 0xb4, 0xb7, 0xb7, 0x4b, 0x92, 0x84, 0x53, 0xed, 0xe5,
+  0x73, 0x97, 0xd6, 0xc8, 0x47, 0xe7, 0xac, 0x6f, 0x9f, 0xb4, 0x7c, 0x03, 0xea, 0x7e, 0xfe, 0xea,
+  0xfe, 0x47, 0xfb, 0x76, 0x2f, 0xbf, 0xb8, 0xe5, 0x16, 0x94, 0x03, 0xe8, 0x36, 0x40, 0x4b, 0x01,
+  0xd5, 0x01, 0xf2, 0x02, 0xda, 0x03, 0xa8, 0x13, 0xd0, 0x59, 0xd8, 0x5d, 0x58, 0xb8, 0x7a, 0xf2,
+  0xe4, 0x0f, 0x4e, 0xad, 0xe8, 0x6e, 0xc9, 0xdf, 0xe8, 0x4a, 0xbf, 0x1c, 0xea, 0x3b, 0xf3, 0xec,
+  0x99, 0x17, 0x5c, 0x3b, 0x71, 0x36, 0x77, 0x75, 0x75, 0xed, 0x5b, 0x9c, 0xff, 0x8e, 0x7b, 0xda,
+  0x99, 0xb6, 0x06, 0x74, 0x6a, 0x7b, 0x47, 0x47, 0xc7, 0xae, 0x5d, 0xcf, 0x79, 0x3c, 0x1e, 0x9c,
+  0x4b, 0x38, 0x3d, 0x90, 0x36, 0x20, 0x6d, 0x86, 0xaf, 0xc5, 0x8b, 0x16, 0xde, 0x85, 0xdf, 0x10,
+  0x20, 0x7e, 0x39, 0xef, 0x28, 0x5c, 0x04, 0xc0, 0xf0, 0xda, 0x0b, 0xc6, 0x60, 0x64, 0xd3, 0xc6,
+  0x8c, 0xe5, 0xd2, 0xaf, 0xbb, 0x9e, 0x1f, 0x77, 0xc3, 0x78, 0x61, 0xc2, 0x67, 0x3e, 0x6b, 0xfa,
+  0xdc, 0x8d, 0x13, 0xcd, 0x9f, 0xbf, 0xe9, 0x0b, 0x19, 0x93, 0xbe, 0x38, 0x39, 0x33, 0x2b, 0x7b,
+  0x4a, 0x8e, 0x25, 0xf7, 0x4b, 0x79, 0xd6, 0x2f, 0xe7, 0xdb, 0xec, 0x37, 0x7f, 0x65, 0xaa, 0xe3,
+  0xab, 0x5f, 0xfb, 0x7a, 0xc1, 0x37, 0xa6, 0xdd, 0x32, 0xfd, 0xd6, 0x19, 0x33, 0x67, 0xdd, 0x36,
+  0x7b, 0x4e, 0xa1, 0x38, 0x77, 0x5e, 0x51, 0x71, 0xc9, 0xfc, 0x05, 0xa5, 0xdf, 0xbc, 0xfd, 0x8e,
+  0x3b, 0x17, 0x2e, 0xfa, 0x96, 0x73, 0xf1, 0x5d, 0x4b, 0xca, 0xca, 0x97, 0xde, 0x5d, 0xf1, 0xed,
+  0x65, 0xcb, 0xef, 0xb9, 0xb7, 0xf2, 0x3b, 0xdf, 0x75, 0x55, 0xdd, 0x77, 0x7f, 0x75, 0x4d, 0xed,
+  0x0a, 0xf7, 0x03, 0x2b, 0xbf, 0xf7, 0xfd, 0x07, 0x7f, 0x50, 0x57, 0xff, 0xc3, 0x87, 0x7e, 0xb4,
+  0xea, 0xe1, 0xd5, 0x3f, 0x6e, 0xf8, 0xc9, 0x23, 0x6b, 0xd6, 0x7a, 0x7e, 0xfa, 0xe8, 0x3a, 0x69,
+  0xfd, 0x86, 0xc7, 0x36, 0x6e, 0xda, 0xdc, 0xe8, 0x6d, 0xda, 0xb2, 0x75, 0xdb, 0xe3, 0x4f, 0x6c,
+  0xf7, 0x3d, 0xf9, 0xd4, 0xcf, 0x9e, 0xfe, 0xf9, 0x8e, 0x5f, 0x34, 0x3f, 0xb3, 0xb3, 0x65, 0xd7,
+  0xee, 0x5f, 0x3e, 0xfb, 0x9c, 0xbc, 0xe7, 0xf9, 0x17, 0xf6, 0xfe, 0xca, 0xdf, 0xaa, 0xbc, 0xd8,
+  0xf6, 0xeb, 0xf6, 0x97, 0xf6, 0xed, 0x0f, 0x1c, 0xf8, 0xcd, 0x6f, 0x7f, 0xf7, 0xf2, 0xef, 0x5f,
+  0x09, 0x1e, 0xec, 0xe8, 0xfc, 0xc3, 0x1f, 0xbb, 0x5e, 0xfd, 0x53, 0xa8, 0xfb, 0xd0, 0xe1, 0x23,
+  0x47, 0x8f, 0x1d, 0x0f, 0x9f, 0x78, 0xed, 0xf5, 0x93, 0xa7, 0x4e, 0xbf, 0x11, 0x39, 0xf3, 0xe6,
+  0x5b, 0x67, 0xcf, 0xbd, 0x7d, 0x3e, 0xda, 0x73, 0xa1, 0xf7, 0xcf, 0xef, 0xfc, 0xe5, 0xdd, 0xf7,
+  0xd4, 0xbf, 0xfe, 0xed, 0xfd, 0x8b, 0x1f, 0x7c, 0x78, 0x29, 0x76, 0xf9, 0xef, 0x7d, 0x1f, 0xfd,
+  0xa3, 0xff, 0xca, 0xc0, 0xd5, 0x8f, 0xff, 0xf9, 0xaf, 0x7f, 0x7f, 0xf2, 0x1f, 0x84, 0xf7, 0x8d,
+  0x79, 0x38, 0x76, 0x1b, 0x8f, 0x0b, 0xa3, 0x17, 0x45, 0x68, 0xe5, 0x1b, 0xf9, 0xcd, 0xdc, 0x26,
+  0xae, 0x96, 0xab, 0xe1, 0xe6, 0xb3, 0xd5, 0x44, 0xb8, 0x12, 0xb6, 0x04, 0xbf, 0x1a, 0x3d, 0xad,
+  0x15, 0x4b, 0x23, 0x4f, 0x48, 0x44, 0x4a, 0xd8, 0x62, 0x4d, 0x72, 0xa1, 0x08, 0xc8, 0x38, 0x6a,
+  0xcd, 0x12, 0x34, 0x4d, 0x23, 0xcc, 0x29, 0x86, 0x22, 0xd6, 0x02, 0x39, 0x78, 0x8f, 0x24, 0xf2,
+  0xbf, 0xe8, 0xb6, 0x49, 0xa3, 0x61, 0x6d, 0xc0, 0x12, 0x17, 0x30, 0x19, 0x71, 0x49, 0xe4, 0x80,
+  0x65, 0x54, 0xfa, 0x11, 0x9a, 0x1f, 0xfb, 0x8d, 0xd8, 0x49, 0x6c, 0xa3, 0xac, 0x1c, 0x52, 0x59,
+  0x1a, 0x8f, 0xc5, 0xaf, 0x46, 0x5e, 0x7d, 0x0c, 0xaf, 0x2e, 0x62, 0xb3, 0x81, 0x8a, 0x41, 0x13,
+  0x06, 0xdf, 0x39, 0x40, 0x74, 0xcb, 0xc5, 0x6b, 0x59, 0x4d, 0x08, 0x89, 0xf2, 0x88, 0x86, 0x23,
+  0xf3, 0xfc, 0xbc, 0x46, 0x62, 0xab, 0xf8, 0xc3, 0x66, 0x65, 0xba, 0x52, 0xe0, 0x75, 0x48, 0x82,
+  0xc8, 0x31, 0x5a, 0x71, 0xe8, 0x7a, 0x11, 0x06, 0x79, 0x8e, 0xce, 0x63, 0x47, 0xe0, 0xf9, 0x85,
+  0x1a, 0x8d, 0xe6, 0xb6, 0x07, 0xca, 0xde, 0xa8, 0xf0, 0x3a, 0x8e, 0x99, 0xfb, 0x4c, 0x47, 0xcd,
+  0x5e, 0x87, 0xa3, 0x34, 0x3c, 0x2b, 0x53, 0x43, 0x1a, 0xe3, 0x2c, 0x1a, 0x85, 0xa4, 0x0c, 0x47,
+  0xd3, 0xad, 0x94, 0x4d, 0x81, 0x32, 0x9f, 0xd3, 0x6d, 0x7f, 0x5a, 0xf8, 0x24, 0x63, 0x86, 0xf5,
+  0xe3, 0xa2, 0xad, 0x7c, 0x08, 0x33, 0x33, 0x99, 0x4c, 0xe6, 0x02, 0xb3, 0x8b, 0xe9, 0xd4, 0xb8,
+  0x8c, 0x26, 0x60, 0xa2, 0xa3, 0x61, 0x18, 0xfd, 0x88, 0x9d, 0x55, 0xbc, 0xa3, 0xd8, 0x59, 0x2a,
+  0x9b, 0xc6, 0x8b, 0x81, 0xb2, 0x40, 0xd9, 0x92, 0xe2, 0xab, 0x85, 0xab, 0x2d, 0x75, 0xf6, 0xad,
+  0x0e, 0xa5, 0x80, 0xd0, 0x3a, 0x19, 0x11, 0x87, 0xc0, 0x63, 0xf0, 0x18, 0x28, 0x91, 0x9c, 0xa7,
+  0x74, 0x36, 0x94, 0x77, 0x4c, 0x98, 0xa7, 0xe9, 0xa6, 0x66, 0x6c, 0x73, 0xc8, 0xa6, 0x90, 0x29,
+  0x64, 0x56, 0x33, 0x94, 0x02, 0x41, 0x9c, 0x5a, 0x1c, 0x2b, 0x0c, 0xcf, 0x72, 0xdb, 0x09, 0x2d,
+  0x53, 0xd3, 0xad, 0x93, 0x21, 0x3c, 0x4a, 0xd4, 0x79, 0x84, 0x48, 0x39, 0x35, 0xfc, 0x94, 0x44,
+  0x24, 0xe7, 0xb2, 0xc2, 0x84, 0x89, 0x69, 0x21, 0x33, 0xe5, 0x11, 0xa2, 0x8a, 0xe7, 0x92, 0x20,
+  0x09, 0x2e, 0xde, 0xc5, 0x89, 0x5c, 0x16, 0xeb, 0x61, 0x2a, 0x19, 0x12, 0x59, 0x3c, 0xd3, 0x79,
+  0x36, 0x3a, 0x50, 0xfd, 0x36, 0xf3, 0x34, 0x8e, 0xaa, 0xd9, 0x6d, 0x77, 0xdb, 0xb9, 0x2c, 0xab,
+  0xc5, 0x6a, 0x71, 0xf1, 0x6e, 0x3b, 0x25, 0xca, 0xa6, 0xf5, 0x82, 0xc4, 0x8b, 0x1a, 0x29, 0x8b,
+  0xcd, 0x64, 0x3c, 0x8c, 0x8b, 0xa7, 0x1c, 0x03, 0xb5, 0xd9, 0x96, 0x2a, 0x84, 0x47, 0xb4, 0x12,
+  0xc4, 0xf0, 0xf4, 0x40, 0x99, 0xd7, 0x41, 0x68, 0xdc, 0x24, 0xa2, 0x4d, 0xa9, 0xd5, 0x6d, 0xb7,
+  0x5a, 0x64, 0x53, 0x15, 0xef, 0xc2, 0x34, 0x6a, 0x29, 0x11, 0x17, 0x9f, 0xf4, 0x1d, 0xc0, 0x05,
+  0x23, 0x15, 0x5d, 0x3f, 0xbf, 0x66, 0xa9, 0xdb, 0x2e, 0x09, 0xb2, 0x49, 0x29, 0x50, 0x33, 0x08,
+  0x4f, 0x35, 0x13, 0x1e, 0xb6, 0x33, 0x83, 0xda, 0x1b, 0x4a, 0xd8, 0x2b, 0x72, 0x3a, 0x2d, 0xe9,
+  0x3d, 0xc2, 0xd2, 0x99, 0x0c, 0x10, 0xff, 0xcb, 0xa6, 0xfd, 0x38, 0x8a, 0x91, 0x7b, 0xac, 0x96,
+  0x7e, 0x76, 0x62, 0xda, 0xb4, 0x71, 0x47, 0xb4, 0xd5, 0x74, 0xbd, 0x24, 0x60, 0x9a, 0x36, 0x23,
+  0xf6, 0x02, 0x54, 0x6a, 0x71, 0xc8, 0xc5, 0x47, 0x97, 0x11, 0x28, 0x43, 0xd7, 0x8e, 0x8e, 0x94,
+  0x57, 0x6a, 0x25, 0x99, 0xc1, 0x65, 0xf5, 0xb3, 0xe6, 0x74, 0x73, 0xfa, 0xc4, 0xb4, 0x27, 0xf8,
+  0x15, 0xdc, 0xfd, 0xd8, 0x4e, 0xca, 0xa1, 0x76, 0xe2, 0x88, 0x32, 0x84, 0x06, 0x40, 0x6b, 0xcd,
+  0x98, 0x42, 0xd4, 0x6d, 0x07, 0xd0, 0x72, 0x97, 0xa5, 0x31, 0xe0, 0x26, 0x9d, 0xe4, 0x08, 0xef,
+  0x56, 0x7c, 0xf7, 0xc3, 0x16, 0x68, 0x62, 0xa9, 0xbf, 0x08, 0x93, 0xb0, 0x01, 0x47, 0x94, 0xc4,
+  0xc2, 0x63, 0x48, 0xd3, 0x78, 0xa4, 0x9e, 0x53, 0xbd, 0x87, 0x47, 0x5b, 0xab, 0x96, 0x71, 0x3a,
+  0xcf, 0x6a, 0x21, 0xf6, 0xde, 0x94, 0x6e, 0x4e, 0xeb, 0x87, 0x53, 0xd0, 0x8e, 0x99, 0x84, 0xa8,
+  0x65, 0x0a, 0x4f, 0xbd, 0x27, 0xf2, 0x94, 0xa8, 0xd7, 0x46, 0x32, 0x22, 0x94, 0x7b, 0x5c, 0xa8,
+  0xe6, 0xb2, 0x21, 0x64, 0x26, 0x3c, 0x4c, 0xcc, 0xba, 0xc2, 0x4d, 0x1b, 0x77, 0x63, 0xfa, 0x15,
+  0xf6, 0x14, 0xee, 0xb1, 0xb6, 0x11, 0x1d, 0x71, 0x07, 0x49, 0xb2, 0x97, 0xe8, 0x98, 0x14, 0xdd,
+  0x46, 0x06, 0x92, 0xd6, 0xd2, 0x19, 0xa9, 0x09, 0x9c, 0xc3, 0x1c, 0xd1, 0x30, 0x3c, 0x9d, 0x64,
+  0x9f, 0x30, 0xe1, 0x23, 0xee, 0x75, 0x96, 0xe8, 0xb6, 0x12, 0xcb, 0x03, 0xe0, 0xc6, 0xc4, 0x3c,
+  0x2d, 0xa6, 0x24, 0xff, 0x00, 0x52, 0x57, 0x27, 0xa3, 0x91, 0xe4, 0x1d, 0x17, 0xa6, 0x68, 0x16,
+  0x73, 0x59, 0xa4, 0x56, 0x95, 0x02, 0x49, 0x38, 0x64, 0x7a, 0x91, 0x6d, 0xd2, 0x48, 0xa5, 0xb0,
+  0x00, 0xac, 0x1a, 0x2f, 0x2f, 0x25, 0xe7, 0x92, 0xeb, 0x87, 0xd2, 0x28, 0x8f, 0x58, 0x9c, 0xcd,
+  0xd6, 0xdf, 0xe9, 0x73, 0x6e, 0x77, 0xe6, 0x65, 0xa9, 0x19, 0x92, 0x40, 0xbc, 0xb6, 0x91, 0x75,
+  0x63, 0x5a, 0x1e, 0x6e, 0x67, 0xc6, 0x40, 0x9a, 0xb6, 0x73, 0x5e, 0x9b, 0xc7, 0x43, 0xac, 0x8d,
+  0xd7, 0x07, 0xa9, 0x90, 0x2a, 0x3e, 0x3c, 0xdd, 0xe7, 0xc4, 0xf5, 0x80, 0x7d, 0x2f, 0x09, 0x56,
+  0x8b, 0x07, 0x57, 0xfd, 0x2e, 0x9c, 0x21, 0x1e, 0x43, 0x76, 0x7c, 0x67, 0x1e, 0xea, 0xfd, 0x54,
+  0xad, 0x74, 0xbb, 0xf5, 0xfd, 0x80, 0xac, 0xe1, 0xb0, 0x66, 0xa4, 0xde, 0x48, 0x8d, 0x90, 0xda,
+  0xf0, 0x30, 0xc9, 0x3a, 0xa0, 0x32, 0xd8, 0xbe, 0xc1, 0xf5, 0xa6, 0xc7, 0x87, 0xf2, 0xaa, 0x39,
+  0x03, 0x90, 0xda, 0x22, 0x75, 0x95, 0xc9, 0xe8, 0x34, 0x80, 0xe1, 0xd6, 0x0e, 0xfb, 0x4e, 0x7c,
+  0x7f, 0xa1, 0x3c, 0x05, 0xef, 0xef, 0x0c, 0x88, 0x6c, 0xc8, 0x4c, 0x33, 0x8d, 0xec, 0x21, 0x43,
+  0x59, 0xa9, 0x84, 0xc1, 0x5a, 0xa5, 0xf2, 0x0c, 0xa0, 0xc4, 0x4f, 0x41, 0xe2, 0x1d, 0xa2, 0x1d,
+  0xdd, 0xe3, 0x46, 0xe6, 0x5d, 0xab, 0x25, 0x8d, 0x83, 0x2e, 0xf1, 0x33, 0x95, 0x2f, 0xc2, 0xe1,
+  0xd3, 0x6b, 0x0b, 0xf3, 0xae, 0xb1, 0x75, 0xd0, 0xfa, 0x6b, 0xf4, 0xd5, 0xf5, 0xc3, 0x3f, 0x92,
+  0x78, 0x3f, 0xe9, 0x6d, 0xf8, 0x12, 0xed, 0xd7, 0x13, 0xd9, 0xcb, 0x45, 0xae, 0x30, 0xb1, 0xef,
+  0x0e, 0x17, 0x85, 0xa1, 0x3c, 0x6d, 0x48, 0xf0, 0x1a, 0xb5, 0x4e, 0xa9, 0x96, 0xf4, 0x35, 0xf4,
+  0x64, 0x81, 0xc1, 0x31, 0x4d, 0xb5, 0x51, 0xaf, 0x88, 0x61, 0x2c, 0x4f, 0xf0, 0x36, 0x63, 0xdd,
+  0x6a, 0x71, 0xcf, 0x45, 0xba, 0x07, 0x16, 0x0c, 0x29, 0xc4, 0x21, 0x66, 0xda, 0x92, 0xb1, 0x18,
+  0xba, 0x2b, 0x0f, 0xe6, 0xd5, 0x6a, 0xdd, 0x88, 0x05, 0xf3, 0x8c, 0xd7, 0x9c, 0xce, 0x83, 0xcf,
+  0x06, 0xb0, 0xa5, 0xc4, 0xd5, 0x36, 0xbc, 0x6c, 0x8a, 0xf7, 0x70, 0x74, 0x7f, 0x64, 0xb4, 0x4a,
+  0xd0, 0x4f, 0xbf, 0xd4, 0xe7, 0xfe, 0x77, 0x33, 0x03, 0xd0, 0x5e, 0x89, 0x74, 0x23, 0xc6, 0x44,
+  0xcf, 0x33, 0x3c, 0x8f, 0x19, 0x91, 0x02, 0x29, 0xf9, 0x4c, 0x78, 0xb9, 0x1a, 0x8d, 0xfc, 0x66,
+  0x8e, 0x57, 0xe9, 0x28, 0xb5, 0x1a, 0xcc, 0x2b, 0x61, 0x8b, 0x12, 0x3c, 0xc3, 0xff, 0x81, 0x47,
+  0xba, 0xb9, 0x91, 0x23, 0x30, 0x5a, 0xa9, 0x4d, 0xf4, 0x9a, 0x60, 0xcb, 0x89, 0x77, 0x61, 0x60,
+  0x33, 0xc4, 0x7d, 0x49, 0x9e, 0xab, 0xfb, 0x80, 0x19, 0xd1, 0x1b, 0x4c, 0xe2, 0x7b, 0x46, 0xd0,
+  0x7b, 0xe1, 0x5c, 0x96, 0xf0, 0x68, 0x8f, 0x08, 0x36, 0x63, 0x82, 0x0c, 0x09, 0x1f, 0xd0, 0x7e,
+  0xcc, 0x30, 0x24, 0x32, 0xc9, 0xa7, 0x91, 0xcf, 0x8c, 0xf0, 0x29, 0xb1, 0xab, 0x44, 0x05, 0xc8,
+  0x10, 0x00, 0x00
+};
+
+// Template.wiz.gz (Map Thumbnail; modified in-code to display stats).
+// (https://github.com/michaelbarlow7/moonbase-console/blob/master/MoonbaseConsole/Template.wiz)
+const byte Template_wiz[] = {
+  0x1f, 0x8b, 0x08, 0x08, 0xf4, 0x21, 0x4c, 0x65, 0x00, 0x03, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61,
+  0x74, 0x65, 0x2e, 0x77, 0x69, 0x7a, 0x00, 0xed, 0x5d, 0x0d, 0x9c, 0x1b, 0x45, 0x15, 0x7f, 0x48,
+  0x80, 0x05, 0x0e, 0x08, 0x7a, 0x6a, 0xda, 0x5e, 0x81, 0x53, 0xee, 0x2e, 0x69, 0x0b, 0xb4, 0x16,
+  0x84, 0x42, 0xf9, 0xe8, 0x81, 0x05, 0x22, 0x1c, 0xed, 0x1e, 0xf4, 0x20, 0x82, 0x20, 0x9b, 0x0a,
+  0x12, 0x51, 0xb8, 0x88, 0x80, 0x91, 0xb6, 0x72, 0x4b, 0x01, 0x09, 0x28, 0x12, 0x50, 0xe1, 0xa0,
+  0x54, 0x08, 0x1f, 0x96, 0x58, 0x4b, 0x2f, 0xa8, 0x48, 0x28, 0x5a, 0x4c, 0x05, 0x34, 0x45, 0xc0,
+  0x14, 0x28, 0xa4, 0x56, 0xa4, 0x8b, 0x7c, 0xf4, 0xb0, 0x4a, 0x83, 0xf8, 0x31, 0xee, 0x64, 0x32,
+  0xd9, 0xd9, 0xdd, 0xd9, 0x7c, 0xb4, 0xb9, 0x66, 0xfd, 0xed, 0xe6, 0xdf, 0x6b, 0x76, 0xdf, 0xbe,
+  0x9d, 0xbc, 0xfd, 0xef, 0xdb, 0x99, 0x79, 0x33, 0xbb, 0x6f, 0x67, 0x0d, 0x9c, 0x1c, 0x02, 0xb8,
+  0xe3, 0x48, 0xf5, 0xeb, 0x24, 0x00, 0x68, 0xff, 0x90, 0xfa, 0xdf, 0x0d, 0xe5, 0x3f, 0xf1, 0xc4,
+  0xde, 0x7e, 0x80, 0x9d, 0x05, 0xc0, 0x9f, 0x65, 0x2a, 0x60, 0xd9, 0xb2, 0x65, 0xa5, 0xa5, 0x65,
+  0x03, 0x78, 0x71, 0x00, 0x7f, 0x90, 0x8a, 0x01, 0x84, 0x50, 0x69, 0x09, 0x95, 0xfe, 0x00, 0x66,
+  0x02, 0x9c, 0x0d, 0x70, 0x15, 0xc0, 0x9d, 0x00, 0x8f, 0x03, 0x14, 0x00, 0xd0, 0x41, 0x53, 0xd1,
+  0x29, 0x17, 0xa0, 0xcb, 0x97, 0xa0, 0x91, 0x75, 0x68, 0xe3, 0x16, 0xd4, 0x1b, 0x8d, 0xf7, 0xc6,
+  0x92, 0xbd, 0x72, 0xb2, 0x37, 0x9e, 0x3a, 0x70, 0x37, 0x98, 0xd9, 0x0e, 0x67, 0x74, 0xc2, 0xc5,
+  0x07, 0xc3, 0xe2, 0xa3, 0x60, 0xc9, 0xc9, 0xb0, 0xfc, 0x3c, 0xef, 0xaa, 0xcb, 0x0f, 0x58, 0x7b,
+  0xd3, 0xd4, 0x0d, 0xc9, 0xe3, 0x46, 0x1f, 0x9b, 0x83, 0x5e, 0x38, 0x0f, 0x3d, 0x0d, 0x6a, 0xc1,
+  0x52, 0x44, 0xde, 0x08, 0x9d, 0xbd, 0x00, 0x17, 0x00, 0xdc, 0x08, 0xb0, 0x12, 0xe0, 0x25, 0xb5,
+  0x68, 0xf5, 0xdf, 0xe4, 0x29, 0x68, 0xe0, 0x4c, 0x34, 0x74, 0x0d, 0x5a, 0xbe, 0x02, 0xad, 0x2f,
+  0xa8, 0x9a, 0x28, 0x0f, 0x28, 0x05, 0x48, 0x06, 0xa4, 0x1a, 0x72, 0x2c, 0xc0, 0xfc, 0xd2, 0x21,
+  0x3d, 0x0c, 0xf0, 0x22, 0xde, 0xe1, 0x20, 0x34, 0x39, 0x84, 0x06, 0xae, 0x45, 0x43, 0x23, 0x68,
+  0xf9, 0x46, 0xb4, 0x7e, 0x0a, 0x6c, 0x3e, 0x0b, 0x9e, 0x5c, 0x0c, 0xb7, 0xaf, 0x84, 0x4b, 0x36,
+  0xc2, 0x89, 0xb3, 0xe1, 0xa2, 0xb3, 0x61, 0xe1, 0x20, 0x24, 0xae, 0x87, 0x07, 0x97, 0xc0, 0xe3,
+  0x8f, 0xc0, 0x0b, 0xab, 0x27, 0xbf, 0xf2, 0xec, 0xc0, 0xeb, 0xaf, 0x0e, 0xbd, 0xf3, 0xe6, 0xf2,
+  0xad, 0xef, 0xaf, 0x47, 0xe0, 0x5f, 0x0b, 0xe2, 0x1a, 0x18, 0xbc, 0x19, 0x6e, 0x8b, 0xc0, 0x83,
+  0x47, 0xef, 0xb4, 0xaf, 0xbf, 0xbd, 0x7b, 0xa6, 0x7f, 0xe6, 0x9c, 0xa3, 0xc4, 0xf0, 0x69, 0x17,
+  0x5e, 0x21, 0x2d, 0xb8, 0x71, 0xc1, 0xad, 0x4b, 0x6f, 0x7f, 0x28, 0xfd, 0xc8, 0xea, 0xa7, 0x9e,
+  0x7b, 0xf9, 0xd5, 0xcd, 0x5b, 0xb6, 0x1c, 0xbb, 0x11, 0xce, 0xdd, 0x04, 0x0b, 0xdf, 0x82, 0x25,
+  0xef, 0xc2, 0xaa, 0xf7, 0x20, 0x9f, 0xcb, 0x8d, 0x8e, 0x2a, 0xe9, 0x74, 0x3c, 0x9b, 0xcb, 0x45,
+  0x93, 0xa9, 0x4c, 0x41, 0xe9, 0x4d, 0xa4, 0xb2, 0x05, 0x25, 0x95, 0x57, 0xa2, 0xc3, 0xa9, 0x48,
+  0x22, 0x29, 0xc6, 0x93, 0x89, 0x64, 0x2a, 0x99, 0xcd, 0xf7, 0x4a, 0x51, 0x95, 0x1f, 0xa5, 0x88,
+  0x12, 0xe9, 0x2c, 0x66, 0x4c, 0x4e, 0x4a, 0xc3, 0x99, 0x68, 0x32, 0x2b, 0xc6, 0x12, 0x81, 0x48,
+  0x42, 0x4e, 0x66, 0x42, 0x51, 0x59, 0x8c, 0xa7, 0x33, 0x85, 0x62, 0x2a, 0xa7, 0x44, 0xe2, 0x49,
+  0x95, 0xd2, 0x44, 0xa6, 0x20, 0xa7, 0x0b, 0x05, 0x65, 0xb4, 0x30, 0x8a, 0xf2, 0x4a, 0x31, 0x9e,
+  0xcc, 0x28, 0xa3, 0xc5, 0x5c, 0xbe, 0xd0, 0x1b, 0x49, 0x48, 0xf1, 0xcc, 0xb4, 0x90, 0x2a, 0x28,
+  0xa4, 0x72, 0x28, 0x57, 0x28, 0x26, 0xd3, 0xb9, 0x5c, 0x01, 0x45, 0x62, 0xc3, 0xf1, 0x64, 0x5e,
+  0x94, 0xe4, 0xe1, 0x0c, 0x9a, 0x16, 0x8c, 0x65, 0x73, 0x8a, 0x3c, 0x5c, 0xcc, 0x17, 0x50, 0x32,
+  0x95, 0xcb, 0xe6, 0x90, 0x1c, 0xcf, 0x84, 0xa4, 0x61, 0xb5, 0xb8, 0x78, 0x3c, 0x91, 0xcf, 0x2b,
+  0xa9, 0x54, 0x3e, 0x93, 0x19, 0x4d, 0xa5, 0x14, 0x39, 0x96, 0x2c, 0xe4, 0x8b, 0x51, 0x29, 0x19,
+  0x0a, 0xc6, 0xe5, 0x48, 0x26, 0x99, 0xc8, 0x66, 0x92, 0x4a, 0x7a, 0xb8, 0x10, 0x93, 0x92, 0xc3,
+  0xb1, 0xac, 0x2c, 0x25, 0xa3, 0x62, 0x22, 0x2e, 0xa5, 0x0a, 0xd9, 0xd1, 0x7c, 0x46, 0x51, 0x72,
+  0xa3, 0xf9, 0x74, 0x1e, 0x8d, 0x16, 0x55, 0x67, 0x02, 0xf0, 0x00, 0xec, 0x02, 0xb0, 0x2b, 0xc0,
+  0x6e, 0x00, 0xaa, 0x6b, 0xed, 0x0e, 0xb0, 0x07, 0xc0, 0x9e, 0x00, 0x6d, 0x00, 0x7b, 0x01, 0xec,
+  0x0d, 0xb0, 0xcf, 0xda, 0x35, 0x70, 0xdf, 0x5d, 0xb0, 0xe0, 0x32, 0x38, 0xfe, 0x78, 0xd8, 0xb0,
+  0x61, 0xc3, 0x8a, 0x15, 0x2b, 0x64, 0x59, 0x56, 0x5d, 0xed, 0xd1, 0xf5, 0x9b, 0x17, 0x24, 0x9f,
+  0x39, 0xee, 0x9a, 0x15, 0x13, 0xcf, 0x59, 0x8c, 0xd6, 0xdc, 0xff, 0xfe, 0xc8, 0xd5, 0x5b, 0x96,
+  0x9e, 0xf3, 0xd6, 0x4d, 0x47, 0xa0, 0x03, 0x01, 0x1d, 0x03, 0xe8, 0x4c, 0x40, 0x83, 0x80, 0xe2,
+  0x80, 0xee, 0x03, 0xf4, 0x04, 0xa0, 0x97, 0x61, 0xe9, 0xac, 0x59, 0x57, 0xee, 0xbf, 0xff, 0xdb,
+  0xcf, 0x5f, 0xb4, 0x66, 0xc9, 0xe4, 0xeb, 0xa4, 0xdd, 0xdf, 0xcd, 0x6e, 0x59, 0x77, 0xcf, 0xba,
+  0x07, 0xa4, 0xbb, 0x54, 0x6f, 0x5e, 0xbd, 0x7a, 0xf5, 0xca, 0xfe, 0xc9, 0xaf, 0x45, 0x0e, 0x5f,
+  0xb7, 0x3c, 0x86, 0x9e, 0xbf, 0x65, 0xd5, 0xaa, 0x55, 0x77, 0xdf, 0x7d, 0xef, 0xa2, 0x45, 0x8b,
+  0x54, 0x5f, 0x52, 0xdd, 0x03, 0x95, 0xbe, 0x50, 0x69, 0x49, 0xfd, 0xf4, 0xcf, 0x39, 0xed, 0x74,
+  0x55, 0xe0, 0x85, 0xf2, 0x47, 0x3c, 0x75, 0xd6, 0x1c, 0x80, 0x9d, 0xda, 0x4a, 0x2b, 0x3b, 0x7d,
+  0x68, 0x67, 0xcf, 0x2e, 0xbb, 0xee, 0x26, 0xec, 0xbe, 0xc7, 0x9e, 0x6d, 0x7b, 0xed, 0xbd, 0x8f,
+  0x77, 0xdf, 0x0f, 0x7f, 0xa4, 0xfd, 0xa3, 0x1f, 0xfb, 0xb8, 0x6f, 0xdc, 0xf8, 0x09, 0x1d, 0x13,
+  0xf7, 0xdb, 0xff, 0x80, 0xce, 0x4f, 0x7c, 0xf2, 0xc0, 0xae, 0xee, 0x1e, 0x7f, 0x60, 0xd2, 0xe4,
+  0x29, 0x07, 0x1d, 0x7c, 0xc8, 0xd4, 0x69, 0x9f, 0x9a, 0x7e, 0xe8, 0x61, 0x9f, 0x3e, 0xfc, 0x88,
+  0x19, 0x47, 0x1e, 0x35, 0xf3, 0xe8, 0x63, 0x8e, 0x3d, 0x6e, 0x56, 0xef, 0xf1, 0x27, 0x7c, 0x66,
+  0xf6, 0x89, 0x27, 0x9d, 0x1c, 0xfc, 0xec, 0x29, 0xa7, 0xf6, 0x9d, 0x36, 0x67, 0xae, 0xd8, 0x7f,
+  0xfa, 0x19, 0xf3, 0x06, 0xce, 0x3c, 0x2b, 0xf4, 0xb9, 0xb3, 0xcf, 0xf9, 0xfc, 0xb9, 0xe7, 0x7d,
+  0xe1, 0x7c, 0x29, 0x3c, 0xff, 0x8b, 0x17, 0x5c, 0xf8, 0xa5, 0x8b, 0x22, 0x5f, 0xbe, 0xf8, 0x2b,
+  0x5f, 0xbd, 0xe4, 0xd2, 0xc1, 0xe8, 0xd7, 0x2e, 0xfb, 0xfa, 0xe5, 0x57, 0x5c, 0xf9, 0x8d, 0xd8,
+  0x37, 0xaf, 0x5a, 0xb0, 0x70, 0xd1, 0xb7, 0xae, 0x1e, 0x92, 0xaf, 0x59, 0x7c, 0xed, 0x75, 0xd7,
+  0x7f, 0xfb, 0x86, 0xf8, 0x8d, 0x37, 0x7d, 0xe7, 0xbb, 0x37, 0x7f, 0xef, 0x96, 0xc4, 0xad, 0xb7,
+  0x7d, 0xff, 0x07, 0x3f, 0xbc, 0xfd, 0x8e, 0xe1, 0x3b, 0xef, 0x5a, 0x72, 0xf7, 0xd2, 0x1f, 0xdd,
+  0x73, 0x6f, 0xf2, 0xbe, 0xfb, 0x1f, 0x78, 0xf0, 0xc7, 0xcb, 0x1e, 0x4a, 0xfd, 0x64, 0xf9, 0x4f,
+  0x57, 0x3c, 0xbc, 0x72, 0x24, 0xfd, 0xc8, 0xcf, 0x7e, 0xfe, 0x8b, 0x47, 0x7f, 0xf9, 0x58, 0xe6,
+  0xf1, 0x55, 0x4f, 0xfc, 0xea, 0xd7, 0xab, 0x9f, 0xfc, 0x4d, 0x76, 0xcd, 0x6f, 0x9f, 0x7a, 0xfa,
+  0x99, 0xdf, 0xfd, 0x3e, 0xb7, 0xf6, 0xd9, 0x3f, 0x3c, 0xf7, 0xfc, 0x0b, 0x7f, 0xcc, 0xaf, 0x7b,
+  0xf1, 0xa5, 0x97, 0xd7, 0xbf, 0xf2, 0x6a, 0x61, 0xc3, 0x9f, 0x36, 0xfe, 0xf9, 0xb5, 0xbf, 0xbc,
+  0xbe, 0x49, 0x79, 0xe3, 0xaf, 0x6f, 0xbe, 0xf5, 0xf6, 0x3b, 0x9b, 0x47, 0xdf, 0xfd, 0xdb, 0x96,
+  0xbf, 0xff, 0xe3, 0xbd, 0xad, 0xc5, 0xf7, 0xff, 0xf9, 0xc1, 0xbf, 0xfe, 0xfd, 0x9f, 0xff, 0x22,
+  0xb5, 0xde, 0x38, 0x01, 0xe0, 0xb6, 0x0f, 0xe6, 0xb6, 0xb9, 0x70, 0x36, 0x06, 0xbd, 0x97, 0x7a,
+  0xe7, 0x7a, 0xcb, 0x6b, 0x5e, 0xfd, 0x5a, 0xab, 0x6d, 0x6b, 0x1d, 0x06, 0xbd, 0x18, 0x25, 0x06,
+  0xbc, 0x83, 0x5e, 0xfd, 0x5a, 0xab, 0x6d, 0x6b, 0x35, 0x2b, 0x98, 0x81, 0x4b, 0x2b, 0xac, 0xd0,
+  0xb5, 0x56, 0xdb, 0x66, 0x07, 0x56, 0x06, 0x75, 0xac, 0x0c, 0xba, 0xac, 0xb8, 0xac, 0x70, 0x59,
+  0x71, 0xeb, 0x15, 0x33, 0x2b, 0x73, 0xcb, 0x3c, 0xcc, 0xf5, 0xea, 0xd7, 0x5a, 0x6d, 0x9b, 0x0b,
+  0x7b, 0xa1, 0xe2, 0x1d, 0x95, 0x6b, 0x48, 0x5b, 0x6b, 0xb5, 0x6d, 0xad, 0x65, 0xc5, 0xad, 0x57,
+  0xf8, 0xac, 0x0c, 0x7a, 0xe7, 0x7a, 0x75, 0x6d, 0x90, 0xd7, 0x6d, 0x83, 0x5c, 0x56, 0xb6, 0x9d,
+  0x95, 0xe9, 0x5e, 0xe7, 0x20, 0x5a, 0x42, 0xbf, 0xba, 0xd4, 0x5f, 0x5e, 0xa6, 0x6b, 0xfd, 0x06,
+  0xcd, 0x0e, 0xf7, 0xc3, 0xf9, 0x4c, 0x70, 0xe1, 0xa2, 0x4e, 0x4c, 0x11, 0x5c, 0x98, 0x11, 0x10,
+  0x26, 0x8d, 0x01, 0x02, 0xdb, 0x8c, 0xb1, 0xb0, 0xa6, 0x31, 0x04, 0x4b, 0xf6, 0xd7, 0x3c, 0x42,
+  0x8f, 0x9f, 0x81, 0x26, 0xd5, 0xe4, 0x01, 0x0f, 0xd5, 0xeb, 0xa9, 0x40, 0x95, 0xaa, 0x65, 0xb3,
+  0x12, 0x2a, 0xd3, 0x4b, 0xcb, 0xb2, 0x52, 0x39, 0x64, 0x9d, 0x2d, 0xb3, 0x96, 0x35, 0xac, 0x66,
+  0xc0, 0x24, 0x0b, 0x70, 0xf5, 0xf8, 0x3c, 0x18, 0xcf, 0x6a, 0x75, 0x4e, 0xfc, 0x9e, 0xb0, 0x20,
+  0x33, 0x08, 0x0b, 0x98, 0x19, 0xbd, 0x34, 0x2c, 0xe0, 0xe3, 0x31, 0xea, 0xf1, 0x65, 0x01, 0xa1,
+  0xa7, 0xe6, 0xbe, 0x54, 0x6e, 0xb6, 0xc6, 0x5a, 0xb3, 0x76, 0xa9, 0xfc, 0x12, 0x2d, 0xb8, 0xaf,
+  0xca, 0x4b, 0x40, 0x2d, 0x39, 0x2f, 0x86, 0x24, 0x0d, 0xc5, 0xd0, 0x1b, 0xbe, 0x6e, 0xcf, 0x1b,
+  0xbe, 0x62, 0x48, 0x2f, 0x93, 0x3c, 0x46, 0x3d, 0xa5, 0x5d, 0xe2, 0xec, 0xdb, 0x65, 0xda, 0xd7,
+  0xac, 0x47, 0x75, 0x8d, 0x47, 0x61, 0xb6, 0xc6, 0xba, 0x54, 0x9e, 0x45, 0xe6, 0x12, 0xb7, 0x95,
+  0x15, 0x59, 0x08, 0x49, 0x68, 0x21, 0x5a, 0x18, 0x8b, 0x84, 0xa4, 0x58, 0x04, 0x2f, 0x8d, 0xf4,
+  0x49, 0x42, 0x31, 0x44, 0x65, 0x58, 0x9a, 0x89, 0x16, 0x43, 0xaa, 0x6c, 0x9e, 0x5e, 0x86, 0xf5,
+  0x58, 0xbb, 0xa8, 0xcc, 0xb8, 0xef, 0x48, 0xdf, 0x50, 0xe9, 0x37, 0x62, 0x11, 0x52, 0x3e, 0x59,
+  0xc2, 0x65, 0x86, 0x05, 0xbd, 0xd7, 0xfb, 0xcb, 0xd6, 0x98, 0x35, 0x25, 0x61, 0xa4, 0xaf, 0xb6,
+  0x45, 0xe6, 0x12, 0xad, 0xae, 0xa8, 0xfa, 0x58, 0x89, 0x45, 0x84, 0x4e, 0xc5, 0x17, 0x09, 0x60,
+  0x6b, 0xb4, 0xa3, 0x88, 0x04, 0x84, 0x4e, 0xa1, 0x13, 0x4b, 0x43, 0xd2, 0x90, 0xb0, 0x75, 0x1e,
+  0x96, 0x29, 0x3e, 0xec, 0xad, 0x8a, 0x2f, 0x16, 0x99, 0x71, 0xee, 0xf9, 0xb0, 0xc9, 0x87, 0xf7,
+  0x93, 0xbd, 0x54, 0xb6, 0x75, 0x1e, 0xdd, 0x57, 0xd3, 0x23, 0x32, 0x2c, 0xc1, 0x6b, 0x64, 0x1b,
+  0x5e, 0x0a, 0x49, 0xb2, 0xe0, 0xe7, 0xb0, 0xc2, 0xd3, 0xa4, 0xbf, 0xce, 0xb3, 0x08, 0x5b, 0x40,
+  0x65, 0xc6, 0x12, 0x29, 0x0b, 0x41, 0xdd, 0xda, 0xa4, 0x1a, 0x35, 0x3f, 0x65, 0x25, 0x24, 0x29,
+  0xbe, 0xbc, 0x48, 0x2c, 0xd9, 0xd4, 0x4e, 0x64, 0x98, 0xfb, 0xb4, 0x98, 0x16, 0x8b, 0xa1, 0x4c,
+  0x94, 0xda, 0x80, 0x7f, 0xb7, 0xdb, 0xd3, 0x5d, 0xda, 0xab, 0x38, 0x8f, 0xf8, 0x4a, 0x5e, 0x94,
+  0x84, 0x2e, 0x4f, 0x57, 0x49, 0x46, 0x59, 0x61, 0xf5, 0x88, 0x2c, 0x24, 0x49, 0x82, 0x54, 0xde,
+  0x46, 0x96, 0xac, 0x58, 0xe1, 0x69, 0x92, 0x5f, 0xe7, 0x5b, 0x94, 0xf5, 0x89, 0xbd, 0x69, 0x31,
+  0x2f, 0xce, 0x50, 0x2d, 0xb1, 0xf2, 0x15, 0x8d, 0x97, 0x60, 0x09, 0xd5, 0x59, 0xf1, 0x57, 0x58,
+  0x11, 0x3a, 0xe9, 0x95, 0x44, 0x59, 0x61, 0xcf, 0x37, 0xcb, 0x0a, 0xae, 0xe7, 0x58, 0x06, 0x58,
+  0x3d, 0xcc, 0x14, 0xbe, 0x82, 0xcc, 0xbe, 0xd2, 0x0c, 0x56, 0x2c, 0x2c, 0xf2, 0x4a, 0x35, 0xea,
+  0xdb, 0xa0, 0x05, 0x2b, 0x56, 0xbc, 0xd0, 0xfa, 0x2d, 0x2f, 0x62, 0x5f, 0xc1, 0xbf, 0x3f, 0x43,
+  0x9a, 0x36, 0x9b, 0xfa, 0x00, 0xad, 0xe9, 0xf3, 0x22, 0xf6, 0x87, 0x68, 0x1f, 0x91, 0xe1, 0x56,
+  0x10, 0xcb, 0xa2, 0xe5, 0x7a, 0x05, 0x9f, 0x23, 0x7c, 0x06, 0xc9, 0xd9, 0x92, 0x4a, 0xf5, 0x22,
+  0x2b, 0x23, 0x7a, 0xb8, 0x04, 0xcd, 0xb7, 0x88, 0xc4, 0x78, 0x66, 0x03, 0x95, 0xdf, 0x32, 0x6a,
+  0x6a, 0xbf, 0xce, 0xb3, 0xa8, 0xa7, 0xd2, 0x36, 0x07, 0x2d, 0x8e, 0xb3, 0x31, 0x56, 0x68, 0x8b,
+  0x17, 0x16, 0xba, 0x21, 0x5c, 0x61, 0xbc, 0xab, 0x2c, 0x23, 0xcc, 0x63, 0x0d, 0x56, 0x86, 0x4b,
+  0x63, 0x65, 0xb5, 0xdb, 0xeb, 0xae, 0x92, 0x36, 0xdd, 0x42, 0x97, 0x78, 0x67, 0xb6, 0xc7, 0x42,
+  0xb3, 0xba, 0x45, 0x6c, 0x8d, 0xc1, 0xe7, 0x23, 0xa8, 0x5b, 0xd7, 0x58, 0xa9, 0x56, 0xb7, 0x60,
+  0x96, 0xb5, 0x5e, 0x1b, 0x3e, 0x7f, 0x01, 0x5d, 0xaf, 0xa8, 0xb4, 0xb5, 0xd4, 0x37, 0xa3, 0xfd,
+  0xb4, 0x40, 0xc9, 0x63, 0xb4, 0xfe, 0x9a, 0x9f, 0xe9, 0xb3, 0xf1, 0x7a, 0x57, 0x01, 0xa6, 0xdf,
+  0x45, 0x97, 0xf8, 0x35, 0x80, 0x95, 0xa6, 0xd9, 0x22, 0xa3, 0xcc, 0x1a, 0x46, 0xb6, 0x58, 0x56,
+  0x9a, 0xd3, 0xdb, 0xb6, 0x4f, 0xcf, 0x7d, 0x7b, 0xd0, 0xea, 0x38, 0xcc, 0x9e, 0x68, 0x75, 0xcc,
+  0x6e, 0x4f, 0xb8, 0x1f, 0xde, 0xa7, 0xd5, 0x63, 0xa9, 0xf6, 0xc4, 0xb6, 0x8e, 0x97, 0x8b, 0x0d,
+  0xfe, 0x8e, 0xe8, 0xb5, 0xcb, 0xde, 0x63, 0x89, 0xe9, 0xde, 0xf1, 0xbe, 0xfa, 0x3d, 0x72, 0xbc,
+  0x4f, 0xcf, 0x7f, 0x2b, 0xf7, 0x1e, 0x5b, 0x56, 0xea, 0xb7, 0x0b, 0x7f, 0x8c, 0xc7, 0xd5, 0xba,
+  0xbd, 0xc7, 0x96, 0x95, 0x71, 0xbe, 0x43, 0xeb, 0xf4, 0xe0, 0x43, 0x55, 0x5d, 0xe3, 0x71, 0xb5,
+  0x6e, 0xef, 0xb1, 0x84, 0xd8, 0xc0, 0xf5, 0x6a, 0xd6, 0x6d, 0xe5, 0xde, 0x2e, 0x76, 0x0c, 0x5c,
+  0xe6, 0x79, 0x98, 0xbe, 0x43, 0xaf, 0x52, 0xfb, 0xc0, 0x38, 0xb3, 0x10, 0xf0, 0xe8, 0x59, 0xd9,
+  0x91, 0xed, 0x9c, 0x5d, 0x60, 0x9e, 0x59, 0xc0, 0xe3, 0x13, 0x4e, 0x67, 0xc5, 0x3c, 0xb3, 0x40,
+  0x46, 0xc4, 0x9c, 0xcd, 0x0a, 0x3b, 0xcf, 0x61, 0x66, 0x45, 0x54, 0x5b, 0xff, 0x09, 0xbe, 0xc3,
+  0xda, 0x1b, 0xeb, 0x6f, 0xdb, 0x07, 0xdb, 0xda, 0x4e, 0x84, 0xcb, 0x63, 0xcd, 0x64, 0x06, 0x01,
+  0x43, 0xf1, 0x75, 0x03, 0x65, 0x05, 0xd7, 0xb5, 0x13, 0x3b, 0x26, 0xf8, 0xc6, 0xff, 0x5f, 0x62,
+  0xdb, 0xdb, 0x89, 0x1e, 0x8f, 0x52, 0x19, 0x6b, 0xc6, 0x23, 0xcd, 0xae, 0xaf, 0x10, 0x56, 0xf0,
+  0xbc, 0x01, 0xf1, 0x12, 0x32, 0x27, 0x46, 0xe6, 0xdb, 0xe8, 0x76, 0x67, 0xd6, 0x2b, 0xf3, 0x05,
+  0x3c, 0xa3, 0x94, 0xae, 0xcc, 0x4a, 0x90, 0xb9, 0x59, 0x6d, 0xbb, 0x33, 0x59, 0xe1, 0xcd, 0xe3,
+  0xb3, 0xdb, 0x9d, 0xc9, 0x8a, 0xb1, 0x17, 0x17, 0x70, 0x7b, 0x71, 0x6d, 0xd4, 0x57, 0xa8, 0x87,
+  0xd0, 0x39, 0x29, 0xa7, 0xb3, 0x12, 0xae, 0xcc, 0x95, 0x62, 0x2f, 0x09, 0x57, 0xe6, 0x35, 0x9d,
+  0xcd, 0x8a, 0x5c, 0xb9, 0x63, 0x80, 0xce, 0xa1, 0x93, 0x39, 0x70, 0xb2, 0xd5, 0xa9, 0x2d, 0x33,
+  0xef, 0x6e, 0x03, 0x8d, 0x15, 0xa7, 0xf6, 0xe2, 0xc2, 0xba, 0xbb, 0x08, 0xc8, 0x7d, 0x20, 0xae,
+  0xaf, 0xe8, 0x5b, 0x66, 0xa3, 0xaf, 0x38, 0xb5, 0x5e, 0x61, 0x5b, 0xe6, 0x1e, 0xb7, 0xb6, 0xe5,
+  0xc2, 0x6d, 0x99, 0x35, 0xb0, 0x77, 0x03, 0xbb, 0xbd, 0x38, 0x82, 0xea, 0x7d, 0x7e, 0x67, 0xb2,
+  0xe2, 0xe7, 0xde, 0x75, 0xdc, 0xe3, 0xf0, 0x7a, 0x05, 0xb3, 0x42, 0xee, 0x12, 0xd6, 0xa0, 0x8d,
+  0x25, 0x38, 0xb5, 0x65, 0xe6, 0x8d, 0xb0, 0x68, 0x6d, 0xb3, 0x53, 0x7b, 0x71, 0x98, 0x15, 0xed,
+  0x3e, 0x73, 0x72, 0x5f, 0xb8, 0xc6, 0x8a, 0xeb, 0x2b, 0xfc, 0xd1, 0x38, 0x67, 0xd6, 0x2b, 0x01,
+  0x4f, 0xf5, 0xd1, 0x38, 0x67, 0xb2, 0xe2, 0xb6, 0xcc, 0x56, 0x30, 0x8e, 0xc6, 0xb1, 0xdb, 0x9c,
+  0xca, 0x8a, 0xeb, 0x2b, 0x66, 0xb8, 0xbd, 0x38, 0x2b, 0x56, 0x78, 0xbd, 0x38, 0x67, 0xb7, 0xcc,
+  0x7e, 0x4f, 0x37, 0x04, 0x3b, 0x69, 0xbb, 0x6c, 0x64, 0xc5, 0xa9, 0xbd, 0x38, 0xcd, 0x57, 0xe8,
+  0xfc, 0x7b, 0x31, 0xa4, 0x54, 0xae, 0x20, 0xa7, 0xfa, 0x4a, 0x4f, 0xe5, 0x39, 0x43, 0x3a, 0xff,
+  0x8e, 0x47, 0x70, 0xdd, 0x7a, 0x45, 0x3f, 0x72, 0x8b, 0x21, 0xf6, 0xce, 0x67, 0xc6, 0xb3, 0x9d,
+  0xc8, 0x4a, 0xad, 0xbb, 0x9d, 0x9c, 0xca, 0x0a, 0x1d, 0x8b, 0xd3, 0x9e, 0x01, 0xf3, 0x3b, 0xbe,
+  0xbf, 0x42, 0xa0, 0x9f, 0x57, 0x65, 0xe1, 0x5c, 0x56, 0xe8, 0x73, 0xa9, 0xc6, 0xbb, 0x34, 0x5c,
+  0x56, 0x48, 0xeb, 0xac, 0xbf, 0xa3, 0xc7, 0xb9, 0x2d, 0x33, 0x01, 0xbe, 0x0f, 0x4c, 0x3f, 0x0a,
+  0x47, 0xe0, 0xd4, 0x5e, 0x1c, 0x81, 0xf6, 0xc4, 0xbb, 0x9e, 0x15, 0x67, 0xfb, 0x8a, 0x15, 0x2b,
+  0x4e, 0xae, 0x57, 0xb4, 0xfa, 0x56, 0x3f, 0x9b, 0xea, 0x74, 0x56, 0xd8, 0xb6, 0x79, 0x92, 0xe0,
+  0xb2, 0xa2, 0x81, 0x3e, 0x4d, 0xaf, 0x97, 0x3a, 0xf5, 0x99, 0x8f, 0xea, 0x70, 0x9f, 0x0f, 0xaa,
+  0x0e, 0xf7, 0x09, 0x3b, 0x1e, 0xdc, 0xa7, 0x31, 0xf9, 0xac, 0xb4, 0xee, 0xd9, 0x5b, 0x3b, 0x3f,
+  0xb9, 0xcb, 0x7b, 0xd2, 0x7a, 0x62, 0xc7, 0x7e, 0xea, 0x9f, 0xf9, 0x53, 0xdf, 0x73, 0xda, 0x3b,
+  0x66, 0xef, 0xb1, 0x04, 0xef, 0xa9, 0xfc, 0xc3, 0xda, 0x3b, 0x54, 0xcb, 0x3a, 0x3a, 0x78, 0xbd,
+  0xdf, 0xda, 0xcf, 0xf4, 0xef, 0xa8, 0xbd, 0xeb, 0x3b, 0xe7, 0xcd, 0x43, 0x35, 0xcb, 0xaa, 0x03,
+  0xdb, 0x8d, 0xaf, 0x8b, 0xfd, 0xca, 0xfe, 0xde, 0x68, 0x26, 0x84, 0xed, 0xf9, 0x6d, 0x1e, 0xc6,
+  0xf9, 0x9a, 0x89, 0xf1, 0x1d, 0x13, 0x3a, 0xc6, 0x77, 0x34, 0xbc, 0x57, 0xc9, 0xc7, 0x59, 0x56,
+  0xf0, 0x35, 0xd2, 0x68, 0x29, 0x24, 0x73, 0x4a, 0x73, 0x8e, 0xa3, 0xd5, 0x59, 0x71, 0xa6, 0x08,
+  0x87, 0xb4, 0x8d, 0xe3, 0xb0, 0x32, 0xce, 0x77, 0x48, 0x5b, 0xeb, 0x6c, 0xaa, 0xe4, 0x63, 0x62,
+  0xee, 0x0f, 0xd4, 0x4b, 0x8c, 0x99, 0x41, 0x8d, 0xb9, 0x41, 0x79, 0xb9, 0x4a, 0x79, 0xd9, 0x4a,
+  0x79, 0xd9, 0xb0, 0x48, 0x0e, 0x25, 0x3e, 0x2b, 0x53, 0x98, 0x3c, 0x4b, 0xe6, 0x2c, 0x58, 0x6c,
+  0xd6, 0xab, 0xda, 0x99, 0x4a, 0x79, 0xf9, 0xb5, 0xf4, 0x92, 0x20, 0x27, 0xbb, 0x93, 0x79, 0x76,
+  0xb9, 0xbb, 0x8e, 0x5c, 0xa5, 0x32, 0x27, 0xfb, 0x19, 0x2f, 0x2f, 0xa9, 0x6c, 0x91, 0x39, 0x0d,
+  0x47, 0x59, 0x81, 0x3a, 0x58, 0x31, 0x67, 0x4c, 0xd3, 0x67, 0x48, 0xab, 0x95, 0xa9, 0xd4, 0xca,
+  0x1a, 0xbd, 0x96, 0x99, 0x13, 0x7d, 0xc6, 0x4f, 0x92, 0x9f, 0x0e, 0xe7, 0xa0, 0xab, 0x9e, 0xab,
+  0x34, 0x24, 0x45, 0xfb, 0xea, 0xc9, 0x4b, 0xaa, 0xe9, 0xb1, 0x59, 0xf6, 0xc8, 0x72, 0x6d, 0x56,
+  0xb4, 0x08, 0x5e, 0xcb, 0x99, 0x47, 0xbf, 0x95, 0xf6, 0x5a, 0x99, 0x4a, 0xcd, 0x5a, 0x56, 0x56,
+  0xf7, 0x98, 0x32, 0xf6, 0xd1, 0xf9, 0x42, 0x6d, 0x6e, 0x99, 0x9f, 0x83, 0xd4, 0xa8, 0x47, 0x33,
+  0x75, 0x56, 0xcb, 0x69, 0x5a, 0xb2, 0x63, 0xb6, 0x39, 0xff, 0x24, 0xcd, 0xa8, 0x58, 0x8b, 0x15,
+  0x6d, 0xb4, 0x87, 0xe6, 0x57, 0xd4, 0xf2, 0x2c, 0xf2, 0x32, 0x95, 0x46, 0xfb, 0xb4, 0x8c, 0xa6,
+  0x84, 0x15, 0xaa, 0x55, 0xcd, 0x6a, 0x63, 0x3e, 0x53, 0x3f, 0x33, 0x5f, 0x48, 0xee, 0xfd, 0xc2,
+  0x99, 0x40, 0x25, 0x0f, 0x3f, 0xb7, 0xa8, 0x5e, 0x4f, 0xcb, 0x49, 0xc9, 0xcb, 0x69, 0x4a, 0xf6,
+  0x95, 0xbd, 0x58, 0xcf, 0x98, 0x7f, 0x12, 0x9f, 0x1f, 0x62, 0xc7, 0xf6, 0xb0, 0x62, 0xce, 0x54,
+  0x2a, 0x0b, 0x92, 0x47, 0xcb, 0x68, 0x8a, 0xaf, 0x0d, 0x7a, 0x24, 0xd5, 0xad, 0xb6, 0x62, 0x85,
+  0xe4, 0x25, 0xa5, 0x5e, 0x47, 0xca, 0x22, 0xe7, 0xd3, 0x6f, 0xc8, 0x37, 0xaa, 0xe9, 0x9d, 0x5f,
+  0x25, 0xa7, 0x29, 0xde, 0x17, 0xe7, 0x2a, 0x2d, 0x7b, 0x7b, 0x39, 0xff, 0x24, 0xfe, 0xc3, 0xff,
+  0xe7, 0x45, 0xea, 0xb3, 0xdb, 0xcb, 0x8a, 0x3e, 0x53, 0x29, 0xf6, 0x45, 0xf3, 0x53, 0x4e, 0xb5,
+  0xad, 0xc6, 0xb3, 0xe9, 0x41, 0xce, 0x15, 0x44, 0x33, 0xc1, 0x92, 0xb9, 0x65, 0x8d, 0x15, 0x5c,
+  0xdb, 0xd3, 0xcc, 0xac, 0x46, 0x3d, 0x89, 0x9b, 0xd3, 0x94, 0xef, 0x17, 0xa4, 0xce, 0xc3, 0xe7,
+  0x11, 0x6f, 0xd1, 0xea, 0xb7, 0x7a, 0x59, 0xa1, 0xd9, 0x6c, 0xcd, 0x59, 0x6d, 0xf5, 0x4f, 0x33,
+  0xf5, 0xe8, 0xc6, 0x57, 0x79, 0x47, 0xc7, 0xb3, 0x5a, 0xcf, 0x4a, 0xa0, 0x52, 0xdb, 0xea, 0xe7,
+  0x96, 0xb5, 0x8c, 0x9f, 0xda, 0xb3, 0x76, 0x92, 0x49, 0x6f, 0xea, 0x31, 0x92, 0x29, 0xa7, 0x69,
+  0x34, 0x68, 0xcc, 0x4b, 0x4a, 0xfd, 0x22, 0xc0, 0x3c, 0x47, 0xa2, 0xd5, 0x6d, 0xd6, 0xac, 0x04,
+  0x74, 0xb5, 0x2d, 0x2e, 0x0f, 0xdf, 0xbf, 0x48, 0xbf, 0xf9, 0x99, 0x4a, 0xc3, 0x82, 0xdf, 0xc3,
+  0x8e, 0xaf, 0xf2, 0x8e, 0x8e, 0x6f, 0xf5, 0x7c, 0xe6, 0x0a, 0x0a, 0x58, 0xb4, 0xcc, 0xbc, 0x2c,
+  0xa0, 0xd6, 0x6d, 0x9c, 0xfa, 0xcd, 0xe4, 0x34, 0xe5, 0xb5, 0x98, 0x34, 0x33, 0xa5, 0x39, 0x1b,
+  0x69, 0x2d, 0x56, 0xf8, 0x39, 0xc4, 0xad, 0x6d, 0x64, 0x5b, 0x72, 0xab, 0x7e, 0x07, 0xdd, 0xb3,
+  0x5b, 0x67, 0x35, 0x73, 0xfd, 0x54, 0xce, 0x08, 0xaf, 0x9f, 0x63, 0xcc, 0x02, 0x6a, 0xd6, 0xa3,
+  0xbd, 0x33, 0x9a, 0x39, 0x5e, 0x9f, 0x73, 0xde, 0xcf, 0x48, 0x8c, 0x25, 0xd5, 0xcf, 0x0a, 0x2f,
+  0xdf, 0x7c, 0x35, 0x1b, 0xcd, 0xd9, 0x4a, 0xad, 0x8e, 0x4e, 0x9f, 0x89, 0xd5, 0x4e, 0xd9, 0x39,
+  0xed, 0xd8, 0xe3, 0x6f, 0x52, 0x54, 0xd8, 0x9c, 0x52, 0x9a, 0x10, 0xdf, 0x35, 0xc7, 0x92, 0xe6,
+  0x8c, 0x21, 0xb4, 0xf6, 0xcc, 0x1a, 0xfd, 0x6e, 0xfb, 0xd1, 0x9c, 0x71, 0x39, 0xda, 0x8e, 0xb2,
+  0x31, 0x66, 0xf5, 0x9a, 0xa8, 0xf1, 0x77, 0x5f, 0x90, 0xd2, 0xfc, 0xe5, 0x25, 0x7e, 0xec, 0x4a,
+  0xeb, 0x28, 0x3b, 0x80, 0xb2, 0x62, 0xae, 0xeb, 0xfd, 0x75, 0x46, 0x66, 0x8d, 0xbd, 0xfb, 0xc2,
+  0x3a, 0xba, 0xb3, 0x1f, 0x2b, 0xe6, 0xf7, 0x4d, 0xd0, 0x1e, 0x4e, 0xad, 0xb8, 0xb3, 0xd1, 0x77,
+  0x5f, 0x58, 0x47, 0x77, 0xf6, 0x63, 0x65, 0x92, 0x80, 0x59, 0x61, 0x23, 0xb3, 0x28, 0x27, 0x9e,
+  0xd4, 0xc7, 0x9d, 0x34, 0x9e, 0xe4, 0x45, 0x6b, 0xe6, 0xb7, 0x54, 0x50, 0x3d, 0x1a, 0x7b, 0x98,
+  0xdf, 0x56, 0x61, 0x47, 0x56, 0x70, 0xaf, 0x92, 0x8d, 0xcc, 0x24, 0x4e, 0xdc, 0xb9, 0xa9, 0x12,
+  0x77, 0xf2, 0xe2, 0x49, 0x36, 0x5a, 0x23, 0xec, 0xb1, 0xb1, 0x1f, 0x65, 0x83, 0xf7, 0xfe, 0x03,
+  0xd2, 0xbf, 0xb7, 0x23, 0x2b, 0x6c, 0x24, 0x27, 0x97, 0xea, 0x94, 0x6a, 0x71, 0x27, 0x2f, 0x9e,
+  0x64, 0xa3, 0x35, 0xa2, 0xc7, 0xc6, 0x7e, 0x46, 0x56, 0xcc, 0x59, 0x2e, 0xec, 0xc9, 0x4a, 0xa0,
+  0x66, 0x64, 0x36, 0x54, 0x61, 0xc5, 0xfc, 0x8e, 0x0c, 0x7d, 0xb4, 0x66, 0x3d, 0x96, 0xc1, 0xb2,
+  0x42, 0x23, 0x7a, 0x7b, 0xb3, 0x52, 0x2b, 0x32, 0xd3, 0xe2, 0x4e, 0xde, 0x3b, 0x32, 0x74, 0x31,
+  0xa6, 0x29, 0xf6, 0xa3, 0xb5, 0x2c, 0x3b, 0xb2, 0xa7, 0xcf, 0x13, 0x63, 0x4f, 0x56, 0x1a, 0x89,
+  0xcc, 0xba, 0x38, 0xef, 0xc8, 0xa8, 0xf7, 0xbd, 0x19, 0x56, 0x71, 0xa1, 0x5d, 0x59, 0xa9, 0x16,
+  0x99, 0xe9, 0x47, 0xfb, 0xf5, 0xf1, 0xa4, 0xdf, 0xa8, 0x55, 0xe3, 0x2d, 0x15, 0xfc, 0xb8, 0xd0,
+  0x6e, 0xac, 0xd8, 0xa9, 0xc7, 0xdf, 0x6a, 0x3e, 0x28, 0x2b, 0xcd, 0x89, 0xc9, 0x9a, 0x01, 0xfb,
+  0xdc, 0xa1, 0xd6, 0xf8, 0xac, 0xf0, 0x58, 0xc2, 0xbd, 0x17, 0xcb, 0x85, 0x0b, 0x17, 0x2e, 0x5c,
+  0xb8, 0x70, 0xe1, 0xc2, 0x85, 0x0b, 0x17, 0x2e, 0x5c, 0xb8, 0x70, 0xb1, 0x63, 0xf1, 0x3f, 0x53,
+  0xd1, 0xe8, 0xeb, 0x3a, 0x9b, 0x00, 0x00
+};
+
+#endif // SCUMM_HE_MOONBASE_MAP_DATA
diff --git a/engines/scumm/he/moonbase/map_main.cpp b/engines/scumm/he/moonbase/map_main.cpp
new file mode 100644
index 00000000000..d0459d2ab43
--- /dev/null
+++ b/engines/scumm/he/moonbase/map_main.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 "common/compression/deflate.h"
+
+#include "common/memstream.h"
+#include "common/bufferedstream.h"
+
+#include "scumm/he/intern_he.h"
+
+#include "scumm/he/moonbase/map_data.h"
+#include "scumm/he/moonbase/map_main.h"
+
+namespace Scumm {
+
+Map::Map(ScummEngine_v100he *vm) : _vm(vm), _rnd("moonbase") {
+}
+
+Map::~Map() {
+}
+
+Common::SeekableReadStream *Map::substituteFile(const byte *fileName) {
+	if (!strcmp((const char *)fileName, "map\\moon001.thm")) {
+		// Load thumbnail data
+		Common::MemoryReadStream *thumbnail = new Common::MemoryReadStream(Template_thm, ARRAYSIZE(Template_thm));
+		Common::SeekableReadStream *stream = Common::wrapCompressedReadStream(thumbnail);
+		return stream;
+	}
+
+	return nullptr;
+}
+
+} // End of namespace Scumm
diff --git a/engines/scumm/he/moonbase/map_main.h b/engines/scumm/he/moonbase/map_main.h
new file mode 100644
index 00000000000..610f4f0f8ec
--- /dev/null
+++ b/engines/scumm/he/moonbase/map_main.h
@@ -0,0 +1,53 @@
+/* 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 SCUMM_HE_MOONBASE_MAP_MAIN
+#define SCUMM_HE_MOONBASE_MAP_MAIN
+
+#ifdef ENABLE_HE
+
+#include "common/stream.h"
+#include "common/random.h"
+
+namespace Scumm {
+
+class Map {
+public:
+	Map(ScummEngine_v100he *vm);
+	~Map();
+
+	Common::SeekableReadStream *substituteFile(const byte *fileName);
+
+private:
+	ScummEngine_v100he *_vm;
+
+	// We require our own random number generator
+	// so we can send and set seeds from online players to ensure
+	// they're playing on the same generated map.
+	Common::RandomSource _rnd;
+};
+
+} // End of namespace Scumm
+
+
+#endif // ENABLE_HE
+
+#endif // SCUMM_HE_MOONBASE_MAP_MAIN
diff --git a/engines/scumm/he/moonbase/moonbase.cpp b/engines/scumm/he/moonbase/moonbase.cpp
index d58e313dee3..6ed17bcae32 100644
--- a/engines/scumm/he/moonbase/moonbase.cpp
+++ b/engines/scumm/he/moonbase/moonbase.cpp
@@ -24,6 +24,7 @@
 #include "scumm/he/intern_he.h"
 #include "scumm/he/moonbase/moonbase.h"
 #include "scumm/he/moonbase/ai_main.h"
+#include "scumm/he/moonbase/map_main.h"
 
 namespace Scumm {
 
@@ -33,11 +34,13 @@ Moonbase::Moonbase(ScummEngine_v100he *vm) : _vm(vm) {
 	initFOW();
 
 	_ai = new AI(_vm);
+	_map = new Map(_vm);
 }
 
 Moonbase::~Moonbase() {
 	delete _exe;
 	delete _ai;
+	delete _map;
 }
 
 int Moonbase::readFromArray(int array, int y, int x) {
diff --git a/engines/scumm/he/moonbase/moonbase.h b/engines/scumm/he/moonbase/moonbase.h
index 0186b8d62a5..edabbece19b 100644
--- a/engines/scumm/he/moonbase/moonbase.h
+++ b/engines/scumm/he/moonbase/moonbase.h
@@ -31,7 +31,7 @@ class PEResources;
 namespace Scumm {
 
 class AI;
-class Net;
+class Map;
 
 class Moonbase {
 public:
@@ -71,9 +71,7 @@ public:
 	uint32 _fowSentinelConditionBits;
 
 	AI *_ai;
-#ifdef USE_LIBCURL
-	Net *_net;
-#endif
+	Map *_map;
 
 private:
 	ScummEngine_v100he *_vm;
diff --git a/engines/scumm/he/script_v100he.cpp b/engines/scumm/he/script_v100he.cpp
index 2e63a9c09fc..1120ce4d17c 100644
--- a/engines/scumm/he/script_v100he.cpp
+++ b/engines/scumm/he/script_v100he.cpp
@@ -2160,6 +2160,13 @@ void ScummEngine_v100he::o100_startScript() {
 	getStackList(args, ARRAYSIZE(args));
 	script = pop();
 	flags = fetchScriptByte();
+
+	if (_game.id == GID_MOONBASE && _roomResource == 5 &&
+		((!strcmp(_game.variant, "1.1") && script == 2178) || script == 2177)) {
+		// TODO: Add a dialog for random map generation.
+		debug(1, "this is setup-gamesetup");
+	}
+
 	runScript(script, (flags == SO_BAK || flags == SO_BAKREC), (flags == SO_REC || flags == SO_BAKREC), args);
 }
 
diff --git a/engines/scumm/he/script_v60he.cpp b/engines/scumm/he/script_v60he.cpp
index ccbdae4dcdd..9e43bfc82ea 100644
--- a/engines/scumm/he/script_v60he.cpp
+++ b/engines/scumm/he/script_v60he.cpp
@@ -34,6 +34,9 @@
 #include "scumm/util.h"
 #include "scumm/verbs.h"
 
+#include "scumm/he/moonbase/moonbase.h"
+#include "scumm/he/moonbase/map_main.h"
+
 namespace Scumm {
 
 struct vsUnpackCtx {
@@ -185,6 +188,11 @@ Common::String ScummEngine_v60he::convertSavePathOld(const byte *src) {
 }
 
 Common::SeekableReadStream *ScummEngine_v60he::openFileForReading(const byte *fileName) {
+	if (_moonbase) {
+		Common::SeekableReadStream *substitutedFile = _moonbase->_map->substituteFile(fileName);
+		if (substitutedFile)
+			return substitutedFile;
+	}
 	Common::SeekableReadStream *saveFile = openSaveFileForReading(fileName);
 
 	if (saveFile)
diff --git a/engines/scumm/module.mk b/engines/scumm/module.mk
index 97d59993f8f..5f589cafb66 100644
--- a/engines/scumm/module.mk
+++ b/engines/scumm/module.mk
@@ -175,6 +175,7 @@ MODULE_OBJS += \
 	he/moonbase/ai_tree.o \
 	he/moonbase/ai_types.o \
 	he/moonbase/ai_weapon.o \
+	he/moonbase/map_main.o \
 	he/moonbase/moonbase.o \
 	he/moonbase/moonbase_fow.o \
 	he/moonbase/moonbase_gfx.o
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index 44f73feca4b..2cd845aa753 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -647,6 +647,8 @@ ScummEngine_v6::ScummEngine_v6(OSystem *syst, const DetectorResult &dr)
 
 ScummEngine_v60he::ScummEngine_v60he(OSystem *syst, const DetectorResult &dr)
 	: ScummEngine_v6(syst, dr) {
+	_moonbase = 0;
+
 	memset(_hInFileTable, 0, sizeof(_hInFileTable));
 	memset(_hOutFileTable, 0, sizeof(_hOutFileTable));
 
@@ -798,8 +800,6 @@ ScummEngine_v90he::~ScummEngine_v90he() {
 
 ScummEngine_v100he::ScummEngine_v100he(OSystem *syst, const DetectorResult &dr) : ScummEngine_v99he(syst, dr) {
 	/* Moonbase stuff */
-	_moonbase = 0;
-
 	if (_game.id == GID_MOONBASE)
 		_moonbase = new Moonbase(this);
 


Commit: b2a158b7c48cdcbd2412eedf1cea69e52ab7ccfc
    https://github.com/scummvm/scummvm/commit/b2a158b7c48cdcbd2412eedf1cea69e52ab7ccfc
Author: Little Cat (toontownlittlecat at gmail.com)
Date: 2024-05-12T15:08:27+02:00

Commit Message:
SCUMM HE: Add Spiff Moonbase map generator.

Painstakingly converted from Moonbase Console's source to match our
format conventions.  Unsure if it really works yet.

Changed paths:
  A engines/scumm/he/moonbase/map_spiff.cpp
  A engines/scumm/he/moonbase/map_spiff.h
    engines/scumm/module.mk


diff --git a/engines/scumm/he/moonbase/map_spiff.cpp b/engines/scumm/he/moonbase/map_spiff.cpp
new file mode 100644
index 00000000000..82fecc66411
--- /dev/null
+++ b/engines/scumm/he/moonbase/map_spiff.cpp
@@ -0,0 +1,533 @@
+/* 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 "scumm/he/moonbase/map_spiff.h"
+
+namespace Scumm {
+
+SpiffGenerator::SpiffGenerator(Common::RandomSource *rnd) {
+	_rnd = rnd;
+}
+
+SpiffGenerator::~SpiffGenerator() {
+}
+
+void SpiffGenerator::generateMap(int water, int mapSize, int energy, int terrain) {
+	totalMapSizeG = mapSize;
+	energyAmountG = (2 + energy) * totalMapSizeG * totalMapSizeG;
+
+	islandsFlagG = pickFrom2(0, 1, water - 4, (water >= 5)); // 1 is large islands, 2 is small
+	if (islandsFlagG) {
+		water -= 3;
+		energyAmountG = (int)(energyAmountG * (5 - islandsFlagG) / 6); // *2/3 or *1/2
+	}
+
+	waterAmountG = 4 * water;
+	cliffAmountG = 1 << terrain;
+	advancedMirrorOK_G = ((terrain > 1) && (water < 6)) || islandsFlagG;
+	terrainSeedFlagG = 2 * water - terrain;
+
+	int n = (int)(energyAmountG / 2700);
+	if (n > 12) {
+		n = 12;
+	}
+	if (n < 1) {
+		n = 1;
+	}
+	numPoolsG = _rnd->getRandomNumberRngSigned((int)(energyAmountG / 4000) + 1, n);
+	if (numPoolsG > 12) {
+		numPoolsG = 12;
+	}
+
+	generate();
+}
+
+int SpiffGenerator::pickFrom2(int a, int probA, int b, int probB) {
+	debug(3, "SpiffGenerator::pickFrom2(%d, %d, %d, %d)", a, probA, b, probB);
+	if ((int)_rnd->getRandomNumber(probB) < probA)
+		return a;
+	else
+		return b;
+}
+
+int SpiffGenerator::pickFrom3(int a, int probA, int b, int probB, int c, int probC) {
+	debug(3, "SpiffGenerator::pickFrom3(%d, %d, %d, %d, %d, %d)", a, probA, b, probB, c, probC);
+	int r = _rnd->getRandomNumber(probC);
+	if (r < probA)
+		return a;
+	else if (r < probA + probB)
+		return b;
+	else
+		return c;
+}
+
+int SpiffGenerator::pickFrom4(int a, int probA, int b, int probB, int c, int probC, int d, int probD) {
+	debug(3, "SpiffGenerator::pickFrom4(%d, %d, %d, %d, %d, %d, %d, %d)", a, probA, b, probB, c, probC, d, probD);
+	int r = _rnd->getRandomNumber(probD);
+	if (r < probA)
+		return a;
+	else if (r < probA + probB)
+		return b;
+	else if (r < probA + probB + probC)
+		return c;
+	else
+		return d;
+}
+
+void SpiffGenerator::getSpecials() {
+	// choose where the starting points and pools are
+	int x, y, p, t;
+	int edgeWaterA = (int)(islandsFlagG * totalMapSizeG / 16 + 0.5);
+	int edgeWaterB = (int)(islandsFlagG * totalMapSizeG / 16); // don't put pools between islands
+
+	// No matter what, they get a start hub spot.
+	if (mirrorTypeG == MAXDISTMIRROR)
+		x = (int)((totalMapSizeG * 3 + 8) / 16);
+	else
+		x = (int)(mapMiddleMaxG / 2);
+	y = x;
+
+	mapMiddle[x][y] = HUB; // hub start position
+
+	for (p = 1; p <= numPoolsG; ++p) {
+		x = _rnd->getRandomNumberRngSigned(edgeWaterA, mapMiddleMaxG - edgeWaterB);
+		y = _rnd->getRandomNumberRngSigned(edgeWaterA, mapMiddleMaxG - edgeWaterB);
+		if (mapMiddle[x][y] != UNASSIGNED)
+			--p; // repick this pool
+		else {
+			t = pickFrom3(SMALLPOOL, 40000 * numPoolsG, MEDIUMPOOL, 20000 * numPoolsG + energyAmountG, LARGEPOOLTOP, 2 * energyAmountG);
+			if (t == LARGEPOOLTOP) {
+				if ((y == mapMiddleMaxG - edgeWaterB) || (mapMiddle[x][y + 1] != UNASSIGNED))
+					t = SMALLPOOL; // keep large pool from being too high or overlapping another pool or start
+				else
+					mapMiddle[x][y + 1] = LARGEPOOLBOTTOM;
+			}
+			mapMiddle[x][y] = t;
+		}
+	}
+}
+
+void SpiffGenerator::copyMap(int XOffset, int YOffset, int XDirection, int YDirection) {
+	// copies the first quadrant of the map
+	// XOffset and YOffset are the distances moved
+	// XDirection and/or YDirection are/is -1 for mirrored, 1 for not mirrored
+	int x, y, tempMiddle, newCX;
+	int newCY = YOffset;
+	int newMX, newMY;
+
+	if (YDirection < 0)
+		newCY += mapCornerMaxG;
+
+	for (y = 0; y <= mapCornerMaxG; ++y) {
+		if (newCY < 0)
+			newCY += totalMapSizeG;
+		else if (newCY >= totalMapSizeG)
+			newCY -= totalMapSizeG;
+
+		newCX = XOffset;
+		if (XDirection < 0)
+			newCX += mapCornerMaxG;
+
+		for (x = 0; x <= mapCornerMaxG; ++x) {
+			if (newCX < 0)
+				newCX += totalMapSizeG;
+			else if (newCX >= totalMapSizeG)
+				newCX -= totalMapSizeG;
+
+			mapCorner[newCX][newCY] = mapCorner[x][y];
+			if ((x != mapCornerMaxG) && (y != mapCornerMaxG)) {
+				tempMiddle = mapMiddle[x][y];
+				newMX = newCX;
+				newMY = newCY;
+				if (YDirection < 0) {
+					newMY--;
+					if (newMY == -1)
+						newMY = totalMapSizeG - 1;
+					if (tempMiddle == LARGEPOOLTOP)
+						tempMiddle = LARGEPOOLBOTTOM;
+					else if (tempMiddle == LARGEPOOLBOTTOM)
+						tempMiddle = LARGEPOOLTOP;
+				}
+				if (XDirection < 0) {
+					newMX--;
+					if (newMX == -1)
+						newMX = totalMapSizeG - 1;
+				}
+				mapMiddle[newMX][newMY] = tempMiddle;
+			}
+
+			newCX += XDirection;
+		}
+
+		newCY += YDirection;
+	}
+}
+
+void SpiffGenerator::mirrorMap() {
+	// --------------------------------------------------------------
+	//  mirror map
+	// --------------------------------------------------------------
+
+	int swapXa = pickFrom2(-1, 1, 1, advancedMirrorOK_G);
+	int swapYa = pickFrom2(-1, advancedMirrorOK_G, 1, 1);
+	int swapXb = pickFrom2(-1, advancedMirrorOK_G, 1, 1);
+	int swapYb = pickFrom2(-1, 1, 1, advancedMirrorOK_G);
+
+	switch (mirrorTypeG) {
+	case NORMALMIRROR: // four quadrants
+		// ABCBA
+		// DEFED
+		// GHIHG
+		// DEFED
+		// ABCBA
+		copyMap(mapCornerMaxG, 0, swapXa, swapYa);
+		copyMap(0, mapCornerMaxG, swapXb, swapYb);
+		copyMap(mapCornerMaxG, mapCornerMaxG, swapXa * swapXb, swapYa * swapYb);
+		break;
+	case XOFFSETMIRROR: // Like normal, but one half is moved horizontally by 1/4 totalmapsize
+		// ABABABABA
+		// DEFGHGFED
+		// CDCDCDCDC
+		// FGHGFEDEF
+		// ABABABABA
+		if (swapYa == -1) // ensures fairness
+			swapXb = -1;
+		copyMap(mapCornerMaxG, 0, 1, swapYa);
+		copyMap(mapCornerMaxG / 2, mapCornerMaxG, swapXb, swapYb);
+		copyMap(mapCornerMaxG * 3 / 2, mapCornerMaxG, swapXb, swapYa * swapYb);
+		break;
+	case YOFFSETMIRROR:   // Like normal, but one half is moved vertically by 1/4 totalmapsize
+		if (swapXb == -1) // ensures fairness
+			swapYa = -1;
+		copyMap(mapCornerMaxG, mapCornerMaxG / 2, swapXa, swapYa);
+		copyMap(0, mapCornerMaxG, swapXb, 1);
+		copyMap(mapCornerMaxG, mapCornerMaxG * 3 / 2, swapXa * swapXb, swapYa);
+		break;
+	case MAXDISTMIRROR: // Allows maximum distance between starting points
+	default:
+		// ABCDCBA
+		// E*GHIJE
+		// HIJE*GH
+		// DCBABCD
+		// HG*EJIH
+		// EJIHG*E
+		// ABCDCBA
+
+		copyMap(mapCornerMaxG, 0, 1, -1);
+		copyMap(0, mapCornerMaxG, -1, 1);
+		copyMap(mapCornerMaxG, mapCornerMaxG, -1, -1);
+	}
+}
+
+void SpiffGenerator::errorCorrection() {
+	// corrects errors caused by pool placement and mirroring
+	// doesn't correct mapCorner[x][totalMapSizeG+1] or mapCorner[totalMapSizeG+1][y], since it isn't used
+
+	// for any HIGH to LOW transitions, makes the HIGH MEDIUM
+	// for pools on nonflat terrain, makes the terrain MEDIUM
+	// removes invalid water
+
+	int x;
+	int y;
+	int tempX;
+	int tempY;
+	int dx;
+	int dy;
+	int redo;
+	int elev;
+
+	for (y = 0; y < totalMapSizeG; ++y) {
+		for (x = 0; x < totalMapSizeG; ++x) {
+			if (mapCorner[x][y] == HIGH) {
+				for (dy = -1; dy <= 1; ++dy) {
+					tempY = y + dy;
+					if (tempY == totalMapSizeG)
+						tempY = 0;
+					else if (tempY == -1)
+						tempY = totalMapSizeG - 1;
+				}
+
+				for (dx = -1; dx <= 1; ++dx) {
+					tempX = x + dx;
+					if (tempX == totalMapSizeG)
+						tempX = 0;
+					else if (tempX == -1)
+						tempX = totalMapSizeG - 1;
+					if (mapCorner[tempX][tempY] == LOW)
+						mapCorner[x][y] = MEDIUM;
+				}
+			} else if ((mapCorner[x][y] != LOW) && (mapCorner[x][y] != MEDIUM)) {
+				mapCorner[x][y] = MEDIUM; // should not happen anymore
+			}
+		}
+	}
+
+	do {
+		redo = 0;
+		for (y = 0; y < totalMapSizeG; ++y) {
+			for (x = 0; x < totalMapSizeG; ++x) {
+				if (mapMiddle[x][y] != UNASSIGNED) {
+					tempY = y + 1;
+					if (tempY == totalMapSizeG)
+						tempY = 0;
+
+					tempX = x + 1;
+					if (tempX == totalMapSizeG)
+						tempX = 0;
+
+					elev = mapCorner[x][y];
+					if ((mapMiddle[x][y] == WATER) && (elev != LOW))
+						mapMiddle[x][y] = UNASSIGNED;
+					else if ((elev != mapCorner[x][tempY]) || (elev != mapCorner[tempX][y]) || (elev != mapCorner[tempX][tempY])) {
+						if (mapMiddle[x][y] == WATER)
+							mapMiddle[x][y] = UNASSIGNED;
+						else {
+							mapCorner[x][y] = MEDIUM;
+							mapCorner[x][tempY] = MEDIUM;
+							mapCorner[tempX][y] = MEDIUM;
+							mapCorner[tempX][tempY] = MEDIUM;
+							redo = 1;
+						}
+					}
+				}
+			}
+		}
+	} while (redo);
+}
+
+void SpiffGenerator::generate() {
+	// --------------------------------------------------------------
+	//  initialize
+	// --------------------------------------------------------------
+	int x;
+	int y;
+	int neighbors[MAXELEVVAL];
+	int a;
+	int b;
+	int tempElevation;
+	int nextElevation;
+	int special;
+
+	mapCornerMaxG = totalMapSizeG / 2;
+	mapMiddleMaxG = mapCornerMaxG - 1;
+
+	for (y = 0; y <= mapCornerMaxG; ++y) {
+		// initialise map to UNASSIGNED tiles
+		for (x = 0; x <= mapCornerMaxG; ++x) {
+			mapCorner[x][y] = UNASSIGNED;
+			mapMiddle[x][y] = UNASSIGNED;
+		}
+	}
+	if (advancedMirrorOK_G)
+		mirrorTypeG = pickFrom4(NORMALMIRROR, 1, XOFFSETMIRROR, 2, YOFFSETMIRROR, 2, MAXDISTMIRROR, 4);
+	else
+		mirrorTypeG = NORMALMIRROR;
+	getSpecials(); // get start and pools
+
+	// --------------------------------------------------------------
+	//  loop through each square
+	// --------------------------------------------------------------
+	mapCorner[0][0] = pickFrom3(LOW, 1, MEDIUM, (terrainSeedFlagG < 9), HIGH, (terrainSeedFlagG < 8)); // seed
+	for (y = 0; y <= mapCornerMaxG; ++y) {                                                             // fill in the rest of the random map
+		for (x = 0; x <= mapCornerMaxG; ++x) {
+			special = mapMiddle[x][y]; // water wouldn't have been assigned yet, so must be pool, start, or UNASSIGNED
+
+			// --------------------------------------------------------------
+			//  check neighbors
+			// --------------------------------------------------------------
+			if ((mapCorner[x][y] != UNASSIGNED) && (mapCorner[x][y] != LOW_OR_WATER))
+				nextElevation = mapCorner[x][y]; // already defined because of a special or (0,0), so no change
+			else {
+				neighbors[HIGH] = 0;
+				neighbors[MEDIUM] = 0;
+				neighbors[LOW] = 0;
+				neighbors[WATER] = 0;
+
+				if (x > 0) {
+					a = mapCorner[x - 1][y];
+					if ((y > 1) && (mapMiddle[x - 1][y - 2] == WATER))
+						++neighbors[WATER];
+					if (y > 0)
+						neighbors[mapCorner[x - 1][y - 1]] += 3;
+				} else {
+					a = mapCorner[x][y - 1];
+				}
+
+				neighbors[a] += 3;
+				if (y > 0) {
+					b = mapCorner[x][y - 1];
+					neighbors[b] += 3;
+					if (x < mapCornerMaxG) {
+						++neighbors[mapCorner[x + 1][y - 1]]; // so this value can be ignored when choosing water
+						if ((special != UNASSIGNED) && (x < mapCornerMaxG - 1))
+							++neighbors[mapCorner[x + 2][y - 1]];
+					}
+					if ((x > 1) && (mapMiddle[x - 2][y - 1] == WATER))
+						++neighbors[WATER];
+				} else {
+					b = mapCorner[x - 1][y]; // for probability equations for edges
+				}
+
+				// --------------------------------------------------------------
+				//  pick new elevation
+				// --------------------------------------------------------------
+				// neighbors                  possible new elevation
+				// HIGH or HIGH with MEDIUM   HIGH or MEDIUM
+				// MEDIUM only                HIGH, MEDIUM or LOW
+				// LOW or WATER only          MEDIUM, LOW or WATER
+				// MEDIUM with LOW or WATER   MEDIUM or LOW, possible WATER if no MEDIUM left, down, or down-left
+				// HIGH with LOW or WATER     MEDIUM
+
+				static int highAmt = 105;
+				static int mediumAmt = 100 + waterAmountG;
+				static int lowAmt = 105 + 3 * waterAmountG;
+				static int waterAmt = 15 * waterAmountG;
+
+				if (neighbors[LOW]) {
+					if (neighbors[HIGH]) { // HIGH with LOW or WATER
+						nextElevation = MEDIUM;
+					} else if (neighbors[MEDIUM] >= 3) { // MEDIUM with LOW or WATER
+						if (a != b) {
+							nextElevation = pickFrom2(LOW, lowAmt, MEDIUM, mediumAmt);
+						} else if (a == LOW) {
+							nextElevation = pickFrom2(LOW, 100 * lowAmt, MEDIUM, mediumAmt * cliffAmountG);
+						} else {
+							nextElevation = pickFrom2(LOW, lowAmt * cliffAmountG, MEDIUM, 100 * mediumAmt);
+						}
+					} else { // LOW or WATER only, possibly MEDIUM down-right
+						if (neighbors[WATER] == 1) {
+							nextElevation = pickFrom3(WATER, 100 * waterAmt, LOW, 100 * lowAmt, MEDIUM, mediumAmt * cliffAmountG);
+						} else if (neighbors[WATER] == 0) {
+							nextElevation = pickFrom3(WATER, waterAmt * cliffAmountG, LOW, 100 * lowAmt, MEDIUM, mediumAmt * cliffAmountG);
+						} else {
+							nextElevation = pickFrom3(WATER, 10000 * waterAmt, LOW, lowAmt * 100 * cliffAmountG, MEDIUM, mediumAmt * cliffAmountG * cliffAmountG);
+						}
+					}
+				} else {
+					if (neighbors[HIGH]) { // HIGH or HIGH with MEDIUM
+						if (a != b) {
+							nextElevation = pickFrom2(MEDIUM, mediumAmt, HIGH, highAmt);
+						} else if (a == HIGH) {
+							nextElevation = pickFrom2(MEDIUM, mediumAmt * cliffAmountG, HIGH, 100 * highAmt);
+						} else {
+							nextElevation = pickFrom2(MEDIUM, 100 * mediumAmt, HIGH, highAmt * cliffAmountG);
+						}
+					} else {
+						nextElevation = pickFrom3(LOW, lowAmt * cliffAmountG, MEDIUM, 200 * mediumAmt, HIGH, highAmt * cliffAmountG);
+					}
+				}
+
+				// --------------------------------------------------------------
+				//  set elevation
+				// --------------------------------------------------------------
+				if ((mapCorner[x][y] == LOW_OR_WATER) && (nextElevation != WATER)) {
+					// bottom and left edges of a special on LOW ground there may only be LOW or WATER
+					nextElevation = LOW;
+				}
+
+				if (nextElevation == WATER) {
+					if ((x != 0) && (y != 0) && (mapMiddle[x - 1][y - 1] == UNASSIGNED)) {
+						mapMiddle[x - 1][y - 1] = WATER; // set WATER
+					}
+					nextElevation = LOW;
+				}
+
+				mapCorner[x][y] = nextElevation; // set elevation
+
+				if (special != UNASSIGNED) { // if special, make flat spot (don't worry about going over map edge, will go into mirrored part)
+					tempElevation = nextElevation;
+					if (tempElevation == LOW)
+						tempElevation = LOW_OR_WATER; // allow for water on left and bottom edges
+					mapCorner[x + 1][y + 1] = nextElevation;
+					mapCorner[x + 1][y] = tempElevation;
+					mapCorner[x][y + 1] = tempElevation;
+				}
+			}
+
+			if (islandsFlagG) { // replace borders with water, errorCorrection() finishes it.
+				int edgeWaterA = (int)(islandsFlagG * totalMapSizeG / 16 + 0.5);
+				int edgeWaterB = mapMiddleMaxG - (int)(islandsFlagG * totalMapSizeG / 16);
+				for (y = 0; y <= mapCornerMaxG; ++y) {
+					for (x = 0; x < edgeWaterA; ++x) {
+						mapCorner[x][y] = LOW;
+						mapMiddle[x][y] = WATER;
+					}
+					if (mapCorner[edgeWaterA + 1][y] == HIGH)
+						mapCorner[edgeWaterA][y] = MEDIUM;
+
+					for (x = mapMiddleMaxG; x > edgeWaterB; --x) {
+						mapCorner[x + 1][y] = LOW;
+						mapMiddle[x][y] = WATER;
+					}
+					if (mapCorner[edgeWaterB][y] == HIGH) {
+						mapCorner[edgeWaterB + 1][y] = MEDIUM;
+					}
+				}
+
+				for (x = edgeWaterA; x <= edgeWaterB + 1; ++x) {
+					for (y = 0; y < edgeWaterA; ++y) {
+						mapCorner[x][y] = LOW;
+						mapMiddle[x][y] = WATER;
+					}
+					if (mapCorner[x][edgeWaterA + 1] == HIGH)
+						mapCorner[x][edgeWaterA] = MEDIUM;
+
+					for (y = mapMiddleMaxG; y > edgeWaterB; --y) {
+						mapCorner[x][y + 1] = LOW;
+						mapMiddle[x][y] = WATER;
+					}
+					if (mapCorner[x][edgeWaterB] == HIGH) {
+						mapCorner[x][edgeWaterB + 1] = MEDIUM;
+					}
+				}
+
+				if (islandsFlagG == 2) { // add tiny islands to help bridge wide channels
+					int j;
+					for (int i = 0; i < totalMapSizeG / 16; ++i) {
+						x = (int)(totalMapSizeG / 16 - .5);
+						y = _rnd->getRandomNumberRngSigned(x, totalMapSizeG / 2 - 1 - x);
+						if (_rnd->getRandomBit()) {
+							x = totalMapSizeG / 2 - 1 - x;
+						}
+						if (_rnd->getRandomBit()) {
+							mapMiddle[x][y] = UNASSIGNED;
+							for (j = 0; j < 4; ++j) {
+								mapMiddle[x + _rnd->getRandomNumberRngSigned(-1, 1)][y + _rnd->getRandomNumberRngSigned(-1, 1)] = UNASSIGNED;
+							}
+						} else {
+							mapMiddle[y][x] = UNASSIGNED;
+							for (j = 0; j < 4; ++j) {
+								mapMiddle[y + _rnd->getRandomNumberRngSigned(-1, 1)][x + _rnd->getRandomNumberRngSigned(-1, 1)] = UNASSIGNED;
+							}
+						}
+					}
+				}
+			}
+		}
+	}
+
+	mirrorMap();
+	errorCorrection();
+}
+
+} // End of namespace Scumm
diff --git a/engines/scumm/he/moonbase/map_spiff.h b/engines/scumm/he/moonbase/map_spiff.h
new file mode 100644
index 00000000000..47e88104803
--- /dev/null
+++ b/engines/scumm/he/moonbase/map_spiff.h
@@ -0,0 +1,93 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef SCUMM_HE_MOONBASE_MAP_SPIFF
+#define SCUMM_HE_MOONBASE_MAP_SPIFF
+
+#ifdef ENABLE_HE
+
+#include "common/random.h"
+
+#define MAXELEVVAL 4 // for array size
+#define HIGH 3 // elevations
+#define MEDIUM 2
+#define LOW 1
+#define WATER 0 // special types
+#define HUB 1
+#define SMALLPOOL 2
+#define MEDIUMPOOL 3
+#define LARGEPOOLTOP 4
+#define LARGEPOOLBOTTOM 5 // placeholder for top half of a large pool
+
+#define UNASSIGNED -1
+#define LOW_OR_WATER -2
+
+#define MAXSIZE 80
+
+#define NORMALMIRROR 0
+#define XOFFSETMIRROR 1
+#define YOFFSETMIRROR 2
+#define MAXDISTMIRROR 3
+
+namespace Scumm {
+
+class SpiffGenerator {
+public:
+	SpiffGenerator(Common::RandomSource *rnd);
+	~SpiffGenerator();
+
+	void generateMap(int water, int mapSize, int energy, int terrain);
+
+private:
+	Common::RandomSource *_rnd;
+
+	int numPoolsG; // per quadrant
+	int energyAmountG; // 2048 = min energy on small map, 51200 = max energy on max map, etc.
+	int cliffAmountG; // amount of cliffs, 10 is min, 70 is max
+	int waterAmountG; // 0 is min, 30 is max
+	int totalMapSizeG;
+
+	int terrainSeedFlagG; // disables HIGH or LOW terrain for the initial elevation when appropriate
+	int islandsFlagG; // enables islands
+	int advancedMirrorOK_G; // low terrain roughness can leave too abrupt changes at the edge, so set false to disable some mirroring types
+	int mirrorTypeG; // what mirroring is used
+
+	int mapCornerMaxG; // size of random section
+	int mapMiddleMaxG;
+	int mapCorner[MAXSIZE+1][MAXSIZE+1];
+	int mapMiddle[MAXSIZE][MAXSIZE];
+
+	int pickFrom2(int a, int probA, int b, int probB);
+	int pickFrom3(int a, int probA, int b, int probB, int c, int probC);
+	int pickFrom4(int a, int probA, int b, int probB, int c, int probC, int d, int probD);
+
+	void getSpecials();
+	void copyMap(int XOffset, int YOffset, int XDirection, int YDirection);
+	void mirrorMap();
+	void errorCorrection();
+	void generate();
+};
+
+} // End of namespace Scumm
+
+#endif // ENABLE_HE
+
+#endif // SCUMM_HE_MOONBASE_MAP_SPIFF
diff --git a/engines/scumm/module.mk b/engines/scumm/module.mk
index 5f589cafb66..593d3a974b6 100644
--- a/engines/scumm/module.mk
+++ b/engines/scumm/module.mk
@@ -175,6 +175,7 @@ MODULE_OBJS += \
 	he/moonbase/ai_tree.o \
 	he/moonbase/ai_types.o \
 	he/moonbase/ai_weapon.o \
+	he/moonbase/map_spiff.o \
 	he/moonbase/map_main.o \
 	he/moonbase/moonbase.o \
 	he/moonbase/moonbase_fow.o \


Commit: aa79a9b687a0610ad04df14d53be5b6ec00a2bf2
    https://github.com/scummvm/scummvm/commit/aa79a9b687a0610ad04df14d53be5b6ec00a2bf2
Author: Little Cat (toontownlittlecat at gmail.com)
Date: 2024-05-12T15:08:27+02:00

Commit Message:
SCUMM HE: Slightly working stat generation.

Changed paths:
    engines/scumm/he/moonbase/map_data.h
    engines/scumm/he/moonbase/map_main.cpp
    engines/scumm/he/moonbase/map_main.h
    engines/scumm/he/script_v100he.cpp


diff --git a/engines/scumm/he/moonbase/map_data.h b/engines/scumm/he/moonbase/map_data.h
index fa019711d66..7d3f2f1ad7d 100644
--- a/engines/scumm/he/moonbase/map_data.h
+++ b/engines/scumm/he/moonbase/map_data.h
@@ -29,6 +29,7 @@
 
 // Template.thm.gz (Map Icon).
 // (https://github.com/michaelbarlow7/moonbase-console/blob/master/MoonbaseConsole/Template.thm)
+#define TEMPLATE_THM_SIZE 4296 // The actual non-compressed size of Template.thm.
 const byte Template_thm[] = {
   0x1f, 0x8b, 0x08, 0x08, 0x5f, 0x3e, 0x4b, 0x65, 0x00, 0x03, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61,
   0x74, 0x65, 0x2e, 0x74, 0x68, 0x6d, 0x00, 0xad, 0x97, 0x0f, 0x7c, 0x13, 0xd5, 0x1d, 0xc0, 0x7f,
@@ -174,6 +175,7 @@ const byte Template_thm[] = {
 
 // Template.wiz.gz (Map Thumbnail; modified in-code to display stats).
 // (https://github.com/michaelbarlow7/moonbase-console/blob/master/MoonbaseConsole/Template.wiz)
+#define TEMPLATE_WIZ_SIZE 39738 // The actual non-compressed size of Template.wiz.
 const byte Template_wiz[] = {
   0x1f, 0x8b, 0x08, 0x08, 0xf4, 0x21, 0x4c, 0x65, 0x00, 0x03, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61,
   0x74, 0x65, 0x2e, 0x77, 0x69, 0x7a, 0x00, 0xed, 0x5d, 0x0d, 0x9c, 0x1b, 0x45, 0x15, 0x7f, 0x48,
diff --git a/engines/scumm/he/moonbase/map_main.cpp b/engines/scumm/he/moonbase/map_main.cpp
index d0459d2ab43..075573680c8 100644
--- a/engines/scumm/he/moonbase/map_main.cpp
+++ b/engines/scumm/he/moonbase/map_main.cpp
@@ -28,23 +28,144 @@
 
 #include "scumm/he/moonbase/map_data.h"
 #include "scumm/he/moonbase/map_main.h"
+#include "scumm/he/moonbase/map_spiff.h"
 
 namespace Scumm {
 
 Map::Map(ScummEngine_v100he *vm) : _vm(vm), _rnd("moonbase") {
+	_mapGenerated = false;
+
+	_energy = 0;
+	_terrain = 0;
+	_water = 0;
 }
 
 Map::~Map() {
 }
 
-Common::SeekableReadStream *Map::substituteFile(const byte *fileName) {
-	if (!strcmp((const char *)fileName, "map\\moon001.thm")) {
-		// Load thumbnail data
-		Common::MemoryReadStream *thumbnail = new Common::MemoryReadStream(Template_thm, ARRAYSIZE(Template_thm));
-		Common::SeekableReadStream *stream = Common::wrapCompressedReadStream(thumbnail);
-		return stream;
+bool Map::generateNewMap() {
+
+	// TODO: Show a dialog allowing the user to customize options.
+
+	// Don't randomly pick nonstandard map sizes.
+	int mapSize = _rnd.getRandomNumberRngSigned(4, 8) * 8;
+
+	int tileSet = _rnd.getRandomNumberRngSigned(1, 7);
+
+	// Only use [2, 3, 4] of the legal [0, 1, 2, 3, 4, 5, 6]
+	int energy = _rnd.getRandomNumberRngSigned(2, 4);
+	int terrain = _rnd.getRandomNumberRngSigned(2, 4);
+	int water = _rnd.getRandomNumberRngSigned(2, 4);
+
+	_randSeed = _rnd.generateNewSeed();
+
+	return generateMapWithInfo(SPIFF_GEN, _randSeed, mapSize, tileSet, energy, terrain, water);
+}
+
+bool Map::generateMapWithInfo(uint8 generator, uint32 seed, int mapSize, int tileset, int energy, int terrain, int water) {
+	_rnd.setSeed(seed);
+
+	debug(1, "Map: Generating new map with info: generator = %d, seed = %d, mapSize = %d, tileset = %d , energy = %d, terrain = %d, water = %d.", generator, seed, mapSize, tileset, energy, terrain, water);
+	switch (generator) {
+	case SPIFF_GEN:
+	{
+		SpiffGenerator spiff = SpiffGenerator(&_rnd);
+		spiff.generateMap(water, mapSize, energy, terrain);
+		// TODO: Actually create the map file.
+		break;
+	}
+	default:
+		error("Map: Got unknown generator: %d", generator);
+		return false;
 	}
 
+	// Store these for wiz generation.
+	_energy = energy;
+	_terrain = terrain;
+	_water = water;
+
+	_mapGenerated = true;
+	return true;
+}
+
+Common::SeekableReadStream *Map::makeWiz() {
+	unsigned short wiz [139][139];
+	int i, j;
+
+	Common::MemoryReadStream *wizTemplate = new Common::MemoryReadStream(Template_wiz, ARRAYSIZE(Template_wiz));
+	Common::SeekableReadStream *stream = Common::wrapCompressedReadStream(wizTemplate);
+
+	stream->seek(0x0448);
+	for (j = 0; j < 139; ++j) {
+		for (i = 0; i < 139; ++i) {
+			uint16 data = stream->readUint16BE();
+			wiz[i][j] = data;
+		}
+	}
+	delete stream;
+
+	for (j = 0; j < _energy * 9; j++) {
+		for (i = 30; i < 51; i++) {
+			wiz[i][91 - j] = ((255) / 8 ) + ((int) (130 - (j * 100 / (_energy * 9)))) / 8 * 32 + ((int) (80 + j * 80 / (_energy * 9)) / 8 * 1024);
+		}
+	}
+
+	for (j = 0; j < _terrain * 9; j++) {
+		for (i = 61; i < 82; i++) {
+			wiz[i][91 - j] = ((255) / 8 ) + ((int) (130 - (j * 100 / (_terrain*9))))/8 * 32 + ((int) (80 + j * 80 / (_terrain * 9)) / 8 * 1024);
+		}
+	}
+
+	for (j = 0; j < _water * 9; j++) {
+		for (i = 92; i < 113; i++) {
+			wiz[i][91 - j] = ((255) / 8 ) + ((int) (130 - (j * 100 / (_water * 9)))) / 8 * 32 + ((int) (80 + j * 80 / (_water*9)) / 8 * 1024);
+		}
+	}
+
+	// Re-read the template (to avoid compressed stream seeking):
+	wizTemplate = new Common::MemoryReadStream(Template_wiz, ARRAYSIZE(Template_wiz));
+	stream = Common::wrapCompressedReadStream(wizTemplate);
+	byte *pwiz = (byte *)malloc(TEMPLATE_WIZ_SIZE);
+	stream->read(pwiz, TEMPLATE_WIZ_SIZE);
+	delete stream;
+
+	Common::SeekableMemoryWriteStream ws = Common::SeekableMemoryWriteStream(pwiz, TEMPLATE_WIZ_SIZE);
+	ws.seek(0x0448);
+	for (j = 0; j < 139; j++) {
+		for (i = 0; i < 139; i++) {
+			ws.writeUint16BE(wiz[i][j]);
+		}
+	}
+
+	return new Common::MemoryReadStream(pwiz, TEMPLATE_WIZ_SIZE, DisposeAfterUse::YES);
+}
+
+Common::SeekableReadStream *Map::substituteFile(const byte *fileName) {
+	if (_mapGenerated) {
+		// Worth noting here that the game opens these files more than once.
+		// The exact scenario for the .thm and .wiz files is that the game
+		// opens it first to make sure that it exists and readable, closes it,
+		// and calls processWizImage to open the file again to actually read
+		// the data inside.
+		if (!strcmp((const char *)fileName, "map\\moon001.thm")) {
+			// Load compressed thumbnail data from header.
+			Common::MemoryReadStream *templateThm = new Common::MemoryReadStream(Template_thm, ARRAYSIZE(Template_thm));
+			Common::SeekableReadStream *stream = Common::wrapCompressedReadStream(templateThm);
+
+			// Read the uncompressed data into memory
+			// (This is done to avoid compressed stream seeking)
+			byte *thumbnail = (byte *)malloc(TEMPLATE_THM_SIZE);
+			stream->read(thumbnail, TEMPLATE_THM_SIZE);
+			delete stream;
+
+			// And return a new ReadStream for it.
+			return new Common::MemoryReadStream(thumbnail, TEMPLATE_THM_SIZE, DisposeAfterUse::YES);
+		}
+
+		if (!strcmp((const char *)fileName, "map\\moon001.wiz")) {
+			return makeWiz();
+		}
+	}
 	return nullptr;
 }
 
diff --git a/engines/scumm/he/moonbase/map_main.h b/engines/scumm/he/moonbase/map_main.h
index 610f4f0f8ec..2e863ac1482 100644
--- a/engines/scumm/he/moonbase/map_main.h
+++ b/engines/scumm/he/moonbase/map_main.h
@@ -27,6 +27,9 @@
 #include "common/stream.h"
 #include "common/random.h"
 
+#define SPIFF_GEN  1
+#define KATTON_GEN 2
+
 namespace Scumm {
 
 class Map {
@@ -34,8 +37,14 @@ public:
 	Map(ScummEngine_v100he *vm);
 	~Map();
 
+	bool generateNewMap();
+	bool generateMapWithInfo(uint8 generator, uint32 seed, int mapSize, int tileset, int energy, int terrain, int water);
 	Common::SeekableReadStream *substituteFile(const byte *fileName);
 
+	uint32 getSeed() const {
+		return _randSeed;
+	}
+
 private:
 	ScummEngine_v100he *_vm;
 
@@ -43,6 +52,15 @@ private:
 	// so we can send and set seeds from online players to ensure
 	// they're playing on the same generated map.
 	Common::RandomSource _rnd;
+	uint32 _randSeed;
+
+	bool _mapGenerated;
+
+	// Data for makeWiz:
+	int _energy;
+	int _terrain;
+	int _water;
+	Common::SeekableReadStream *makeWiz();
 };
 
 } // End of namespace Scumm
diff --git a/engines/scumm/he/script_v100he.cpp b/engines/scumm/he/script_v100he.cpp
index 1120ce4d17c..d642b30e55b 100644
--- a/engines/scumm/he/script_v100he.cpp
+++ b/engines/scumm/he/script_v100he.cpp
@@ -35,6 +35,9 @@
 #include "scumm/he/sprite_he.h"
 #include "scumm/util.h"
 
+#include "scumm/he/moonbase/moonbase.h"
+#include "scumm/he/moonbase/map_main.h"
+
 namespace Scumm {
 
 #define OPCODE(i, x2)	_opcodes[i]._OPCODE(ScummEngine_v100he, x2)
@@ -2163,8 +2166,11 @@ void ScummEngine_v100he::o100_startScript() {
 
 	if (_game.id == GID_MOONBASE && _roomResource == 5 &&
 		((!strcmp(_game.variant, "1.1") && script == 2178) || script == 2177)) {
-		// TODO: Add a dialog for random map generation.
-		debug(1, "this is setup-gamesetup");
+		// TODO: Only run if we're doing a single-player skirmesh or hosting a
+		// multiplayer game.
+		// (gGameMode == GAME-MODE-MULTIPLAYER-HOST || gGameMode == GAME-MODE-TCPIP-HOST ||
+		//  gGameMode == GAME-MODE-SINGLEPLAYER-SKIRMISH)
+		_moonbase->_map->generateNewMap();
 	}
 
 	runScript(script, (flags == SO_BAK || flags == SO_BAKREC), (flags == SO_REC || flags == SO_BAKREC), args);


Commit: f2a8a7e2bdd2e419e3ad14d47cc12e97c62cfad1
    https://github.com/scummvm/scummvm/commit/f2a8a7e2bdd2e419e3ad14d47cc12e97c62cfad1
Author: Little Cat (toontownlittlecat at gmail.com)
Date: 2024-05-12T15:08:27+02:00

Commit Message:
SCUMM HE: Moonbase maps now generated.

Slighty broken at the moment, sometimes it works, sometimes it doesn't.
Sometimes there will be too many energy pools, or none at all.

Changed paths:
  A engines/scumm/he/moonbase/map_mif.cpp
  A engines/scumm/he/moonbase/map_mif.h
    engines/scumm/he/moonbase/map_main.cpp
    engines/scumm/he/moonbase/map_main.h
    engines/scumm/he/moonbase/map_spiff.cpp
    engines/scumm/he/moonbase/map_spiff.h
    engines/scumm/module.mk


diff --git a/engines/scumm/he/moonbase/map_main.cpp b/engines/scumm/he/moonbase/map_main.cpp
index 075573680c8..6342721f52c 100644
--- a/engines/scumm/he/moonbase/map_main.cpp
+++ b/engines/scumm/he/moonbase/map_main.cpp
@@ -34,6 +34,7 @@ namespace Scumm {
 
 Map::Map(ScummEngine_v100he *vm) : _vm(vm), _rnd("moonbase") {
 	_mapGenerated = false;
+	_generatedMap = nullptr;
 
 	_energy = 0;
 	_terrain = 0;
@@ -41,14 +42,23 @@ Map::Map(ScummEngine_v100he *vm) : _vm(vm), _rnd("moonbase") {
 }
 
 Map::~Map() {
+	if (_generatedMap) {
+		delete _generatedMap;
+	}
 }
 
 bool Map::generateNewMap() {
 
 	// TODO: Show a dialog allowing the user to customize options.
 
+	// Create a new seed just for the below values.  This is to
+	// ensure these are truely random after generating a previous
+	// map (or to debug with a prefixed seed).
+	_rnd.generateNewSeed();
+
 	// Don't randomly pick nonstandard map sizes.
 	int mapSize = _rnd.getRandomNumberRngSigned(4, 8) * 8;
+	mapSize = 4 * 8;
 
 	int tileSet = _rnd.getRandomNumberRngSigned(1, 7);
 
@@ -57,21 +67,27 @@ bool Map::generateNewMap() {
 	int terrain = _rnd.getRandomNumberRngSigned(2, 4);
 	int water = _rnd.getRandomNumberRngSigned(2, 4);
 
-	_randSeed = _rnd.generateNewSeed();
-
-	return generateMapWithInfo(SPIFF_GEN, _randSeed, mapSize, tileSet, energy, terrain, water);
+	return generateMapWithInfo(SPIFF_GEN, 0, mapSize, tileSet, energy, terrain, water);
 }
 
 bool Map::generateMapWithInfo(uint8 generator, uint32 seed, int mapSize, int tileset, int energy, int terrain, int water) {
-	_rnd.setSeed(seed);
+	if (_generatedMap) {
+		// Delete old map.
+		delete _generatedMap;
+	}
 
-	debug(1, "Map: Generating new map with info: generator = %d, seed = %d, mapSize = %d, tileset = %d , energy = %d, terrain = %d, water = %d.", generator, seed, mapSize, tileset, energy, terrain, water);
+	if (seed) {
+		_rnd.setSeed(seed);
+	} else {
+		_rnd.generateNewSeed();
+	}
+
+	debug(1, "Map: Generating new map with info: generator = %d, seed = %d, mapSize = %d, tileset = %d , energy = %d, terrain = %d, water = %d.", generator, getSeed(), mapSize, tileset, energy, terrain, water);
 	switch (generator) {
 	case SPIFF_GEN:
 	{
 		SpiffGenerator spiff = SpiffGenerator(&_rnd);
-		spiff.generateMap(water, mapSize, energy, terrain);
-		// TODO: Actually create the map file.
+		_generatedMap = spiff.generateMap(water, mapSize, energy, terrain);
 		break;
 	}
 	default:
@@ -98,7 +114,7 @@ Common::SeekableReadStream *Map::makeWiz() {
 	stream->seek(0x0448);
 	for (j = 0; j < 139; ++j) {
 		for (i = 0; i < 139; ++i) {
-			uint16 data = stream->readUint16BE();
+			uint16 data = stream->readUint16LE();
 			wiz[i][j] = data;
 		}
 	}
@@ -133,7 +149,7 @@ Common::SeekableReadStream *Map::makeWiz() {
 	ws.seek(0x0448);
 	for (j = 0; j < 139; j++) {
 		for (i = 0; i < 139; i++) {
-			ws.writeUint16BE(wiz[i][j]);
+			ws.writeUint16LE(wiz[i][j]);
 		}
 	}
 
@@ -165,6 +181,12 @@ Common::SeekableReadStream *Map::substituteFile(const byte *fileName) {
 		if (!strcmp((const char *)fileName, "map\\moon001.wiz")) {
 			return makeWiz();
 		}
+
+		if (!strcmp((const char *)fileName, "map\\moon001.map")) {
+			// Return new ReadStream but do not dispose it.  We'll handle
+			// that ourselves.
+			return new Common::MemoryReadStream((byte *)_generatedMap, sizeof(MapFile));
+		}
 	}
 	return nullptr;
 }
diff --git a/engines/scumm/he/moonbase/map_main.h b/engines/scumm/he/moonbase/map_main.h
index 2e863ac1482..47a005d0cd4 100644
--- a/engines/scumm/he/moonbase/map_main.h
+++ b/engines/scumm/he/moonbase/map_main.h
@@ -27,6 +27,8 @@
 #include "common/stream.h"
 #include "common/random.h"
 
+#include "engines/scumm/he/moonbase/map_mif.h"
+
 #define SPIFF_GEN  1
 #define KATTON_GEN 2
 
@@ -42,7 +44,7 @@ public:
 	Common::SeekableReadStream *substituteFile(const byte *fileName);
 
 	uint32 getSeed() const {
-		return _randSeed;
+		return _rnd.getSeed();
 	}
 
 private:
@@ -52,9 +54,9 @@ private:
 	// so we can send and set seeds from online players to ensure
 	// they're playing on the same generated map.
 	Common::RandomSource _rnd;
-	uint32 _randSeed;
 
 	bool _mapGenerated;
+	MapFile *_generatedMap;
 
 	// Data for makeWiz:
 	int _energy;
diff --git a/engines/scumm/he/moonbase/map_mif.cpp b/engines/scumm/he/moonbase/map_mif.cpp
new file mode 100644
index 00000000000..fe2f6bb924c
--- /dev/null
+++ b/engines/scumm/he/moonbase/map_mif.cpp
@@ -0,0 +1,825 @@
+/* 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/str.h"
+#include "common/textconsole.h"
+
+#include "scumm/he/moonbase/map_mif.h"
+
+namespace Scumm {
+
+static byte waterTileMap[] = {
+	0x44, 0x40, 0x32, 0x32, 0x3C, 0x38, 0x32, 0x32, // 0x00
+	0x2C, 0x2C, 0x26, 0x26, 0x2A, 0x2A, 0x26, 0x26,
+	0x2F, 0x2D, 0x27, 0x27, 0x2F, 0x2D, 0x27, 0x27, // 0x10
+	0x1B, 0x1B, 0x49, 0x49, 0x1B, 0x1B, 0x49, 0x49,
+	0x42, 0x3E, 0x30, 0x30, 0x3A, 0x36, 0x30, 0x30, // 0x20
+	0x2C, 0x2C, 0x26, 0x26, 0x2A, 0x2A, 0x26, 0x26,
+	0x2E, 0x22, 0x1E, 0x1E, 0x2E, 0x22, 0x1E, 0x1E, // 0x30
+	0x1B, 0x1B, 0x49, 0x49, 0x1B, 0x1B, 0x49, 0x49,
+	0x35, 0x33, 0x1C, 0x1C, 0x34, 0x24, 0x1C, 0x1C, // 0x40
+	0x28, 0x28, 0x4B, 0x4B, 0x1F, 0x1F, 0x4B, 0x4B,
+	0x29, 0x20, 0x4C, 0x4C, 0x29, 0x20, 0x4C, 0x4C, // 0x50
+	0x48, 0x48, 0x4A, 0x4A, 0x48, 0x48, 0x4A, 0x4A,
+	0x35, 0x33, 0x1C, 0x1C, 0x34, 0x24, 0x1C, 0x1C, // 0x60
+	0x28, 0x28, 0x4B, 0x4B, 0x1F, 0x1F, 0x4B, 0x4B,
+	0x29, 0x20, 0x4C, 0x4C, 0x29, 0x20, 0x4C, 0x4C, // 0x70
+	0x48, 0x48, 0x4A, 0x4A, 0x48, 0x48, 0x4A, 0x4A,
+	0x43, 0x3F, 0x31, 0x31, 0x3B, 0x37, 0x31, 0x31, // 0x80
+	0x2B, 0x2B, 0x1D, 0x1D, 0x21, 0x21, 0x1D, 0x1D,
+	0x2F, 0x2D, 0x27, 0x27, 0x2F, 0x2D, 0x27, 0x27, // 0x90
+	0x1B, 0x1B, 0x49, 0x49, 0x1B, 0x1B, 0x49, 0x49,
+	0x41, 0x3D, 0x23, 0x23, 0x39, 0x25, 0x23, 0x23, // 0xA0
+	0x2B, 0x2B, 0x1D, 0x1D, 0x21, 0x21, 0x1D, 0x1D,
+	0x2E, 0x22, 0x1E, 0x1E, 0x2E, 0x22, 0x1E, 0x1E, // 0xB0
+	0x1B, 0x1B, 0x49, 0x49, 0x1B, 0x1B, 0x49, 0x49,
+	0x35, 0x33, 0x1C, 0x1C, 0x34, 0x24, 0x1C, 0x1C, // 0xC0
+	0x28, 0x28, 0x4B, 0x4B, 0x1F, 0x1F, 0x4B, 0x4B,
+	0x29, 0x20, 0x4C, 0x4C, 0x29, 0x20, 0x4C, 0x4C, // 0xD0
+	0x48, 0x48, 0x4A, 0x4A, 0x48, 0x48, 0x4A, 0x4A,
+	0x35, 0x33, 0x1C, 0x1C, 0x34, 0x24, 0x1C, 0x1C, // 0xE0
+	0x28, 0x28, 0x4B, 0x4B, 0x1F, 0x1F, 0x4B, 0x4B,
+	0x29, 0x20, 0x4C, 0x4C, 0x29, 0x20, 0x4C, 0x4C, // 0xF0
+	0x48, 0x48, 0x4A, 0x4A, 0x48, 0x48, 0x4A, 0x4A
+};
+
+static int magic(int x, int y) {
+	static byte matrix[8][8] = {
+		{ 2, 0, 2, 1, 3, 0, 3, 1 } ,
+		{ 3, 1, 0, 3, 2, 1, 0, 2 } ,
+		{ 0, 2, 1, 2, 0, 3, 1, 3 } ,
+		{ 1, 3, 0, 3, 1, 2, 0, 2 } ,
+		{ 2, 0, 1, 2, 3, 0, 1, 3 } ,
+		{ 3, 1, 3, 0, 2, 1, 2, 0 } ,
+		{ 0, 2, 0, 1, 3, 0, 3, 2 } ,
+		{ 1, 3, 0, 3, 2, 1, 2, 0 }
+	};
+	return matrix[y % 8][x % 8];
+}
+
+MIF::MIF() {
+}
+
+void MIF::generateMap(MapFile *map) {
+	map->terrainDimX = dimension;
+	map->terrainDimY = dimension;
+	map->mapType = mapType;
+	Common::strlcpy(map->name, name, 17);
+
+	int x, y;
+	for (y = 0; y < dimension; ++y) {
+		for (x = 0; x < dimension; ++x) {
+			map->terrainStates[x][y] = findTileFor(x, y);
+		}
+	}
+
+	defineEnergyPools(map);
+	defineStartLocations(map);
+	makeCraters(map);
+}
+
+void MIF::defineStartLocations(MapFile *map) {
+	int x, y;
+
+	for (y = 0; y < dimension; ++y) {
+		for (x = 0; x < dimension; ++x) {
+			char ch = centerMap[x][y];
+
+			if (ch < 0) {
+				int i;
+				ch = -ch;
+
+				if (ch & 1) {
+					// 4 player start
+					i = 0;
+					while (i < 4) {
+						if (map->fourPlayerPoints[i].x == 0xFFFF) {
+							map->fourPlayerPoints[i].x = x * 60;
+							map->fourPlayerPoints[i].y = y * 60;
+							break;
+						}
+						++i;
+					}
+				}
+				ch = ch >> 1;
+				if (ch & 1) {
+					// 3 player start
+					i = 0;
+					while (i < 3) {
+						if (map->threePlayerPoints[i].x == 0xFFFF) {
+							map->threePlayerPoints[i].y = x * 60;
+							map->threePlayerPoints[i].y = y * 60;
+							break;
+						}
+						++i;
+					}
+				}
+				ch = ch >> 1;
+				if (ch & 1) {
+					// 2 player start
+					i = 0;
+					while (i < 2) {
+						if (map->twoPlayerPoints[i].x == 0xFFFF) {
+							map->twoPlayerPoints[i].x = x * 60;
+							map->twoPlayerPoints[i].y = y * 60;
+							break;
+						}
+						++i;
+					}
+				}
+				ch = ch >> 1;
+				if (ch & 1) {
+					// 2v2 player start
+					i = 0;
+					while (i < 4) {
+						if (map->twoVTwoPoints[i].x == 0xFFFF) {
+							map->twoVTwoPoints[i].x = x * 60;
+							map->twoVTwoPoints[i].y = y * 60;
+							break;
+						}
+						++i;
+					}
+				}
+				ch = ch >> 1;
+				if (ch & 1) {
+					// 1v3 player start
+					i = 0;
+					while (i < 4) {
+						if (map->oneVThreePoints[i].x == 0xFFFF) {
+							map->oneVThreePoints[i].x = x * 60;
+							map->oneVThreePoints[i].y = y * 60;
+							break;
+						}
+						++i;
+					}
+				}
+				ch = ch >> 1;
+				if (ch & 1) {
+					// 1v2 player start
+					i = 0;
+					while (i < 3) {
+						if (map->oneVTwoPoints[i].x == 0xFFFF) {
+							map->oneVTwoPoints[i].x = x * 60;
+							map->oneVTwoPoints[i].y = y * 60;
+							break;
+						}
+						++i;
+					}
+				}
+			}
+		}
+	}
+}
+
+void MIF::defineEnergyPools(MapFile *map) {
+	int x, y;
+
+	for (y = 0; y < dimension; ++y) {
+		for (x = 0; x < dimension; ++x) {
+			char ch = centerMap[x][y];
+
+			if ('S' == ch || 'M' == ch || 'L' == ch) {
+				// Verify legal position
+				if (!((tlCorner(x, y) == trCorner(x, y)) && (blCorner(x, y) == brCorner(x, y)) &&
+					(tlCorner(x, y) == blCorner(x, y)) && (trCorner(x, y) == brCorner(x, y)))) {
+					error("small and medium energy pools must be on a flat tile (%d, %d)", x, y);
+				}
+
+				if ('L' == ch) {
+					byte nHeight;
+					nHeight = blCorner(x, y);
+					if (!(tlCorner(x, y) == nHeight && ttlCorner(x, y) == nHeight && ttrCorner(x, y) == nHeight && trCorner(x, y) == nHeight && brCorner(x, y) == nHeight)) {
+						error("large energy pools must be on the lower of two flat tiles (%d, %d)", x, y);
+					}
+				}
+
+				int xLoc;
+				int yLoc;
+
+				if ('S' == ch) {
+					xLoc = 60 * x + 30 + 20000;
+					yLoc = 60 * y + 30;
+				} else if ('M' == ch) {
+					xLoc = 60 * x + 30 + 10000;
+					yLoc = 60 * y + 30;
+				} else {
+					xLoc = 60 * x + 30;
+					yLoc = 60 * y;
+				}
+
+				if (map->numEnergyPools < 49) {
+					map->poolLocs[map->numEnergyPools].location.x = xLoc;
+					map->poolLocs[map->numEnergyPools].location.y = yLoc;
+
+					++map->numEnergyPools;
+				} else if (map->numEnergyPools == 49) {
+					map->lastPool.x = xLoc;
+					map->lastPool.y = yLoc;
+
+					++map->numEnergyPools;
+				} else {
+					error("only 50 energy pools are allowed, this is the 51st (%d, %d)", x, y);
+				}
+			}
+		}
+	}
+}
+
+void MIF::makeCraters(MapFile *map) {
+	// squarenumber, type, x, y (offset from top left (abs y)). x/y = 9 if none of that type
+	static byte locations[8][3][2] = {
+		{ {1, 1}, {5, 2}, {3, 5} },
+		{ {6, 1}, {1, 6}, {2, 0} },
+		{ {0, 4}, {3, 2}, {6, 5} },
+		{ {4, 4}, {5, 0}, {9, 9} },
+		{ {3, 6}, {9, 9}, {2, 1} },
+		{ {9, 9}, {3, 3}, {0, 2} },
+		{ {2, 4}, {0, 0}, {5, 3} },
+		{ {4, 1}, {0, 3}, {5, 6} }
+	};
+
+	// I made up the crater patterns for sizes larger than SAI
+	// This will work for maps up to 80x80
+	static byte largegrid[10][10] =  {
+		{0, 1, 2, 3, 4, 5, 6, 7, 0, 1},
+		{2, 3, 4, 5, 6, 7, 0, 1, 2, 3},
+		{4, 5, 6, 7, 0, 1, 2, 3, 4, 5},
+		{3, 0, 1, 2, 6, 4, 5, 7, 3, 0},
+		{1, 2, 3, 4, 5, 6, 7, 0, 1, 2},
+		{3, 4, 5, 6, 7, 0, 1, 2, 3, 4},
+		{6, 3, 0, 1, 2, 7, 4, 5, 6, 3},
+		{5, 6, 7, 0, 1, 2, 3, 4, 5, 6},
+		{0, 1, 2, 3, 4, 5, 6, 7, 0, 1},
+		{2, 3, 4, 5, 6, 7, 0, 1, 2, 3}
+	};
+
+	for (int i = 0; i < dimension / 8; i++) {
+		for (int j = 0; j < dimension / 8; j++) {
+			for (int nCrater = 0; nCrater < 3; nCrater++) {
+				if (9 == locations[largegrid[j][i]][nCrater][0]) {
+					continue;
+				}
+
+				int x = locations[largegrid[j][i]][nCrater][0] + i * 8;
+				int y = locations[largegrid[j][i]][nCrater][1] + j * 8;
+
+				byte nLevel = tlCorner(x, y);
+				if ((tlCorner(x, y) == nLevel) && (trCorner(x, y) == nLevel) && (trrCorner(x, y) == nLevel) &&
+					(centerMap[x][y] != 'W') && (centerMap[x + 1][y] != 'W') &&
+					(blCorner(x, y) == nLevel) && (brCorner(x, y) == nLevel) && (brrCorner(x, y) == nLevel) &&
+					(centerMap[x][y + 1] != 'W') && (centerMap[x + 1][y + 1] != 'W') &&
+					(bblCorner(x, y) == nLevel) && (bbrCorner(x, y) == nLevel) && (bbrrCorner(x, y) == nLevel)) {
+					// The tile values follow a predictable pattern, level one craters in order, etc.
+					int16 nBase = 0xA6 + (tlCorner(x, y) * 12) + (nCrater * 4);
+
+					map->terrainStates[x][y] = nBase;
+					map->terrainStates[x + 1][y] = nBase + 1;
+					map->terrainStates[x][y + 1] = nBase + 2;
+					map->terrainStates[x + 1][y + 1] = nBase + 3;
+				}
+			}
+		}
+	}
+}
+
+uint16 MIF::findTileFor(int x, int y) {
+	int index;
+	char ch;
+
+	byte aLowBlanks[] = {0x93, 0x94, 0x00, 0x96};
+	byte aMedBlanks[] = {0x97, 0x99, 0x0D, 0x9A};
+	byte aHiBlanks[] = {0x9B, 0x9C, 0x1A, 0x9D};
+	ch = centerMap[x][y];
+
+	debug(5, "MIF: Tile for %d, %d is %c", x, y, ch);
+
+	if ('S' == ch || 'M' == ch || 'L' == ch || '.' == ch || ch < 0) {
+		// Do the easy cases, things with no transitions.
+		if (0 == tlCorner(x, y) && 0 == trCorner(x, y) && 0 == blCorner(x, y) && 0 == brCorner(x, y))
+			return aLowBlanks[magic(x, y)];
+		if (1 == tlCorner(x, y) && 1 == trCorner(x, y) && 1 == blCorner(x, y) && 1 == brCorner(x, y))
+			return aMedBlanks[magic(x, y)];
+		if (2 == tlCorner(x, y) && 2 == trCorner(x, y) && 2 == blCorner(x, y) && 2 == brCorner(x, y))
+			return aHiBlanks[magic(x, y)];
+
+		//
+		// Low to med transitions
+		//
+		if (0 == tlCorner(x, y) || 0 == trCorner(x, y) || 0 == blCorner(x, y) || 0 == brCorner(x, y)) {
+			// Corner cases
+
+			int CornerSum = tlCorner(x, y) + trCorner(x, y) + blCorner(x, y) + brCorner(x, y);
+
+			if (1 == CornerSum) {
+				if (tlCorner(x, y)) {
+					if (tllCorner(x, y) > 0 && ttlCorner(x, y) > 0)
+						return 0x03;
+					else
+						return 0x89;
+				} else if (trCorner(x, y)) {
+					if (trrCorner(x, y) > 0 && ttrCorner(x, y) > 0)
+						return 0x04;
+					else
+						return 0x8C;
+				} else if (blCorner(x, y)) {
+					if (bllCorner(x, y) > 0 && bblCorner(x, y) > 0)
+						return 0x02;
+					else
+						return 0x86;
+				} else // brCorner
+				{
+					if (brrCorner(x, y) > 0 && bbrCorner(x, y) > 0)
+						return 0x01;
+					else
+						return 0x83;
+				}
+			}
+
+			// Straight edges
+
+			// edge on bottom
+			if (tlCorner(x, y) == 0 && trCorner(x, y) == 0 && blCorner(x, y) == 1 && brCorner(x, y) == 1) {
+				bool bLeftEased = (bllCorner(x, y) == 0 && bblCorner(x, y) == 1);
+				bool bRightEased = (brrCorner(x, y) == 0 && bbrCorner(x, y) == 1);
+
+				if (bLeftEased && bRightEased)
+					return 0x0A;
+				if (!bLeftEased && bRightEased)
+					return 0x54;
+				if (bLeftEased && !bRightEased)
+					return 0x55;
+				if (!bLeftEased && !bRightEased)
+					return (magic(x, y) & 0x01) ? 0x9F : 0x56;
+			}
+			// edge on top
+			else if (tlCorner(x, y) == 1 && trCorner(x, y) == 1 && blCorner(x, y) == 0 && brCorner(x, y) == 0) {
+				bool bLeftEased = (tllCorner(x, y) == 0 && ttlCorner(x, y) == 1);
+				bool bRightEased = (trrCorner(x, y) == 0 && ttrCorner(x, y) == 1);
+
+				if (bLeftEased && bRightEased)
+					return 0x0C;
+				if (!bLeftEased && bRightEased)
+					return 0x52;
+				if (bLeftEased && !bRightEased)
+					return 0x51;
+				if (!bLeftEased && !bRightEased)
+					return (magic(x, y) & 0x01) ? 0xA1 : 0x53;
+			}
+			// edge on right
+			if (tlCorner(x, y) == 0 && blCorner(x, y) == 0 && trCorner(x, y) == 1 && brCorner(x, y) == 1) {
+				bool bTopEased = (ttrCorner(x, y) == 0 && trrCorner(x, y) == 1);
+				bool bBotEased = (bbrCorner(x, y) == 0 && brrCorner(x, y) == 1);
+
+				if (bTopEased && bBotEased)
+					return 0x09;
+				if (!bTopEased && bBotEased)
+					return 0x5B;
+				if (bTopEased && !bBotEased)
+					return 0x5A;
+				if (!bTopEased && !bBotEased)
+					return (magic(x, y) & 0x01) ? 0x9E : 0x5C;
+			}
+			// edge on left
+			if (tlCorner(x, y) == 1 && blCorner(x, y) == 1 && trCorner(x, y) == 0 && brCorner(x, y) == 0) {
+				bool bTopEased = (ttlCorner(x, y) == 0 && tllCorner(x, y) == 1);
+				bool bBotEased = (bblCorner(x, y) == 0 && bllCorner(x, y) == 1);
+
+				if (bTopEased && bBotEased)
+					return 0x0B;
+				if (!bTopEased && bBotEased)
+					return 0x57;
+				if (bTopEased && !bBotEased)
+					return 0x58;
+				if (!bTopEased && !bBotEased)
+					return (magic(x, y) & 0x01) ? 0xA0 : 0x59;
+			}
+
+			// Three corner cases
+
+			// 0 1         1 1           0 0 0       0 0 0
+			// 0 1 1 0x5F  0 1 1 0x5E    0 1 1 0x62  0 1 1 0x60
+			// 0 0 0       0 0 0         0 1         1 1
+			//
+			// 0 1         1 1           0 0 1       0 0 1
+			// 0 1 1 0x5D  0 1 1 0x06    0 1 1 0x61  0 1 1 0x07
+			// 0 0 1       0 0 1         0 1         1 1
+			//
+			//
+			// 0 0 0       1 0 0           1 0         1 1
+			// 1 1 0 0x65  1 1 0 0x63    1 1 0 0x68  1 1 0 0x66
+			//   1 0         1 0         0 0 0       0 0 0
+			//
+			// 0 0 0       1 0 0           1 0         1 1
+			// 1 1 0 0x64  1 1 0 0x08    1 1 0 0x67  1 1 0 0x05
+			//   1 1         1 1         1 0 0       1 0 0
+
+			// corner in upper left
+			if (blCorner(x, y) == 1 && tlCorner(x, y) == 1 && trCorner(x, y) == 1) {
+				bool BLDiag = (bllCorner(x, y) > 0 && bblCorner(x, y) == 0);
+				bool TRDiag = (ttrCorner(x, y) > 0 && trrCorner(x, y) == 0);
+
+				if (!BLDiag && !TRDiag)
+					return 0x62;
+				else if (!BLDiag && TRDiag)
+					return 0x61;
+				else if (BLDiag && !TRDiag)
+					return 0x60;
+				else
+					return 0x07;
+			}
+
+			// corner in upper right
+			if (tlCorner(x, y) == 1 && trCorner(x, y) == 1 && brCorner(x, y) == 1) {
+				bool TLDiag = (ttlCorner(x, y) > 0 && tllCorner(x, y) == 0);
+				bool BRDiag = (brrCorner(x, y) > 0 && bbrCorner(x, y) == 0);
+
+				if (!TLDiag && !BRDiag)
+					return 0x65;
+				else if (!TLDiag && BRDiag)
+					return 0x64;
+				else if (TLDiag && !BRDiag)
+					return 0x63;
+				else
+					return 0x08;
+			}
+
+			// corner in bottom right
+			if (trCorner(x, y) == 1 && brCorner(x, y) == 1 && blCorner(x, y) == 1) {
+				bool TRDiag = (trrCorner(x, y) > 0 && ttrCorner(x, y) == 0);
+				bool BLDiag = (bblCorner(x, y) > 0 && bllCorner(x, y) == 0);
+
+				if (!TRDiag && !BLDiag)
+					return 0x68;
+				else if (!TRDiag && BLDiag)
+					return 0x67;
+				else if (TRDiag && !BLDiag)
+					return 0x66;
+				else
+					return 0x05;
+			}
+
+			// corner in bottom left
+			if (brCorner(x, y) == 1 && blCorner(x, y) == 1 && tlCorner(x, y) == 1) {
+				bool TLDiag = (tllCorner(x, y) > 0 && ttlCorner(x, y) == 0);
+				bool BRDiag = (bbrCorner(x, y) > 0 && brrCorner(x, y) == 0);
+
+				if (!TLDiag && !BRDiag)
+					return 0x5F;
+				else if (!TLDiag && BRDiag)
+					return 0x5D;
+				else if (TLDiag && !BRDiag)
+					return 0x5E;
+				else
+					return 0x06;
+			}
+
+			// Opposing corner cases
+			if (tlCorner(x, y) == 1 && brCorner(x, y) == 1) {
+				// There are four cases, big big, big small, small big, small small
+
+				// big big
+				if (tllCorner(x, y) > 0 && ttlCorner(x, y) > 0 && brrCorner(x, y) > 0 && bbrCorner(x, y) > 0)
+					return 0x4D;
+				// big small
+				if (tllCorner(x, y) > 0 && ttlCorner(x, y) > 0)
+					return 0x81;
+				// small big
+				if (brrCorner(x, y) > 0 && bbrCorner(x, y) > 0)
+					return 0x82;
+				// small small
+				return 0x84;
+			}
+			if (trCorner(x, y) == 1 && blCorner(x, y) == 1) {
+				// There are four cases, big big, big small, small big, small small
+
+				// big big
+				if (trrCorner(x, y) > 0 && ttrCorner(x, y) > 0 && bllCorner(x, y) > 0 && bblCorner(x, y) > 0)
+					return 0x4E;
+				// big small
+				if (trrCorner(x, y) > 0 && ttrCorner(x, y) > 0)
+					return 0x85;
+				// small big
+				if (bllCorner(x, y) > 0 && bblCorner(x, y) > 0)
+					return 0x87;
+				// small small
+				return 0x88;
+			}
+		}
+
+		//
+		// Med to high transitions
+		//
+		if (1 == tlCorner(x, y) || 1 == trCorner(x, y) || 1 == blCorner(x, y) || 1 == brCorner(x, y)) {
+			// Corner cases
+
+			int CornerSum = (tlCorner(x, y) == 2) + (trCorner(x, y) == 2) + (blCorner(x, y) == 2) + (brCorner(x, y) == 2);
+
+			if (1 == CornerSum) {
+				if (tlCorner(x, y) == 2) {
+					if (tllCorner(x, y) == 2 && ttlCorner(x, y) == 2)
+						return 0x10;
+					else
+						return 0x95;
+				} else if (trCorner(x, y) == 2) {
+					if (trrCorner(x, y) == 2 && ttrCorner(x, y) == 2)
+						return 0x11;
+					else
+						return 0x98;
+				} else if (blCorner(x, y) == 2) {
+					if (bllCorner(x, y) == 2 && bblCorner(x, y) == 2)
+						return 0x0F;
+					else
+						return 0x92;
+				} else // brCorner
+				{
+					if (brrCorner(x, y) == 2 && bbrCorner(x, y) == 2)
+						return 0x0E;
+					else
+						return 0x8F;
+				}
+			}
+
+			// Straight edges
+
+			// edge on bottom
+			if (tlCorner(x, y) < 2 && trCorner(x, y) < 2 && blCorner(x, y) == 2 && brCorner(x, y) == 2) {
+				bool bLeftEased = (bllCorner(x, y) < 2 && bblCorner(x, y) == 2);
+				bool bRightEased = (brrCorner(x, y) < 2 && bbrCorner(x, y) == 2);
+
+				if (bLeftEased && bRightEased)
+					return 0x17;
+				if (!bLeftEased && bRightEased)
+					return 0x6C;
+				if (bLeftEased && !bRightEased)
+					return 0x6D;
+				if (!bLeftEased && !bRightEased)
+					return (magic(x, y) & 0x01) ? 0xA3 : 0x6E;
+			}
+			// edge on top
+			else if (tlCorner(x, y) == 2 && trCorner(x, y) == 2 && blCorner(x, y) < 2 && brCorner(x, y) < 2) {
+				bool bLeftEased = (tllCorner(x, y) < 2 && ttlCorner(x, y) == 2);
+				bool bRightEased = (trrCorner(x, y) < 2 && ttrCorner(x, y) == 2);
+
+				if (bLeftEased && bRightEased)
+					return 0x19;
+				if (!bLeftEased && bRightEased)
+					return 0x6A;
+				if (bLeftEased && !bRightEased)
+					return 0x69;
+				if (!bLeftEased && !bRightEased)
+					return (magic(x, y) & 0x01) ? 0xA5 : 0x6B;
+			}
+			// edge on right
+			if (tlCorner(x, y) < 2 && blCorner(x, y) < 2 && trCorner(x, y) == 2 && brCorner(x, y) == 2) {
+				bool bTopEased = (ttrCorner(x, y) < 2 && trrCorner(x, y) == 2);
+				bool bBotEased = (bbrCorner(x, y) < 2 && brrCorner(x, y) == 2);
+
+				if (bTopEased && bBotEased)
+					return 0x16;
+				if (!bTopEased && bBotEased)
+					return 0x73;
+				if (bTopEased && !bBotEased)
+					return 0x72;
+				if (!bTopEased && !bBotEased)
+					return (magic(x, y) & 0x01) ? 0xA2 : 0x74;
+			}
+			// edge on left
+			if (tlCorner(x, y) == 2 && blCorner(x, y) == 2 && trCorner(x, y) < 2 && brCorner(x, y) < 2) {
+				bool bTopEased = (ttlCorner(x, y) < 2 && tllCorner(x, y) == 2);
+				bool bBotEased = (bblCorner(x, y) < 2 && bllCorner(x, y) == 2);
+
+				if (bTopEased && bBotEased)
+					return 0x18;
+				if (!bTopEased && bBotEased)
+					return 0x6F;
+				if (bTopEased && !bBotEased)
+					return 0x70;
+				if (!bTopEased && !bBotEased)
+					return (magic(x, y) & 0x01) ? 0xA4 : 0x71;
+			}
+
+			// edge on bottom
+			if (tlCorner(x, y) == 1 && trCorner(x, y) == 1 && blCorner(x, y) == 2 && brCorner(x, y) == 2) {
+				// no other high corners
+				if (bllCorner(x, y) < 2 && brrCorner(x, y) < 2)
+					return 0x17;
+				// high corner on left
+				if (bllCorner(x, y) == 2 && brrCorner(x, y) < 2)
+					return 0x6C;
+				// high corner on right
+				if (bllCorner(x, y) < 2 && brrCorner(x, y) == 2)
+					return 0x6D;
+				// both neighbor corners high
+				if (bllCorner(x, y) == 2 && brrCorner(x, y) == 2)
+					return (magic(x, y) & 0x01) ? 0xA3 : 0x6E;
+			}
+			// edge on top
+			else if (tlCorner(x, y) == 2 && trCorner(x, y) == 2 && blCorner(x, y) == 1 && brCorner(x, y) == 1) {
+				// no other high corners
+				if (tllCorner(x, y) < 2 && trrCorner(x, y) < 2)
+					return 0x19;
+				// high corner on left
+				if (tllCorner(x, y) == 2 && trrCorner(x, y) < 2)
+					return 0x6A;
+				// high corner on right
+				if (tllCorner(x, y) < 2 && trrCorner(x, y) == 2)
+					return 0x69;
+				// both neighbor corners high
+				if (tllCorner(x, y) == 2 && trrCorner(x, y) == 2)
+					return (magic(x, y) & 0x01) ? 0xA5 : 0x6B;
+			}
+			// edge on right
+			if (tlCorner(x, y) == 1 && blCorner(x, y) == 1 && trCorner(x, y) == 2 && brCorner(x, y) == 2) {
+				// no high neighbor corners
+				if (ttrCorner(x, y) < 2 && bbrCorner(x, y) < 2)
+					return 0x16;
+				// high neighbor corner on top
+				if (ttrCorner(x, y) == 2 && bbrCorner(x, y) < 2)
+					return 0x73;
+				// high neighbor corner on bottom
+				if (ttrCorner(x, y) < 2 && bbrCorner(x, y) == 2)
+					return 0x72;
+				// both neighbor corners high
+				if (ttrCorner(x, y) == 2 && bbrCorner(x, y) == 2)
+					return (magic(x, y) & 0x01) ? 0xA2 : 0x74;
+			}
+			// edge on left
+			if (tlCorner(x, y) == 2 && blCorner(x, y) == 2 && trCorner(x, y) == 1 && brCorner(x, y) == 1) {
+				// no high neighbor corners
+				if (ttlCorner(x, y) < 2 && bblCorner(x, y) < 2)
+					return 0x18;
+				// high neighbor corner on top
+				if (ttlCorner(x, y) == 2 && bblCorner(x, y) < 2)
+					return 0x6F;
+				// high neighbor corner on bottom
+				if (ttlCorner(x, y) < 2 && bblCorner(x, y) == 2)
+					return 0x70;
+				// both neighbor corners high
+				if (ttlCorner(x, y) == 2 && bblCorner(x, y) == 2)
+					return (magic(x, y) & 0x01) ? 0xA4 : 0x71;
+			}
+
+			// Three corner cases
+
+			// Three corner cases
+
+			// 0 1         1 1           0 0 0       0 0 0
+			// 0 1 1 0x77  0 1 1 0x76    0 1 1 0x7A  0 1 1 0x78
+			// 0 0 0       0 0 0         0 1         1 1
+			//
+			// 0 1         1 1           0 0 1       0 0 1
+			// 0 1 1 0x75  0 1 1 0x13    0 1 1 0x79  0 1 1 0x14
+			// 0 0 1       0 0 1         0 1         1 1
+			//
+			//
+			// 0 0 0       1 0 0           1 0         1 1
+			// 1 1 0 0x7D  1 1 0 0x7B    1 1 0 0x80  1 1 0 0x7E
+			//   1 0         1 0         0 0 0       0 0 0
+			//
+			// 0 0 0       1 0 0           1 0         1 1
+			// 1 1 0 0x7C  1 1 0 0x15    1 1 0 0x7F  1 1 0 0x12
+			//   1 1         1 1         1 0 0       1 0 0
+
+			// corner in upper left
+			if (blCorner(x, y) == 2 && tlCorner(x, y) == 2 && trCorner(x, y) == 2) {
+				bool BLDiag = (bllCorner(x, y) > 1 && bblCorner(x, y) < 2);
+				bool TRDiag = (ttrCorner(x, y) > 1 && trrCorner(x, y) < 2);
+
+				if (!BLDiag && !TRDiag)
+					return 0x7A;
+				else if (!BLDiag && TRDiag)
+					return 0x79;
+				else if (BLDiag && !TRDiag)
+					return 0x78;
+				else
+					return 0x14;
+			}
+
+			// corner in upper right
+			if (tlCorner(x, y) == 2 && trCorner(x, y) == 2 && brCorner(x, y) == 2) {
+				bool TLDiag = ((ttlCorner(x, y) > 1) && (tllCorner(x, y) < 2));
+				bool BRDiag = ((brrCorner(x, y) > 1) && (bbrCorner(x, y) < 2));
+
+				if (!TLDiag && !BRDiag)
+					return 0x7D;
+				else if (!TLDiag && BRDiag)
+					return 0x7C;
+				else if (TLDiag && !BRDiag)
+					return 0x7B;
+				else
+					return 0x15;
+			}
+
+			// corner in bottom right
+			if (trCorner(x, y) == 2 && brCorner(x, y) == 2 && blCorner(x, y) == 2) {
+				bool TRDiag = (trrCorner(x, y) > 1 && ttrCorner(x, y) < 2);
+				bool BLDiag = (bblCorner(x, y) > 1 && bllCorner(x, y) < 2);
+
+				if (!TRDiag && !BLDiag)
+					return 0x80;
+				else if (!TRDiag && BLDiag)
+					return 0x7F;
+				else if (TRDiag && !BLDiag)
+					return 0x7E;
+				else
+					return 0x12;
+			}
+
+			// corner in bottom left
+			if (brCorner(x, y) == 2 && blCorner(x, y) == 2 && tlCorner(x, y) == 2) {
+				bool TLDiag = (tllCorner(x, y) > 1 && ttlCorner(x, y) < 2);
+				bool BRDiag = (bbrCorner(x, y) > 1 && brrCorner(x, y) < 2);
+
+				if (!TLDiag && !BRDiag)
+					return 0x77;
+				else if (!TLDiag && BRDiag)
+					return 0x75;
+				else if (TLDiag && !BRDiag)
+					return 0x76;
+				else
+					return 0x13;
+			}
+
+			// Opposing corner cases
+			if (tlCorner(x, y) == 2 && brCorner(x, y) == 2) {
+				// There are four cases, big big, big small, small big, small small
+
+				// big big
+				if (tllCorner(x, y) == 2 && ttlCorner(x, y) == 2 && brrCorner(x, y) == 2 && bbrCorner(x, y) == 2)
+					return 0x4F;
+				// big small
+				if (tllCorner(x, y) == 2 && ttlCorner(x, y) == 2)
+					return 0x8A;
+				// small big
+				if (brrCorner(x, y) == 2 && bbrCorner(x, y) == 2)
+					return 0x8B;
+				// small small
+				return 0x8D;
+			}
+			if (trCorner(x, y) == 2 && blCorner(x, y) == 2) {
+				// There are four cases, big big, big small, small big, small small
+
+				// big big
+				if (trrCorner(x, y) == 2 && ttrCorner(x, y) == 2 && bllCorner(x, y) == 2 && bblCorner(x, y) == 2)
+					return 0x50;
+				// big small
+				if (trrCorner(x, y) == 2 && ttrCorner(x, y) == 2)
+					return 0x8E;
+				// small big
+				if (bllCorner(x, y) == 2 && bblCorner(x, y) == 2)
+					return 0x90;
+				// small small
+				return 0x91;
+			}
+		}
+
+		error("illegal corner height arrangement (%d, %d)", x, y);
+	} else if ('W' == ch) {
+		// Check to make sure that we're on ground level
+		if (tlCorner(x, y) > 0 || trCorner(x, y) > 0 || blCorner(x, y) > 0 || brCorner(x, y) > 0)
+			error("water must be on a flat tile (%d, %d)", x, y);
+
+		index = (('W' != tlCenter(x, y)) << 7) |
+				(('W' != tCenter(x, y)) << 6) |
+				(('W' != trCenter(x, y)) << 5) |
+				(('W' != lCenter(x, y)) << 4) |
+				(('W' != rCenter(x, y)) << 3) |
+				(('W' != blCenter(x, y)) << 2) |
+				(('W' != bCenter(x, y)) << 1) |
+				('W' != brCenter(x, y));
+
+		uint16 nWaterTile = waterTileMap[index];
+
+		if (0x44 == nWaterTile) {
+			uint16 aWaterBlanks[] = {0x45, 0x46, 0x44, 0x47};
+
+			nWaterTile = aWaterBlanks[magic(x, y)];
+		}
+
+		return nWaterTile;
+	} else
+		error("illegal tile character (%d, %d)", x, y);
+
+	error("unknown tile find error (%d, %d)", x, y);
+}
+
+} // End of namespace Scumm
diff --git a/engines/scumm/he/moonbase/map_mif.h b/engines/scumm/he/moonbase/map_mif.h
new file mode 100644
index 00000000000..204f536467d
--- /dev/null
+++ b/engines/scumm/he/moonbase/map_mif.h
@@ -0,0 +1,198 @@
+/* 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 SCUMM_HE_MOONBASE_MAP_MIF
+#define SCUMM_HE_MOONBASE_MAP_MIF
+
+#ifdef ENABLE_HE
+
+#include "config.h"
+
+namespace Scumm {
+
+#define MAX_TILE_COUNT 80
+
+#include <common/pack-start.h>	// START STRUCT PACKING
+
+typedef struct PixelLoc {
+	uint16 x;
+	uint16 y;
+} PixelLoc;
+
+typedef struct EnergyPoolLoc {
+	PixelLoc location;
+	PixelLoc dummy;
+} EnergyPoolLoc;
+
+
+struct MapFile {
+	// Header:
+	uint16 headerDummy;
+	uint16 terrainDimX;
+	uint16 terrainDimY;
+	uint16 mapType;
+	uint16 numEnergyPools;
+
+	uint16 terrainStates[80][161];
+	uint8 space1[230];
+	char name[17];
+	uint8 space2[25837];
+	EnergyPoolLoc poolLocs[49];
+	PixelLoc lastPool;
+	uint16 dummy;
+	PixelLoc fourPlayerPoints[4];  // 2^0
+	PixelLoc threePlayerPoints[3]; // 2^1
+	PixelLoc twoPlayerPoints[2];   // 2^2
+	PixelLoc twoVTwoPoints[4];     // 2^3
+	PixelLoc oneVThreePoints[4];   // 2^4
+	PixelLoc oneVTwoPoints[3];     // 2^5
+
+	MapFile() {
+		memset(this, 0, sizeof(MapFile));
+
+		mapType = 1;
+		memset((void *)fourPlayerPoints, 0xFF, sizeof(PixelLoc) * 20);
+	}
+} PACKED_STRUCT;
+
+#include <common/pack-end.h>	// END STRUCT PACKING
+
+class MIF {
+public:
+	MIF();
+
+	void generateMap(MapFile *map);
+
+	int dimension; // 32 (small), 40 (medium), 48 (large), 56 (huge), 64 (SAI)
+	int mapType;
+	char name[17];
+	byte cornerMap[MAX_TILE_COUNT][MAX_TILE_COUNT];
+	char centerMap[MAX_TILE_COUNT][MAX_TILE_COUNT];
+private:
+
+	void defineStartLocations(MapFile *map);
+	void defineEnergyPools(MapFile *map);
+	void makeCraters(MapFile *map);
+	uint16 findTileFor(int x, int y);
+
+	inline char tlCenter(int x, int y) const {
+		return centerMap[(0 == x) ? dimension - 1 : x - 1][(0 == y) ? dimension - 1 : y - 1];
+	}
+
+	inline char tCenter(int x, int y) const {
+		return centerMap[x][(0 == y) ? dimension - 1 : y - 1];
+	}
+
+	inline char trCenter(int x, int y) const {
+		return centerMap[(x + 1) % dimension][(0 == y) ? dimension - 1 : y - 1];
+	}
+
+	inline char lCenter(int x, int y) const {
+		return centerMap[(0 == x) ? dimension - 1 : x - 1][y];
+	}
+
+	inline char rCenter(int x, int y) const {
+		return centerMap[(x + 1) % dimension][y];
+	}
+
+	inline char blCenter(int x, int y) const {
+		return centerMap[(0 == x) ? dimension - 1 : x - 1][(y + 1) % dimension];
+	}
+
+	inline char bCenter(int x, int y) const {
+		return centerMap[x][(y + 1) % dimension];
+	}
+
+	inline char brCenter(int x, int y) const {
+		return centerMap[(x + 1) % dimension][(y + 1) % dimension];
+	}
+
+	inline byte tlCorner(int x, int y) const {
+		return cornerMap[x][y];
+	}
+
+	inline byte trCorner(int x, int y) const {
+		return cornerMap[(x + 1) % dimension][y];
+	}
+
+	inline byte blCorner(int x, int y) const {
+		return cornerMap[x][(y + 1) % dimension];
+	}
+
+	inline byte brCorner(int x, int y) const {
+		return cornerMap[(x + 1) % dimension][(y + 1) % dimension];
+	}
+
+	inline byte ttllCorner(int x, int y) const {
+		return tlCorner((x == 0) ? dimension - 1 : x - 1, (y == 0) ? dimension - 1: y - 1);
+	}
+
+	inline byte ttlCorner(int x, int y) const {
+		return trCorner((x == 0) ? dimension - 1 : x - 1, (y == 0) ? dimension - 1: y - 1);
+	}
+
+	inline byte ttrCorner(int x, int y) const {
+		return tlCorner((x + 1) % dimension, (y == 0) ? dimension - 1: y - 1);
+	}
+
+	inline byte ttrrCorner(int x, int y) const {
+		return trCorner((x + 1) % dimension, (y == 0) ? dimension - 1: y - 1);
+	}
+
+	inline byte tllCorner(int x, int y) const {
+		return tlCorner((x == 0) ? dimension - 1 : x - 1, y);
+	}
+
+	inline byte trrCorner(int x, int y) const {
+		return trCorner((x + 1) % dimension, y);
+	}
+
+	inline byte bllCorner(int x, int y) const {
+		return blCorner((x == 0) ? dimension - 1 : x - 1, y);
+	}
+
+	inline byte brrCorner(int x, int y) const {
+		return brCorner((x + 1) % dimension, y);
+	}
+
+	inline byte bbllCorner(int x, int y) const {
+		return blCorner((x == 0) ? dimension - 1 : x - 1, (y + 1) % dimension);
+	}
+
+	inline byte bblCorner(int x, int y) const {
+		return brCorner((x == 0) ? dimension - 1 : x - 1, (y + 1) % dimension);
+	}
+
+	inline byte bbrCorner(int x, int y) const {
+		return blCorner((x + 1) % dimension, (y + 1) % dimension);
+	}
+
+	inline byte bbrrCorner(int x, int y) const {
+		return brCorner((x + 1) % dimension, (y + 1) % dimension);
+	}
+
+};
+
+} // End of namespace Scumm
+
+#endif // ENABLE_HE
+
+#endif // SCUMM_HE_MOONBASE_MAP_MIF
diff --git a/engines/scumm/he/moonbase/map_spiff.cpp b/engines/scumm/he/moonbase/map_spiff.cpp
index 82fecc66411..08d81bc1c51 100644
--- a/engines/scumm/he/moonbase/map_spiff.cpp
+++ b/engines/scumm/he/moonbase/map_spiff.cpp
@@ -32,7 +32,7 @@ SpiffGenerator::SpiffGenerator(Common::RandomSource *rnd) {
 SpiffGenerator::~SpiffGenerator() {
 }
 
-void SpiffGenerator::generateMap(int water, int mapSize, int energy, int terrain) {
+MapFile *SpiffGenerator::generateMap(int water, int mapSize, int energy, int terrain) {
 	totalMapSizeG = mapSize;
 	energyAmountG = (2 + energy) * totalMapSizeG * totalMapSizeG;
 
@@ -60,11 +60,74 @@ void SpiffGenerator::generateMap(int water, int mapSize, int energy, int terrain
 	}
 
 	generate();
+
+	// Populate MIF for map data generation:
+	MIF mif = MIF();
+
+	int levelMap[MAXELEVVAL];
+	levelMap[HIGH] = 2;
+	levelMap[MEDIUM] = 1;
+	levelMap[LOW] = 0;
+
+	mif.mapType = terrain;
+	Common::sprintf_s(mif.name, "Spiff %d", _rnd->getSeed());
+
+	mif.dimension = totalMapSizeG;
+
+	int y;
+	int x;
+	char t;
+	int XOffset = _rnd->getRandomNumberRngSigned(0, totalMapSizeG-1);
+	int YOffset = _rnd->getRandomNumberRngSigned(0, totalMapSizeG-1);
+	int newX;
+	int newY;
+
+	for (y = 0, newY = YOffset; y < totalMapSizeG; ++y, ++newY) {
+		for (x = 0, newX = XOffset; x < totalMapSizeG; ++x, ++newX) {
+			if (newX == totalMapSizeG)
+				newX = 0;
+			if (newY == totalMapSizeG)
+				newY = 0;
+			mif.cornerMap[newX][newY] = levelMap[mapCorner[x][y]];
+			switch (mapMiddle[x][y]) {
+			case HUB:
+				t = -1;
+				break;
+			case SMALLPOOL:
+				t = 'S';
+				break;
+			case MEDIUMPOOL:
+				t = 'M';
+				break;
+			case LARGEPOOLBOTTOM:
+				t = 'L';
+				break;
+			case WATER:
+				t = 'W';
+				break;
+			case UNASSIGNED:
+			case LARGEPOOLTOP:
+				t = '.';
+				break;
+			default:
+				t = '?';
+			}
+			mif.centerMap[newX][newY] = t;
+		}
+	}
+
+	// Generate new map:
+	MapFile *map = new MapFile();
+	mif.generateMap(map);
+
+	return map;
 }
 
 int SpiffGenerator::pickFrom2(int a, int probA, int b, int probB) {
 	debug(3, "SpiffGenerator::pickFrom2(%d, %d, %d, %d)", a, probA, b, probB);
-	if ((int)_rnd->getRandomNumber(probB) < probA)
+	int r = _rnd->getRandomNumber(probA + probB);
+	debug(3, "  r = %d", r);
+	if (r < probA)
 		return a;
 	else
 		return b;
@@ -72,7 +135,8 @@ int SpiffGenerator::pickFrom2(int a, int probA, int b, int probB) {
 
 int SpiffGenerator::pickFrom3(int a, int probA, int b, int probB, int c, int probC) {
 	debug(3, "SpiffGenerator::pickFrom3(%d, %d, %d, %d, %d, %d)", a, probA, b, probB, c, probC);
-	int r = _rnd->getRandomNumber(probC);
+	int r = _rnd->getRandomNumber(probA + probB + probC);
+	debug(3, "  r = %d", r);
 	if (r < probA)
 		return a;
 	else if (r < probA + probB)
@@ -83,7 +147,8 @@ int SpiffGenerator::pickFrom3(int a, int probA, int b, int probB, int c, int pro
 
 int SpiffGenerator::pickFrom4(int a, int probA, int b, int probB, int c, int probC, int d, int probD) {
 	debug(3, "SpiffGenerator::pickFrom4(%d, %d, %d, %d, %d, %d, %d, %d)", a, probA, b, probB, c, probC, d, probD);
-	int r = _rnd->getRandomNumber(probD);
+	int r = _rnd->getRandomNumber(probA + probB + probC + probD);
+	debug(3, "  r = %d", r);
 	if (r < probA)
 		return a;
 	else if (r < probA + probB)
@@ -348,7 +413,8 @@ void SpiffGenerator::generate() {
 	//  loop through each square
 	// --------------------------------------------------------------
 	mapCorner[0][0] = pickFrom3(LOW, 1, MEDIUM, (terrainSeedFlagG < 9), HIGH, (terrainSeedFlagG < 8)); // seed
-	for (y = 0; y <= mapCornerMaxG; ++y) {                                                             // fill in the rest of the random map
+	// fill in the rest of the random map
+	for (y = 0; y <= mapCornerMaxG; ++y) {
 		for (x = 0; x <= mapCornerMaxG; ++x) {
 			special = mapMiddle[x][y]; // water wouldn't have been assigned yet, so must be pool, start, or UNASSIGNED
 
@@ -403,6 +469,8 @@ void SpiffGenerator::generate() {
 				static int lowAmt = 105 + 3 * waterAmountG;
 				static int waterAmt = 15 * waterAmountG;
 
+
+
 				if (neighbors[LOW]) {
 					if (neighbors[HIGH]) { // HIGH with LOW or WATER
 						nextElevation = MEDIUM;
@@ -463,63 +531,63 @@ void SpiffGenerator::generate() {
 					mapCorner[x][y + 1] = tempElevation;
 				}
 			}
+		}
+	}
 
-			if (islandsFlagG) { // replace borders with water, errorCorrection() finishes it.
-				int edgeWaterA = (int)(islandsFlagG * totalMapSizeG / 16 + 0.5);
-				int edgeWaterB = mapMiddleMaxG - (int)(islandsFlagG * totalMapSizeG / 16);
-				for (y = 0; y <= mapCornerMaxG; ++y) {
-					for (x = 0; x < edgeWaterA; ++x) {
-						mapCorner[x][y] = LOW;
-						mapMiddle[x][y] = WATER;
-					}
-					if (mapCorner[edgeWaterA + 1][y] == HIGH)
-						mapCorner[edgeWaterA][y] = MEDIUM;
+	if (islandsFlagG) { // replace borders with water, errorCorrection() finishes it.
+		int edgeWaterA = (int)(islandsFlagG * totalMapSizeG / 16 + 0.5);
+		int edgeWaterB = mapMiddleMaxG - (int)(islandsFlagG * totalMapSizeG / 16);
+		for (y = 0; y <= mapCornerMaxG; ++y) {
+			for (x = 0; x < edgeWaterA; ++x) {
+				mapCorner[x][y] = LOW;
+				mapMiddle[x][y] = WATER;
+			}
+			if (mapCorner[edgeWaterA + 1][y] == HIGH)
+				mapCorner[edgeWaterA][y] = MEDIUM;
 
-					for (x = mapMiddleMaxG; x > edgeWaterB; --x) {
-						mapCorner[x + 1][y] = LOW;
-						mapMiddle[x][y] = WATER;
-					}
-					if (mapCorner[edgeWaterB][y] == HIGH) {
-						mapCorner[edgeWaterB + 1][y] = MEDIUM;
-					}
-				}
+			for (x = mapMiddleMaxG; x > edgeWaterB; --x) {
+				mapCorner[x + 1][y] = LOW;
+				mapMiddle[x][y] = WATER;
+			}
+			if (mapCorner[edgeWaterB][y] == HIGH) {
+				mapCorner[edgeWaterB + 1][y] = MEDIUM;
+			}
+		}
 
-				for (x = edgeWaterA; x <= edgeWaterB + 1; ++x) {
-					for (y = 0; y < edgeWaterA; ++y) {
-						mapCorner[x][y] = LOW;
-						mapMiddle[x][y] = WATER;
-					}
-					if (mapCorner[x][edgeWaterA + 1] == HIGH)
-						mapCorner[x][edgeWaterA] = MEDIUM;
+		for (x = edgeWaterA; x <= edgeWaterB + 1; ++x) {
+			for (y = 0; y < edgeWaterA; ++y) {
+				mapCorner[x][y] = LOW;
+				mapMiddle[x][y] = WATER;
+			}
+			if (mapCorner[x][edgeWaterA + 1] == HIGH)
+				mapCorner[x][edgeWaterA] = MEDIUM;
 
-					for (y = mapMiddleMaxG; y > edgeWaterB; --y) {
-						mapCorner[x][y + 1] = LOW;
-						mapMiddle[x][y] = WATER;
-					}
-					if (mapCorner[x][edgeWaterB] == HIGH) {
-						mapCorner[x][edgeWaterB + 1] = MEDIUM;
-					}
-				}
+			for (y = mapMiddleMaxG; y > edgeWaterB; --y) {
+				mapCorner[x][y + 1] = LOW;
+				mapMiddle[x][y] = WATER;
+			}
+			if (mapCorner[x][edgeWaterB] == HIGH) {
+				mapCorner[x][edgeWaterB + 1] = MEDIUM;
+			}
+		}
 
-				if (islandsFlagG == 2) { // add tiny islands to help bridge wide channels
-					int j;
-					for (int i = 0; i < totalMapSizeG / 16; ++i) {
-						x = (int)(totalMapSizeG / 16 - .5);
-						y = _rnd->getRandomNumberRngSigned(x, totalMapSizeG / 2 - 1 - x);
-						if (_rnd->getRandomBit()) {
-							x = totalMapSizeG / 2 - 1 - x;
-						}
-						if (_rnd->getRandomBit()) {
-							mapMiddle[x][y] = UNASSIGNED;
-							for (j = 0; j < 4; ++j) {
-								mapMiddle[x + _rnd->getRandomNumberRngSigned(-1, 1)][y + _rnd->getRandomNumberRngSigned(-1, 1)] = UNASSIGNED;
-							}
-						} else {
-							mapMiddle[y][x] = UNASSIGNED;
-							for (j = 0; j < 4; ++j) {
-								mapMiddle[y + _rnd->getRandomNumberRngSigned(-1, 1)][x + _rnd->getRandomNumberRngSigned(-1, 1)] = UNASSIGNED;
-							}
-						}
+		if (islandsFlagG == 2) { // add tiny islands to help bridge wide channels
+			int j;
+			for (int i = 0; i < totalMapSizeG / 16; ++i) {
+				x = (int)(totalMapSizeG / 16 - .5);
+				y = _rnd->getRandomNumberRngSigned(x, totalMapSizeG / 2 - 1 - x);
+				if (_rnd->getRandomBit()) {
+					x = totalMapSizeG / 2 - 1 - x;
+				}
+				if (_rnd->getRandomBit()) {
+					mapMiddle[x][y] = UNASSIGNED;
+					for (j = 0; j < 4; ++j) {
+						mapMiddle[x + _rnd->getRandomNumberRngSigned(-1, 1)][y + _rnd->getRandomNumberRngSigned(-1, 1)] = UNASSIGNED;
+					}
+				} else {
+					mapMiddle[y][x] = UNASSIGNED;
+					for (j = 0; j < 4; ++j) {
+						mapMiddle[y + _rnd->getRandomNumberRngSigned(-1, 1)][x + _rnd->getRandomNumberRngSigned(-1, 1)] = UNASSIGNED;
 					}
 				}
 			}
diff --git a/engines/scumm/he/moonbase/map_spiff.h b/engines/scumm/he/moonbase/map_spiff.h
index 47e88104803..55670eb115c 100644
--- a/engines/scumm/he/moonbase/map_spiff.h
+++ b/engines/scumm/he/moonbase/map_spiff.h
@@ -26,6 +26,8 @@
 
 #include "common/random.h"
 
+#include "engines/scumm/he/moonbase/map_mif.h"
+
 #define MAXELEVVAL 4 // for array size
 #define HIGH 3 // elevations
 #define MEDIUM 2
@@ -54,7 +56,7 @@ public:
 	SpiffGenerator(Common::RandomSource *rnd);
 	~SpiffGenerator();
 
-	void generateMap(int water, int mapSize, int energy, int terrain);
+	MapFile *generateMap(int water, int mapSize, int energy, int terrain);
 
 private:
 	Common::RandomSource *_rnd;
diff --git a/engines/scumm/module.mk b/engines/scumm/module.mk
index 593d3a974b6..ee893c37bc4 100644
--- a/engines/scumm/module.mk
+++ b/engines/scumm/module.mk
@@ -175,8 +175,9 @@ MODULE_OBJS += \
 	he/moonbase/ai_tree.o \
 	he/moonbase/ai_types.o \
 	he/moonbase/ai_weapon.o \
-	he/moonbase/map_spiff.o \
 	he/moonbase/map_main.o \
+	he/moonbase/map_mif.o \
+	he/moonbase/map_spiff.o \
 	he/moonbase/moonbase.o \
 	he/moonbase/moonbase_fow.o \
 	he/moonbase/moonbase_gfx.o


Commit: 31f57b7dc114162ea0821b5d1e75913599c9e9a5
    https://github.com/scummvm/scummvm/commit/31f57b7dc114162ea0821b5d1e75913599c9e9a5
Author: Little Cat (toontownlittlecat at gmail.com)
Date: 2024-05-12T15:08:27+02:00

Commit Message:
SCUMM HE: Fix compile error on Windows.

Changed paths:
    engines/scumm/he/moonbase/map_mif.h


diff --git a/engines/scumm/he/moonbase/map_mif.h b/engines/scumm/he/moonbase/map_mif.h
index 204f536467d..c28aa5f6910 100644
--- a/engines/scumm/he/moonbase/map_mif.h
+++ b/engines/scumm/he/moonbase/map_mif.h
@@ -24,7 +24,7 @@
 
 #ifdef ENABLE_HE
 
-#include "config.h"
+#include "scumm/he/intern_he.h"
 
 namespace Scumm {
 


Commit: bcecb72c218a6cb7f88819ee4c7452b8e7163098
    https://github.com/scummvm/scummvm/commit/bcecb72c218a6cb7f88819ee4c7452b8e7163098
Author: Little Cat (toontownlittlecat at gmail.com)
Date: 2024-05-12T15:08:27+02:00

Commit Message:
SCUMM HE: Remove debug mapSize.

Changed paths:
    engines/scumm/he/moonbase/map_main.cpp


diff --git a/engines/scumm/he/moonbase/map_main.cpp b/engines/scumm/he/moonbase/map_main.cpp
index 6342721f52c..2720679b744 100644
--- a/engines/scumm/he/moonbase/map_main.cpp
+++ b/engines/scumm/he/moonbase/map_main.cpp
@@ -58,7 +58,6 @@ bool Map::generateNewMap() {
 
 	// Don't randomly pick nonstandard map sizes.
 	int mapSize = _rnd.getRandomNumberRngSigned(4, 8) * 8;
-	mapSize = 4 * 8;
 
 	int tileSet = _rnd.getRandomNumberRngSigned(1, 7);
 


Commit: fbf837b91ec7d5bf86e9f206232e863d4ea4ced3
    https://github.com/scummvm/scummvm/commit/fbf837b91ec7d5bf86e9f206232e863d4ea4ced3
Author: Little Cat (toontownlittlecat at gmail.com)
Date: 2024-05-12T15:08:27+02:00

Commit Message:
SCUMM HE: Use float based random generation.

Changed paths:
    engines/scumm/he/moonbase/map_spiff.cpp
    engines/scumm/he/moonbase/map_spiff.h


diff --git a/engines/scumm/he/moonbase/map_spiff.cpp b/engines/scumm/he/moonbase/map_spiff.cpp
index 08d81bc1c51..91e690a82d1 100644
--- a/engines/scumm/he/moonbase/map_spiff.cpp
+++ b/engines/scumm/he/moonbase/map_spiff.cpp
@@ -54,7 +54,7 @@ MapFile *SpiffGenerator::generateMap(int water, int mapSize, int energy, int ter
 	if (n < 1) {
 		n = 1;
 	}
-	numPoolsG = _rnd->getRandomNumberRngSigned((int)(energyAmountG / 4000) + 1, n);
+	numPoolsG = spiffRand((int)(energyAmountG / 4000) + 1, n);
 	if (numPoolsG > 12) {
 		numPoolsG = 12;
 	}
@@ -77,8 +77,8 @@ MapFile *SpiffGenerator::generateMap(int water, int mapSize, int energy, int ter
 	int y;
 	int x;
 	char t;
-	int XOffset = _rnd->getRandomNumberRngSigned(0, totalMapSizeG-1);
-	int YOffset = _rnd->getRandomNumberRngSigned(0, totalMapSizeG-1);
+	int XOffset = spiffRand(0, totalMapSizeG-1);
+	int YOffset = spiffRand(0, totalMapSizeG-1);
 	int newX;
 	int newY;
 
@@ -123,10 +123,21 @@ MapFile *SpiffGenerator::generateMap(int water, int mapSize, int energy, int ter
 	return map;
 }
 
+float SpiffGenerator::getRandomFloat() {
+	// On Windows, RAND_MAX is 32767.  So we're
+	// doing this to match.
+	return (float)_rnd->getRandomNumber(32767) / 32767;
+}
+
+int SpiffGenerator::spiffRand(int min, int max) {
+	// returns a random integer min to max inclusive
+	return ((int)(getRandomFloat() * (max + 1 - min))) + min;
+}
+
 int SpiffGenerator::pickFrom2(int a, int probA, int b, int probB) {
 	debug(3, "SpiffGenerator::pickFrom2(%d, %d, %d, %d)", a, probA, b, probB);
-	int r = _rnd->getRandomNumber(probA + probB);
-	debug(3, "  r = %d", r);
+	float r = getRandomFloat() * (probA + probB);
+	debug(3, "  r = %f", r);
 	if (r < probA)
 		return a;
 	else
@@ -135,8 +146,8 @@ int SpiffGenerator::pickFrom2(int a, int probA, int b, int probB) {
 
 int SpiffGenerator::pickFrom3(int a, int probA, int b, int probB, int c, int probC) {
 	debug(3, "SpiffGenerator::pickFrom3(%d, %d, %d, %d, %d, %d)", a, probA, b, probB, c, probC);
-	int r = _rnd->getRandomNumber(probA + probB + probC);
-	debug(3, "  r = %d", r);
+	float r = getRandomFloat() * (probA + probB + probC);
+	debug(3, "  r = %f", r);
 	if (r < probA)
 		return a;
 	else if (r < probA + probB)
@@ -147,8 +158,8 @@ int SpiffGenerator::pickFrom3(int a, int probA, int b, int probB, int c, int pro
 
 int SpiffGenerator::pickFrom4(int a, int probA, int b, int probB, int c, int probC, int d, int probD) {
 	debug(3, "SpiffGenerator::pickFrom4(%d, %d, %d, %d, %d, %d, %d, %d)", a, probA, b, probB, c, probC, d, probD);
-	int r = _rnd->getRandomNumber(probA + probB + probC + probD);
-	debug(3, "  r = %d", r);
+	float r = getRandomFloat() * (probA + probB + probC + probD);
+	debug(3, "  r = %f", r);
 	if (r < probA)
 		return a;
 	else if (r < probA + probB)
@@ -175,8 +186,8 @@ void SpiffGenerator::getSpecials() {
 	mapMiddle[x][y] = HUB; // hub start position
 
 	for (p = 1; p <= numPoolsG; ++p) {
-		x = _rnd->getRandomNumberRngSigned(edgeWaterA, mapMiddleMaxG - edgeWaterB);
-		y = _rnd->getRandomNumberRngSigned(edgeWaterA, mapMiddleMaxG - edgeWaterB);
+		x = spiffRand(edgeWaterA, mapMiddleMaxG - edgeWaterB);
+		y = spiffRand(edgeWaterA, mapMiddleMaxG - edgeWaterB);
 		if (mapMiddle[x][y] != UNASSIGNED)
 			--p; // repick this pool
 		else {
@@ -575,19 +586,19 @@ void SpiffGenerator::generate() {
 			int j;
 			for (int i = 0; i < totalMapSizeG / 16; ++i) {
 				x = (int)(totalMapSizeG / 16 - .5);
-				y = _rnd->getRandomNumberRngSigned(x, totalMapSizeG / 2 - 1 - x);
-				if (_rnd->getRandomBit()) {
+				y = spiffRand(x, totalMapSizeG / 2 - 1 - x);
+				if (spiffRand(0, 1)) {
 					x = totalMapSizeG / 2 - 1 - x;
 				}
-				if (_rnd->getRandomBit()) {
+				if (spiffRand(0, 1)) {
 					mapMiddle[x][y] = UNASSIGNED;
 					for (j = 0; j < 4; ++j) {
-						mapMiddle[x + _rnd->getRandomNumberRngSigned(-1, 1)][y + _rnd->getRandomNumberRngSigned(-1, 1)] = UNASSIGNED;
+						mapMiddle[x + spiffRand(-1, 1)][y + spiffRand(-1, 1)] = UNASSIGNED;
 					}
 				} else {
 					mapMiddle[y][x] = UNASSIGNED;
 					for (j = 0; j < 4; ++j) {
-						mapMiddle[y + _rnd->getRandomNumberRngSigned(-1, 1)][x + _rnd->getRandomNumberRngSigned(-1, 1)] = UNASSIGNED;
+						mapMiddle[y + spiffRand(-1, 1)][x + spiffRand(-1, 1)] = UNASSIGNED;
 					}
 				}
 			}
diff --git a/engines/scumm/he/moonbase/map_spiff.h b/engines/scumm/he/moonbase/map_spiff.h
index 55670eb115c..f61f72ce363 100644
--- a/engines/scumm/he/moonbase/map_spiff.h
+++ b/engines/scumm/he/moonbase/map_spiff.h
@@ -77,6 +77,8 @@ private:
 	int mapCorner[MAXSIZE+1][MAXSIZE+1];
 	int mapMiddle[MAXSIZE][MAXSIZE];
 
+	float getRandomFloat();
+	int spiffRand(int min, int max);
 	int pickFrom2(int a, int probA, int b, int probB);
 	int pickFrom3(int a, int probA, int b, int probB, int c, int probC);
 	int pickFrom4(int a, int probA, int b, int probB, int c, int probC, int d, int probD);


Commit: 15e9ae85e5bc40b30587077cdbffa8ac8789cd90
    https://github.com/scummvm/scummvm/commit/15e9ae85e5bc40b30587077cdbffa8ac8789cd90
Author: Little Cat (toontownlittlecat at gmail.com)
Date: 2024-05-12T15:08:27+02:00

Commit Message:
SCUMM HE: Use MSVCRT's RNG algorithm.

Maps are now finally starting to match.

Changed paths:
    engines/scumm/he/moonbase/map_main.cpp
    engines/scumm/he/moonbase/map_main.h
    engines/scumm/he/moonbase/map_spiff.cpp
    engines/scumm/he/moonbase/map_spiff.h


diff --git a/engines/scumm/he/moonbase/map_main.cpp b/engines/scumm/he/moonbase/map_main.cpp
index 2720679b744..02c4518bf9d 100644
--- a/engines/scumm/he/moonbase/map_main.cpp
+++ b/engines/scumm/he/moonbase/map_main.cpp
@@ -66,26 +66,25 @@ bool Map::generateNewMap() {
 	int terrain = _rnd.getRandomNumberRngSigned(2, 4);
 	int water = _rnd.getRandomNumberRngSigned(2, 4);
 
-	return generateMapWithInfo(SPIFF_GEN, 0, mapSize, tileSet, energy, terrain, water);
+	// 32767 is RAND_MAX on Windows
+	int seed = _rnd.getRandomNumber(32767);
+
+	return generateMapWithInfo(SPIFF_GEN, seed, mapSize, tileSet, energy, terrain, water);
 }
 
-bool Map::generateMapWithInfo(uint8 generator, uint32 seed, int mapSize, int tileset, int energy, int terrain, int water) {
+bool Map::generateMapWithInfo(uint8 generator, int seed, int mapSize, int tileset, int energy, int terrain, int water) {
 	if (_generatedMap) {
 		// Delete old map.
 		delete _generatedMap;
 	}
 
-	if (seed) {
-		_rnd.setSeed(seed);
-	} else {
-		_rnd.generateNewSeed();
-	}
+	_seed = seed;
 
 	debug(1, "Map: Generating new map with info: generator = %d, seed = %d, mapSize = %d, tileset = %d , energy = %d, terrain = %d, water = %d.", generator, getSeed(), mapSize, tileset, energy, terrain, water);
 	switch (generator) {
 	case SPIFF_GEN:
 	{
-		SpiffGenerator spiff = SpiffGenerator(&_rnd);
+		SpiffGenerator spiff = SpiffGenerator(seed);
 		_generatedMap = spiff.generateMap(water, mapSize, energy, terrain);
 		break;
 	}
diff --git a/engines/scumm/he/moonbase/map_main.h b/engines/scumm/he/moonbase/map_main.h
index 47a005d0cd4..861f268aecf 100644
--- a/engines/scumm/he/moonbase/map_main.h
+++ b/engines/scumm/he/moonbase/map_main.h
@@ -40,11 +40,11 @@ public:
 	~Map();
 
 	bool generateNewMap();
-	bool generateMapWithInfo(uint8 generator, uint32 seed, int mapSize, int tileset, int energy, int terrain, int water);
+	bool generateMapWithInfo(uint8 generator, int seed, int mapSize, int tileset, int energy, int terrain, int water);
 	Common::SeekableReadStream *substituteFile(const byte *fileName);
 
 	uint32 getSeed() const {
-		return _rnd.getSeed();
+		return _seed;
 	}
 
 private:
@@ -55,6 +55,8 @@ private:
 	// they're playing on the same generated map.
 	Common::RandomSource _rnd;
 
+	int _seed;
+
 	bool _mapGenerated;
 	MapFile *_generatedMap;
 
diff --git a/engines/scumm/he/moonbase/map_spiff.cpp b/engines/scumm/he/moonbase/map_spiff.cpp
index 91e690a82d1..7ecd716ad2b 100644
--- a/engines/scumm/he/moonbase/map_spiff.cpp
+++ b/engines/scumm/he/moonbase/map_spiff.cpp
@@ -25,8 +25,8 @@
 
 namespace Scumm {
 
-SpiffGenerator::SpiffGenerator(Common::RandomSource *rnd) {
-	_rnd = rnd;
+SpiffGenerator::SpiffGenerator(int seed) {
+	_seed = seed;
 }
 
 SpiffGenerator::~SpiffGenerator() {
@@ -70,7 +70,7 @@ MapFile *SpiffGenerator::generateMap(int water, int mapSize, int energy, int ter
 	levelMap[LOW] = 0;
 
 	mif.mapType = terrain;
-	Common::sprintf_s(mif.name, "Spiff %d", _rnd->getSeed());
+	Common::sprintf_s(mif.name, "Spiff %04X", _seed);
 
 	mif.dimension = totalMapSizeG;
 
@@ -124,9 +124,16 @@ MapFile *SpiffGenerator::generateMap(int water, int mapSize, int energy, int ter
 }
 
 float SpiffGenerator::getRandomFloat() {
-	// On Windows, RAND_MAX is 32767.  So we're
-	// doing this to match.
-	return (float)_rnd->getRandomNumber(32767) / 32767;
+	// This is the exact linear congruential generator
+	// algorithm used on MSVCRT (Windows Visual C++ Runtime), with
+	// RAND_MAX being 0x7fff (32767).  This is implemented here
+	// to match the RNG between the original Moonbase Console
+	// program and ScummVM.
+	//
+	// (Common::RandomSource uses Xorshift and uses unsigned
+	// integers compared to MSVCRT's rand)
+	_seed = _seed * 214013 + 2531011;
+	return (float)((_seed >> 16) & 0x7fff) / 32767;
 }
 
 int SpiffGenerator::spiffRand(int min, int max) {
diff --git a/engines/scumm/he/moonbase/map_spiff.h b/engines/scumm/he/moonbase/map_spiff.h
index f61f72ce363..28d55c6c22f 100644
--- a/engines/scumm/he/moonbase/map_spiff.h
+++ b/engines/scumm/he/moonbase/map_spiff.h
@@ -53,13 +53,13 @@ namespace Scumm {
 
 class SpiffGenerator {
 public:
-	SpiffGenerator(Common::RandomSource *rnd);
+	SpiffGenerator(int seed);
 	~SpiffGenerator();
 
 	MapFile *generateMap(int water, int mapSize, int energy, int terrain);
 
 private:
-	Common::RandomSource *_rnd;
+	int _seed;
 
 	int numPoolsG; // per quadrant
 	int energyAmountG; // 2048 = min energy on small map, 51200 = max energy on max map, etc.


Commit: 8879b9c8dd9869a54abcd7360c2796bf5de55093
    https://github.com/scummvm/scummvm/commit/8879b9c8dd9869a54abcd7360c2796bf5de55093
Author: Michael Barlow (michaelbarlow7 at gmail.com)
Date: 2024-05-12T15:08:27+02:00

Commit Message:
SCUMM HE: Correct value now being used for tileSet

The code was using the "terrain" variable instead of the "tileSet" variable
to determine the tileSet. This is now fixed.

Changed paths:
    engines/scumm/he/moonbase/map_main.cpp
    engines/scumm/he/moonbase/map_spiff.cpp
    engines/scumm/he/moonbase/map_spiff.h


diff --git a/engines/scumm/he/moonbase/map_main.cpp b/engines/scumm/he/moonbase/map_main.cpp
index 02c4518bf9d..32a82ff0ebf 100644
--- a/engines/scumm/he/moonbase/map_main.cpp
+++ b/engines/scumm/he/moonbase/map_main.cpp
@@ -85,7 +85,7 @@ bool Map::generateMapWithInfo(uint8 generator, int seed, int mapSize, int tilese
 	case SPIFF_GEN:
 	{
 		SpiffGenerator spiff = SpiffGenerator(seed);
-		_generatedMap = spiff.generateMap(water, mapSize, energy, terrain);
+		_generatedMap = spiff.generateMap(water, tileset, mapSize, energy, terrain);
 		break;
 	}
 	default:
diff --git a/engines/scumm/he/moonbase/map_spiff.cpp b/engines/scumm/he/moonbase/map_spiff.cpp
index 7ecd716ad2b..c56f5f96428 100644
--- a/engines/scumm/he/moonbase/map_spiff.cpp
+++ b/engines/scumm/he/moonbase/map_spiff.cpp
@@ -32,7 +32,7 @@ SpiffGenerator::SpiffGenerator(int seed) {
 SpiffGenerator::~SpiffGenerator() {
 }
 
-MapFile *SpiffGenerator::generateMap(int water, int mapSize, int energy, int terrain) {
+MapFile *SpiffGenerator::generateMap(int water, int tileset, int mapSize, int energy, int terrain) {
 	totalMapSizeG = mapSize;
 	energyAmountG = (2 + energy) * totalMapSizeG * totalMapSizeG;
 
@@ -69,7 +69,7 @@ MapFile *SpiffGenerator::generateMap(int water, int mapSize, int energy, int ter
 	levelMap[MEDIUM] = 1;
 	levelMap[LOW] = 0;
 
-	mif.mapType = terrain;
+	mif.mapType = tileset;
 	Common::sprintf_s(mif.name, "Spiff %04X", _seed);
 
 	mif.dimension = totalMapSizeG;
diff --git a/engines/scumm/he/moonbase/map_spiff.h b/engines/scumm/he/moonbase/map_spiff.h
index 28d55c6c22f..6ac049123c4 100644
--- a/engines/scumm/he/moonbase/map_spiff.h
+++ b/engines/scumm/he/moonbase/map_spiff.h
@@ -56,7 +56,7 @@ public:
 	SpiffGenerator(int seed);
 	~SpiffGenerator();
 
-	MapFile *generateMap(int water, int mapSize, int energy, int terrain);
+	MapFile *generateMap(int water, int tileset, int mapSize, int energy, int terrain);
 
 private:
 	int _seed;


Commit: 73e87c52c6c708d41a5a30ff165d1460de29ec96
    https://github.com/scummvm/scummvm/commit/73e87c52c6c708d41a5a30ff165d1460de29ec96
Author: Little Cat (toontownlittlecat at gmail.com)
Date: 2024-05-12T15:08:27+02:00

Commit Message:
SCUMM HE: Fix the chance of invalid tileset.

Changed paths:
    engines/scumm/he/moonbase/map_main.cpp


diff --git a/engines/scumm/he/moonbase/map_main.cpp b/engines/scumm/he/moonbase/map_main.cpp
index 32a82ff0ebf..06159467b82 100644
--- a/engines/scumm/he/moonbase/map_main.cpp
+++ b/engines/scumm/he/moonbase/map_main.cpp
@@ -59,7 +59,7 @@ bool Map::generateNewMap() {
 	// Don't randomly pick nonstandard map sizes.
 	int mapSize = _rnd.getRandomNumberRngSigned(4, 8) * 8;
 
-	int tileSet = _rnd.getRandomNumberRngSigned(1, 7);
+	int tileSet = _rnd.getRandomNumberRngSigned(1, 6);
 
 	// Only use [2, 3, 4] of the legal [0, 1, 2, 3, 4, 5, 6]
 	int energy = _rnd.getRandomNumberRngSigned(2, 4);


Commit: f5f703a159b81e1c11179f183ae07db3c9ab7d62
    https://github.com/scummvm/scummvm/commit/f5f703a159b81e1c11179f183ae07db3c9ab7d62
Author: Michael Barlow (michaelbarlow7 at gmail.com)
Date: 2024-05-12T15:08:27+02:00

Commit Message:
SCUMM HE: Fixed crash when generating map

There was a formatting error in the errorCorrection() method
ran after generating the map. One of the iterating for loops was meant to be nested in the other,
but instead it ran afterwards, causing some error conditions to get missed
and causing a crash later in the program.

Changed paths:
    engines/scumm/he/moonbase/map_spiff.cpp


diff --git a/engines/scumm/he/moonbase/map_spiff.cpp b/engines/scumm/he/moonbase/map_spiff.cpp
index c56f5f96428..8be3ee31a16 100644
--- a/engines/scumm/he/moonbase/map_spiff.cpp
+++ b/engines/scumm/he/moonbase/map_spiff.cpp
@@ -344,20 +344,24 @@ void SpiffGenerator::errorCorrection() {
 			if (mapCorner[x][y] == HIGH) {
 				for (dy = -1; dy <= 1; ++dy) {
 					tempY = y + dy;
-					if (tempY == totalMapSizeG)
+					if (tempY == totalMapSizeG) {
 						tempY = 0;
-					else if (tempY == -1)
+					} else if (tempY == -1) {
 						tempY = totalMapSizeG - 1;
-				}
+					}
 
-				for (dx = -1; dx <= 1; ++dx) {
-					tempX = x + dx;
-					if (tempX == totalMapSizeG)
-						tempX = 0;
-					else if (tempX == -1)
-						tempX = totalMapSizeG - 1;
-					if (mapCorner[tempX][tempY] == LOW)
-						mapCorner[x][y] = MEDIUM;
+					for (dx = -1; dx <= 1; ++dx) {
+						tempX = x + dx;
+						if (tempX == totalMapSizeG) {
+							tempX = 0;
+						} else if (tempX == -1) {
+							tempX = totalMapSizeG - 1;
+						}
+
+						if (mapCorner[tempX][tempY] == LOW) {
+							mapCorner[x][y] = MEDIUM;
+						}
+					}
 				}
 			} else if ((mapCorner[x][y] != LOW) && (mapCorner[x][y] != MEDIUM)) {
 				mapCorner[x][y] = MEDIUM; // should not happen anymore


Commit: 77270646ed873273b673e14470bba08f7ae519cb
    https://github.com/scummvm/scummvm/commit/77270646ed873273b673e14470bba08f7ae519cb
Author: Little Cat (toontownlittlecat at gmail.com)
Date: 2024-05-12T15:08:27+02:00

Commit Message:
SCUMM HE: Remove no-longer used include.

Changed paths:
    engines/scumm/he/moonbase/map_spiff.h


diff --git a/engines/scumm/he/moonbase/map_spiff.h b/engines/scumm/he/moonbase/map_spiff.h
index 6ac049123c4..5be4c4821b3 100644
--- a/engines/scumm/he/moonbase/map_spiff.h
+++ b/engines/scumm/he/moonbase/map_spiff.h
@@ -24,8 +24,6 @@
 
 #ifdef ENABLE_HE
 
-#include "common/random.h"
-
 #include "engines/scumm/he/moonbase/map_mif.h"
 
 #define MAXELEVVAL 4 // for array size


Commit: b60bb0ec644156a8e398d38a39c2e01b76b14798
    https://github.com/scummvm/scummvm/commit/b60bb0ec644156a8e398d38a39c2e01b76b14798
Author: Little Cat (toontownlittlecat at gmail.com)
Date: 2024-05-12T15:08:27+02:00

Commit Message:
SCUMM HE: Added Katton generator.

Changed paths:
  A engines/scumm/he/moonbase/map_katton.cpp
  A engines/scumm/he/moonbase/map_katton.h
    engines/scumm/he/moonbase/map_main.cpp
    engines/scumm/module.mk


diff --git a/engines/scumm/he/moonbase/map_katton.cpp b/engines/scumm/he/moonbase/map_katton.cpp
new file mode 100644
index 00000000000..e27a815dee3
--- /dev/null
+++ b/engines/scumm/he/moonbase/map_katton.cpp
@@ -0,0 +1,780 @@
+/* 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 "scumm/he/moonbase/map_katton.h"
+
+namespace Scumm {
+
+KattonGenerator::KattonGenerator(int seed) {
+	_seed = seed;
+}
+
+KattonGenerator::~KattonGenerator() {
+}
+
+int KattonGenerator::getRandomNumber() {
+	// This is the exact linear congruential generator
+	// algorithm used on MSVCRT (Windows Visual C++ Runtime), with
+	// RAND_MAX being 0x7fff (32767).  This is implemented here
+	// to match the RNG between the original Moonbase Console
+	// program and ScummVM.
+	//
+	// (Common::RandomSource uses Xorshift and uses unsigned
+	// integers compared to MSVCRT's rand)
+	_seed = _seed * 214013 + 2531011;
+	return (_seed >> 16) & 0x7fff;
+}
+
+MapFile *KattonGenerator::generateMap(int water, int tileSet, int mapSize, int energy, int terrain) {
+	size = mapSize;
+	tileset = tileSet;
+	int inEnergy = energy;
+	int inTerrain = terrain;
+	int inWater = water;
+
+	if (!(inEnergy == 0)) {
+		inEnergy = inEnergy * 14 + plusminus(14);
+	}
+
+	if (!(inTerrain == 0)) {
+		inTerrain = inTerrain * 14 + plusminus(14);
+	}
+
+	if (!(inWater == 0)) {
+		inWater = inWater * 14 + plusminus(14);
+	}
+
+	float terrainpercent = ((float)inTerrain) / 100;
+	float waterpercent = ((float)inWater) / 100;
+
+	//****************************************Let the generation BEGIN!
+
+	fillboards(0);
+
+	// used everywhere
+	int i, j, k, l, x, y, z;
+	// used in making the basic landmass shapes
+	int numsplotches, length;
+	// used in making water
+	int numwaterplaces = 0, numwatersplotches, multiplier;
+	short int goodwater[1600][2];
+	// used in making energy
+	int maxnumclose, maxnumfar, maxnumrand, smallmed, goodplaceClose[300][2], goodplaceFar[300][2], numplaceClose, numplaceFar, placeFar[3], placeClose[2], counter, counterpools;
+
+	//****************************************Make the basic landmass shapes.
+
+	numsplotches = (int)(size / 4) + (int)((terrainpercent - 0.5) * size / 2);
+
+	for (i = 0; i < numsplotches; i++) {
+		length = (int)(((1 - waterpercent) / 6 * size * size) / numsplotches);
+		length = length + plusminus((int)(length / 2));
+		randomsplotch(length, 1 + plusminus(1), 2, getRandomNumber() % size, getRandomNumber() % size);
+	}
+
+	for (i = 0; i < (int)numsplotches / 4; i++) {
+		length = (int)(((1 - waterpercent) / 3 * size * size) / numsplotches);
+		length = length + plusminus((int)(length / 4));
+		randomsplotch(length, 1 + plusminus(1), 1, getRandomNumber() % size, getRandomNumber() % size);
+	}
+
+	for (i = 0; i < (int)numsplotches / 2; i++) {
+		length = (int)(size + plusminus((int)(size / 2)));
+		randomsplotch(length, 1 + plusminus(1), 0, getRandomNumber() % size, getRandomNumber() % size);
+	}
+
+	for (i = 0; i < (int)waterpercent * size; i++) {
+		length = (int)(size + plusminus((int)(size / 2)));
+		randomsplotch(length, 1 + plusminus(1), 0, getRandomNumber() % size, getRandomNumber() % size);
+	}
+
+	//****************************************Fatten up the landmasses
+
+	// make the highhills bigger
+	fattenall(-3, 2, NEVER_USED_NUM, TEMP_REPLACEMENT_NUMA);
+	replacenum(TEMP_REPLACEMENT_NUMA, 2);
+
+	// make the lowlands bigger, depending on wateriness
+	fattenall(-((int)(waterpercent * 3)), 0, NEVER_USED_NUM, TEMP_REPLACEMENT_NUMA);
+	replacenum(TEMP_REPLACEMENT_NUMA, 2);
+
+	// surround the high hills with at least one med
+	fattenall(2, 2, NEVER_USED_NUM, 1);
+
+	// fatten the medium hills
+	fattenall(-3, 1, 2, TEMP_REPLACEMENT_NUMA);
+	replacenum(TEMP_REPLACEMENT_NUMA, 1);
+
+	//****************************************Smooth out/rough up the landmasses
+
+	randomflip((int)(terrainpercent * terrainpercent * size * size / 4 + size / 4), inWater);
+
+	//****************************************Make the start locations
+
+	findstartloc();
+
+	//****************************************Put down some water
+
+	for (i = 0; i < size; i += 2) {
+		for (j = 0; j < size; j += 2) {
+			if (goodforwater(i, j)) {
+				goodwater[numwaterplaces][0] = i;
+				goodwater[numwaterplaces][1] = j;
+				numwaterplaces++;
+			}
+		}
+	}
+
+	numwatersplotches = (int)(size * waterpercent * waterpercent * 5);
+
+	if (numwaterplaces <= numwatersplotches) {
+		numwatersplotches = numwaterplaces;
+	}
+	if (numwatersplotches >= 1) {
+		multiplier = (int)((float)numwaterplaces / (float)numwatersplotches);
+
+		for (i = 0; i < numwatersplotches; i++) {
+			z = getRandomNumber() % multiplier + i * multiplier;
+			x = goodwater[z][0];
+			y = goodwater[z][1];
+			randomwater(size + plusminus(size / 2), getRandomNumber() % 3, x, y);
+		}
+	}
+
+	//****************************************Put down the energy
+	if (inEnergy >= 90) {
+		maxnumclose = 2;
+		maxnumfar = 3;
+		maxnumrand = (int)(size * size / 150);
+		smallmed = 2;
+	} else if (inEnergy >= 75) {
+		maxnumclose = 2;
+		maxnumfar = 1;
+		maxnumrand = (int)(size * size / 250) + 4;
+		smallmed = 3;
+	} else if (inEnergy >= 60) {
+		maxnumclose = 1;
+		maxnumfar = 2;
+		maxnumrand = (int)(size * size / 250);
+		smallmed = 4;
+	} else if (inEnergy >= 45) {
+		maxnumclose = 1;
+		maxnumfar = 1;
+		maxnumrand = (int)(size * size / 250);
+		smallmed = 6;
+	} else if (inEnergy >= 30) {
+		maxnumclose = 1;
+		maxnumfar = 0;
+		maxnumrand = (int)(size * size / 350) + 2;
+		smallmed = 8;
+	} else if (inEnergy >= 15) {
+		maxnumclose = 0;
+		maxnumfar = 1;
+		maxnumrand = (int)(size * size / 450);
+		smallmed = 10;
+	} else if (inEnergy >= 0) {
+		maxnumclose = 0;
+		maxnumfar = 0;
+		maxnumrand = 0;
+		smallmed = 1;
+	}
+
+	for (i = 0; i < 4; i++) {
+		numplaceClose = 0;
+		numplaceFar = 0;
+		for (j = 0; j < size; j++) {
+			for (k = 0; k < size; k++) {
+				if ((goodforenergy(j, k, 0)) && (distance(startloc[i][0], startloc[i][1], j, k) >= (int)(size / 10)) && (distance(startloc[i][0], startloc[i][1], j, k) <= (int)(size / 8))) {
+					goodplaceClose[numplaceClose][0] = j;
+					goodplaceClose[numplaceClose][1] = k;
+					numplaceClose++;
+				} else if ((goodforenergy(j, k, 0)) && (distance(startloc[i][0], startloc[i][1], j, k) >= (int)(size / 7)) && (distance(startloc[i][0], startloc[i][1], j, k) <= (int)(size / 5))) {
+					goodplaceFar[numplaceFar][0] = j;
+					goodplaceFar[numplaceFar][1] = k;
+					numplaceFar++;
+				}
+			}
+		}
+		if (numplaceClose >= 1) {
+			placeClose[0] = getRandomNumber() % (int)(numplaceClose / 2) + 1;
+		}
+		if (numplaceClose >= 2) {
+			placeClose[1] = getRandomNumber() % (int)(numplaceClose / 2) + (int)(numplaceClose / 2) - 1;
+		}
+
+		if (numplaceClose >= maxnumclose) {
+			for (l = 0; l < maxnumclose; l++) {
+				special[goodplaceClose[placeClose[l]][0]][goodplaceClose[placeClose[l]][1]] = 100;
+			}
+		} else {
+			for (l = 0; l < numplaceClose; l++) {
+				special[goodplaceClose[placeClose[l]][0]][goodplaceClose[placeClose[l]][1]] = 100;
+			}
+		}
+
+		if (numplaceFar >= 1) {
+			placeFar[0] = getRandomNumber() % (int)(numplaceFar / 3) + 1;
+		}
+		if (numplaceFar >= 2) {
+			placeFar[1] = getRandomNumber() % (int)(numplaceFar / 3) + (int)(numplaceClose / 3);
+		}
+		if (numplaceFar >= 3) {
+			placeFar[2] = getRandomNumber() % (int)(numplaceFar / 3) + (int)(2 * numplaceClose / 3) - 1;
+		}
+
+		if (numplaceFar >= maxnumfar) {
+			for (l = 0; l < maxnumfar; l++) {
+				special[goodplaceFar[placeFar[l]][0]][goodplaceFar[placeFar[l]][1]] = 100;
+			}
+		} else {
+			for (l = 0; l < numplaceFar; l++) {
+				special[goodplaceFar[placeFar[l]][0]][goodplaceFar[placeFar[l]][1]] = 100;
+			}
+		}
+	}
+
+	counter = 0;
+	counterpools = 4 * (maxnumfar + maxnumclose);
+	for (k = 0; k < maxnumrand && counterpools < 50; k++) {
+		do {
+			i = getRandomNumber() % size;
+			j = getRandomNumber() % size;
+			counter++;
+		} while (!((distance(i, j, startloc[0][0], startloc[0][1]) >= 10) && (distance(i, j, startloc[1][0], startloc[1][1]) >= 10) && (distance(i, j, startloc[2][0], startloc[2][1]) >= 10) && (distance(i, j, startloc[3][0], startloc[3][1]) >= 10) && (goodforenergy(i, j, 1)) && (counter < 5000)));
+		if (getRandomNumber() % smallmed == 0) {
+			special[i][j] = 200;
+			counterpools++;
+		} else {
+			special[i][j] = 100;
+			counterpools++;
+		}
+	}
+
+	//****************************************Do that saving thing that you do, BABY!
+	MIF mif = MIF();
+	Common::sprintf_s(mif.name, "Katton %04X", _seed);
+	mif.dimension = size;
+	mif.mapType = tileset;
+	for (j = 0; j < size; j++) {
+		for (i = 0; i < size; i++)
+			mif.cornerMap[i][j] = board[i][j];
+		for (i = 0; i < size; i++)
+			if (special[i][j] == 0)
+				mif.centerMap[i][j] = '.';
+			else if (special[i][j] == -1)
+				mif.centerMap[i][j] = 'W';
+			else if (special[i][j] == 100)
+				mif.centerMap[i][j] = 'S';
+			else if (special[i][j] == 200)
+				mif.centerMap[i][j] = 'M';
+			else if (special[i][j] == 300)
+				mif.centerMap[i][j] = 'L';
+			else
+				mif.centerMap[i][j] = -special[i][j];
+	}
+
+	// Generate new map:
+	MapFile *map = new MapFile();
+	mif.generateMap(map);
+
+	return map;
+}
+
+int KattonGenerator::distance(int x1, int y1, int x2, int y2) {
+	int dx, dy, disp;
+	dx = min((abs(x1 - x2)), (abs(x1 + size - x2)), (abs(x2 + size - x1)));
+	dy = min((abs(y1 - y2)), (abs(y1 + size - y2)), (abs(y2 + size - y1)));
+	disp = (int)sqrt((double)(dx * dx + dy * dy));
+	return disp;
+}
+
+int KattonGenerator::min(int a, int b, int c) {
+	if ((a <= b) && (a <= c)) {
+		return a;
+	} else if ((b < a) && (b <= c)) {
+		return b;
+	} else if ((c < a) && (c < b)) {
+		return c;
+	} else {
+		return a;
+	}
+}
+
+int KattonGenerator::goodforenergy(int x, int y, int poolsize) {
+	switch (poolsize) {
+	case 0:
+		if ((board[x][y] == board[findcoord(x, +1)][y]) && (board[findcoord(x, +1)][y] == board[x][findcoord(y, +1)]) && (board[x][findcoord(y, +1)] == board[findcoord(x, +1)][findcoord(y, +1)])) {
+			//check main map
+			if (special[x][y] == 0) { //specials are clear
+				return 1;
+			} else {
+				return 0;
+			}
+		} else {
+			return 0;
+		}
+	case 1:
+		if ((board[x][y] == board[findcoord(x, +1)][y]) && (board[findcoord(x, +1)][y] == board[x][findcoord(y, +1)]) && (board[x][findcoord(y, +1)] == board[findcoord(x, +1)][findcoord(y, +1)])) { //check main map
+			if ((special[x][y] == 0) && (special[findcoord(x, +1)][y] == 0) && (special[x][findcoord(y, +1)] == 0) && (special[findcoord(x, +1)][findcoord(y, +1)] == 0)) {                           //specials are clear
+				return 1;
+			} else {
+				return 0;
+			}
+		} else {
+			return 0;
+		}
+	default:
+		return 0;
+	}
+}
+
+int KattonGenerator::plusminus(int max) {
+	int result = getRandomNumber() % (max + 1);
+	if (getRandomNumber() % 2 == 0) {
+		result *= (-1);
+	}
+	return result;
+}
+
+int KattonGenerator::fillboards(int num) {
+	int i, j;
+	for (i = 0; i < size; i++) {
+		for (j = 0; j < size; j++) {
+			board[i][j] = num;
+			special[i][j] = num;
+		}
+	}
+	return 0;
+}
+
+int KattonGenerator::randomplace(int numberofplaces, int placer) {
+	int i, randx, randy;
+	for (i = 0; i < numberofplaces; i++) {
+		randx = (getRandomNumber() % size);
+		randy = (getRandomNumber() % size);
+		board[randx][randy] = placer;
+	}
+	return 0;
+}
+
+int KattonGenerator::randomsplotch(int length, int stringiness, int placer, int x, int y) {
+	int currx, curry, direction = 10, prevdirection, movex, movey, i = 0;
+	currx = x;
+	curry = y;
+	while (i <= length) {
+		board[currx][curry] = placer;
+		prevdirection = direction;
+		direction = (getRandomNumber() % 4);
+		if ((((direction + 2) == prevdirection) || ((direction - 2) == prevdirection)) && (stringiness == 2)) {
+			direction = prevdirection;
+		}
+		if (!((((direction + 2) == prevdirection) || ((direction - 2) == prevdirection)) && (stringiness == 1))) {
+			switch (direction) {
+			case 0:
+				movex = 0;
+				movey = 1;
+				break;
+			case 1:
+				movex = 1;
+				movey = 0;
+				break;
+			case 2:
+				movex = 0;
+				movey = -1;
+				break;
+			case 3:
+				movex = -1;
+				movey = 0;
+				break;
+			}
+			currx = findcoord(currx, movex);
+			curry = findcoord(curry, movey);
+			i++;
+		}
+	}
+	return 0;
+}
+
+int KattonGenerator::findcoord(int value, int move) {
+	move = move % size;
+	int final = value + move;
+	if (final < 0) {
+		final = size + final;
+	}
+	if (final >= size) {
+		final = final % size;
+	}
+	return final;
+}
+
+int KattonGenerator::replacenum(int replacee, int replacer) {
+	int i, j;
+	for (j = 0; j < size; j++) {
+		for (i = 0; i < size; i++) {
+			if (board[i][j] == replacee) {
+				board[i][j] = replacer;
+			}
+		}
+	}
+	return 0;
+}
+
+int KattonGenerator::fattenall(int howfat, int middle, int ignorer, int replacer) {
+	int i, j, temp;
+	for (j = 0; j < size; j++) {
+		for (i = 0; i < size; i++) {
+			if (board[i][j] == middle) {
+				if (howfat <= 0) {
+					temp = (int)(abs(howfat) + plusminus(2));
+					if (temp <= 1) {
+						temp = 2;
+					} else if (temp >= 6) {
+						temp = 5;
+					}
+					fattenone(i, j, temp, middle, ignorer, replacer);
+				} else {
+					fattenone(i, j, howfat, middle, ignorer, replacer);
+				}
+			}
+		}
+	}
+	return 0;
+}
+int KattonGenerator::fattenone(int x, int y, int howfat, int middle, int ignorer, int replacer) {
+	if (howfat == -100) {
+		board[x][y] = replacer;
+		board[findcoord(x, +1)][y] = replacer;
+		board[x][findcoord(y, +1)] = replacer;
+		board[findcoord(x, +1)][findcoord(y, +1)] = replacer;
+	}
+	if (howfat >= 1) {
+		board[x][findcoord(y, -1)] = ((board[x][findcoord(y, -1)] == middle) || (board[x][findcoord(y, -1)] == ignorer)) ? board[x][findcoord(y, -1)] : replacer;
+		board[x][findcoord(y, +1)] = ((board[x][findcoord(y, +1)] == middle) || (board[x][findcoord(y, +1)] == ignorer)) ? board[x][findcoord(y, +1)] : replacer;
+		board[findcoord(x, -1)][y] = ((board[findcoord(x, -1)][y] == middle) || (board[findcoord(x, -1)][y] == ignorer)) ? board[findcoord(x, -1)][y] : replacer;
+		board[findcoord(x, +1)][y] = ((board[findcoord(x, +1)][y] == middle) || (board[findcoord(x, +1)][y] == ignorer)) ? board[findcoord(x, +1)][y] : replacer;
+	}
+	if (howfat >= 2) {
+		board[findcoord(x, -1)][findcoord(y, -1)] = ((board[findcoord(x, -1)][findcoord(y, -1)] == middle) || (board[findcoord(x, -1)][findcoord(y, -1)] == ignorer)) ? board[findcoord(x, -1)][findcoord(y, -1)] : replacer;
+		board[findcoord(x, -1)][findcoord(y, +1)] = ((board[findcoord(x, -1)][findcoord(y, +1)] == middle) || (board[findcoord(x, -1)][findcoord(y, +1)] == ignorer)) ? board[findcoord(x, -1)][findcoord(y, +1)] : replacer;
+		board[findcoord(x, +1)][findcoord(y, -1)] = ((board[findcoord(x, +1)][findcoord(y, -1)] == middle) || (board[findcoord(x, +1)][findcoord(y, -1)] == ignorer)) ? board[findcoord(x, +1)][findcoord(y, -1)] : replacer;
+		board[findcoord(x, +1)][findcoord(y, +1)] = ((board[findcoord(x, +1)][findcoord(y, +1)] == middle) || (board[findcoord(x, +1)][findcoord(y, +1)] == ignorer)) ? board[findcoord(x, +1)][findcoord(y, +1)] : replacer;
+	}
+	if (howfat >= 3) {
+		board[x][findcoord(y, -2)] = ((board[x][findcoord(y, -2)] == middle) || (board[x][findcoord(y, -2)] == ignorer)) ? board[x][findcoord(y, -2)] : replacer;
+		board[x][findcoord(y, +2)] = ((board[x][findcoord(y, +2)] == middle) || (board[x][findcoord(y, +2)] == ignorer)) ? board[x][findcoord(y, +2)] : replacer;
+		board[findcoord(x, -2)][y] = ((board[findcoord(x, -2)][y] == middle) || (board[findcoord(x, -2)][y] == ignorer)) ? board[findcoord(x, -2)][y] : replacer;
+		board[findcoord(x, +2)][y] = ((board[findcoord(x, +2)][y] == middle) || (board[findcoord(x, +2)][y] == ignorer)) ? board[findcoord(x, +2)][y] : replacer;
+	}
+	if (howfat >= 4) {
+		board[findcoord(x, -1)][findcoord(y, -2)] = ((board[findcoord(x, -1)][findcoord(y, -2)] == middle) || (board[findcoord(x, -1)][findcoord(y, -2)] == ignorer)) ? board[findcoord(x, -1)][findcoord(y, -2)] : replacer;
+		board[findcoord(x, -1)][findcoord(y, +2)] = ((board[findcoord(x, -1)][findcoord(y, +2)] == middle) || (board[findcoord(x, -1)][findcoord(y, +2)] == ignorer)) ? board[findcoord(x, -1)][findcoord(y, +2)] : replacer;
+		board[findcoord(x, +1)][findcoord(y, -2)] = ((board[findcoord(x, +1)][findcoord(y, -2)] == middle) || (board[findcoord(x, +1)][findcoord(y, -2)] == ignorer)) ? board[findcoord(x, +1)][findcoord(y, -2)] : replacer;
+		board[findcoord(x, +1)][findcoord(y, +2)] = ((board[findcoord(x, +1)][findcoord(y, +2)] == middle) || (board[findcoord(x, +1)][findcoord(y, +2)] == ignorer)) ? board[findcoord(x, +1)][findcoord(y, +2)] : replacer;
+
+		board[findcoord(x, -2)][findcoord(y, -1)] = ((board[findcoord(x, -2)][findcoord(y, -1)] == middle) || (board[findcoord(x, -2)][findcoord(y, -1)] == ignorer)) ? board[findcoord(x, -2)][findcoord(y, -1)] : replacer;
+		board[findcoord(x, -2)][findcoord(y, +1)] = ((board[findcoord(x, -2)][findcoord(y, +1)] == middle) || (board[findcoord(x, -2)][findcoord(y, +1)] == ignorer)) ? board[findcoord(x, -2)][findcoord(y, +1)] : replacer;
+		board[findcoord(x, +2)][findcoord(y, -1)] = ((board[findcoord(x, +2)][findcoord(y, -1)] == middle) || (board[findcoord(x, +2)][findcoord(y, -1)] == ignorer)) ? board[findcoord(x, +2)][findcoord(y, -1)] : replacer;
+		board[findcoord(x, +2)][findcoord(y, +1)] = ((board[findcoord(x, +2)][findcoord(y, +1)] == middle) || (board[findcoord(x, +2)][findcoord(y, +1)] == ignorer)) ? board[findcoord(x, +2)][findcoord(y, +1)] : replacer;
+	}
+	if (howfat >= 5) {
+		board[findcoord(x, -2)][findcoord(y, -2)] = ((board[findcoord(x, -2)][findcoord(y, -2)] == middle) || (board[findcoord(x, -2)][findcoord(y, -2)] == ignorer)) ? board[findcoord(x, -2)][findcoord(y, -2)] : replacer;
+		board[findcoord(x, -2)][findcoord(y, +2)] = ((board[findcoord(x, -2)][findcoord(y, +2)] == middle) || (board[findcoord(x, -2)][findcoord(y, +2)] == ignorer)) ? board[findcoord(x, -2)][findcoord(y, +2)] : replacer;
+		board[findcoord(x, +2)][findcoord(y, -2)] = ((board[findcoord(x, +2)][findcoord(y, -2)] == middle) || (board[findcoord(x, +2)][findcoord(y, -2)] == ignorer)) ? board[findcoord(x, +2)][findcoord(y, -2)] : replacer;
+		board[findcoord(x, +2)][findcoord(y, +2)] = ((board[findcoord(x, +2)][findcoord(y, +2)] == middle) || (board[findcoord(x, +2)][findcoord(y, +2)] == ignorer)) ? board[findcoord(x, +2)][findcoord(y, +2)] : replacer;
+
+		board[x][findcoord(y, -3)] = ((board[x][findcoord(y, -3)] == middle) || (board[x][findcoord(y, -3)] == ignorer)) ? board[x][findcoord(y, -3)] : replacer;
+		board[x][findcoord(y, +3)] = ((board[x][findcoord(y, +3)] == middle) || (board[x][findcoord(y, +3)] == ignorer)) ? board[x][findcoord(y, +3)] : replacer;
+		board[findcoord(x, -3)][y] = ((board[findcoord(x, -3)][y] == middle) || (board[findcoord(x, -3)][y] == ignorer)) ? board[findcoord(x, -3)][y] : replacer;
+		board[findcoord(x, +3)][y] = ((board[findcoord(x, +3)][y] == middle) || (board[findcoord(x, +3)][y] == ignorer)) ? board[findcoord(x, +3)][y] : replacer;
+	}
+	return 0;
+}
+
+int KattonGenerator::findstartloc() {
+	int temp, i, j, shiftx, shifty, secondshift;
+	int start[4][2];
+	shiftx = getRandomNumber() % size;
+	shifty = getRandomNumber() % size;
+	start[0][0] = findcoord((int)size / 4, (plusminus(3) + shiftx));
+	start[0][1] = findcoord((int)size / 4, (plusminus(3) + shifty));
+	start[1][0] = findcoord((int)3 * size / 4, (plusminus(3) + shiftx));
+	start[1][1] = findcoord((int)size / 4, (plusminus(3) + shifty));
+	start[2][0] = findcoord((int)size / 4, (plusminus(3) + shiftx));
+	start[2][1] = findcoord((int)3 * size / 4, (plusminus(3) + shifty));
+	start[3][0] = findcoord((int)3 * size / 4, (plusminus(3) + shiftx));
+	start[3][1] = findcoord((int)3 * size / 4, (plusminus(3) + shifty));
+
+	temp = getRandomNumber() % 2;
+	secondshift = getRandomNumber() % size;
+
+	if (temp == 0) {
+		start[0][0] = findcoord(start[0][0], secondshift);
+		start[1][0] = findcoord(start[1][0], secondshift);
+	}
+
+	else {
+		start[1][1] = findcoord(start[1][1], secondshift);
+		start[3][1] = findcoord(start[3][1], secondshift);
+	}
+
+	temp = whatheightstartloc(start[0][0], start[0][1]);
+	fattenone(start[0][0], start[0][1], -100, temp, NEVER_USED_NUM, temp);
+
+	temp = whatheightstartloc(start[1][0], start[1][1]);
+	fattenone(start[1][0], start[1][1], -100, temp, NEVER_USED_NUM, temp);
+
+	temp = whatheightstartloc(start[2][0], start[2][1]);
+	fattenone(start[2][0], start[2][1], -100, temp, NEVER_USED_NUM, temp);
+
+	temp = whatheightstartloc(start[3][0], start[3][1]);
+	fattenone(start[3][0], start[3][1], -100, temp, NEVER_USED_NUM, temp);
+
+	for (j = 0; j < 4; j++) {
+		for (i = 0; i < 2; i++) {
+			startloc[j][i] = start[j][i];
+		}
+	}
+
+	temp = getRandomNumber() % 4;
+	j = 4;
+	for (i = 0; i < 4; i++) {
+		if (temp == i) {
+		} else {
+			startloc[j][0] = start[i][0];
+			startloc[j][1] = start[i][1];
+			j++;
+		}
+	}
+
+	startloc[7][0] = startloc[4][0];
+	startloc[7][1] = startloc[4][1];
+	startloc[8][0] = startloc[6][0];
+	startloc[8][1] = startloc[6][1];
+
+	for (j = 9; j < 13; j++) {
+		for (i = 0; i < 2; i++) {
+			startloc[j][i] = start[j - 9][i];
+		}
+	}
+
+	for (j = 13; j < 17; j++) {
+		for (i = 0; i < 2; i++) {
+			startloc[j][i] = start[j - 13][i];
+		}
+	}
+
+	for (j = 17; j < 20; j++) {
+		for (i = 0; i < 2; i++) {
+			startloc[j][i] = startloc[j - 13][i];
+		}
+	}
+
+	// place on special map
+	for (i = 0; i < 4; i++) {
+		special[startloc[i][0]][startloc[i][1]] += 1;
+	}
+	for (i = 4; i < 7; i++) {
+		special[startloc[i][0]][startloc[i][1]] += 2;
+	}
+	for (i = 7; i < 9; i++) {
+		special[startloc[i][0]][startloc[i][1]] += 4;
+	}
+	for (i = 9; i < 13; i++) {
+		special[startloc[i][0]][startloc[i][1]] += 8;
+	}
+	for (i = 13; i < 17; i++) {
+		special[startloc[i][0]][startloc[i][1]] += 16;
+	}
+	for (i = 17; i < 20; i++) {
+		special[startloc[i][0]][startloc[i][1]] += 32;
+	}
+	return 0;
+}
+
+int KattonGenerator::whatheightstartloc(int x, int y) {
+	int heightfield[3] = {0, 0, 0};
+
+	heightfield[board[findcoord(x, +2)][findcoord(y, -1)]]++;
+	heightfield[board[findcoord(x, +2)][y]]++;
+	heightfield[board[findcoord(x, +2)][findcoord(y, +1)]]++;
+	heightfield[board[findcoord(x, +2)][findcoord(y, +2)]]++;
+
+	heightfield[board[findcoord(x, -1)][findcoord(y, -1)]]++;
+	heightfield[board[findcoord(x, -1)][y]]++;
+	heightfield[board[findcoord(x, -1)][findcoord(y, +1)]]++;
+	heightfield[board[findcoord(x, -1)][findcoord(y, +2)]]++;
+
+	heightfield[board[x][findcoord(y, -1)]]++;
+	heightfield[board[x][y]]++;
+	heightfield[board[x][findcoord(y, +1)]]++;
+	heightfield[board[x][findcoord(y, +2)]]++;
+
+	heightfield[board[findcoord(x, +1)][findcoord(y, -1)]]++;
+	heightfield[board[findcoord(x, +1)][y]]++;
+	heightfield[board[findcoord(x, +1)][findcoord(y, +1)]]++;
+	heightfield[board[findcoord(x, +1)][findcoord(y, +2)]]++;
+
+	if (heightfield[0] == 0) {
+		if (heightfield[1] >= heightfield[2]) {
+			return 1;
+		} else {
+			return 2;
+		}
+	} else if (heightfield[1] == 0) {
+		if (heightfield[0] >= heightfield[2]) {
+			return 0;
+		} else {
+			return 2;
+		}
+	} else if (heightfield[2] == 0) {
+		if (heightfield[1] >= heightfield[0]) {
+			return 1;
+		} else {
+			return 0;
+		}
+	} else {
+		return 1;
+	}
+}
+
+int KattonGenerator::goodforwater(int x, int y) {
+	if ((board[x][y] == 0) && (board[findcoord(x, +1)][y] == 0) && (board[x][findcoord(y, +1)] == 0) && (board[findcoord(x, +1)][findcoord(y, +1)] == 0)) {                                                                                                                                                                                                                                                       //check main map
+		if ((special[x][y] <= 0) && (special[x][findcoord(y, 1)] <= 0) && (special[findcoord(x, 1)][findcoord(y, 1)] <= 0) && (special[findcoord(x, 1)][y] <= 0) && (special[findcoord(x, 1)][findcoord(y, -1)] <= 0) && (special[x][findcoord(y, -1)] <= 0) && (special[findcoord(x, -1)][findcoord(y, -1)] <= 0) && (special[findcoord(x, -1)][y] <= 0) && (special[findcoord(x, -1)][findcoord(y, 1)] <= 0)) { //specials are clear
+			return 1;
+		} else {
+			return 0;
+		}
+	} else {
+		return 0;
+	}
+}
+
+int KattonGenerator::randomwater(int length, int stringiness, int x, int y) {
+	int currx, curry, direction = 10, prevdirection, i = 0;
+	currx = x;
+	curry = y;
+	while (i <= length) {
+		special[currx][curry] = -1;
+		prevdirection = direction;
+		direction = (getRandomNumber() % 4);
+		if ((((direction + 2) == prevdirection) || ((direction - 2) == prevdirection)) && (stringiness == 2)) {
+			direction = prevdirection;
+		}
+		if (!((((direction + 2) == prevdirection) || ((direction - 2) == prevdirection)) && (stringiness == 1))) {
+			switch (direction) {
+
+			case 0: //north
+				if (goodforwater(currx, findcoord(curry, 1))) {
+					curry = findcoord(curry, 1);
+				}
+				break;
+
+			case 1: //east
+				if (goodforwater(findcoord(currx, 1), curry)) {
+					currx = findcoord(currx, 1);
+				}
+				break;
+
+			case 2: //south
+				if (goodforwater(currx, findcoord(curry, -1))) {
+					curry = findcoord(curry, -1);
+				}
+				break;
+
+			case 3: //west
+				if (goodforwater(findcoord(currx, -1), curry)) {
+					currx = findcoord(currx, -1);
+				}
+				break;
+			}
+			i++;
+		}
+	}
+	return 0;
+}
+
+int KattonGenerator::tileaverage(int x, int y, int threshold) {
+	int heightfield[3] = {0, 0, 0};
+
+	heightfield[board[findcoord(x, -1)][findcoord(y, -1)]]++;
+	heightfield[board[findcoord(x, -1)][y]]++;
+	heightfield[board[findcoord(x, -1)][findcoord(y, +1)]]++;
+
+	heightfield[board[x][findcoord(y, -1)]]++;
+	heightfield[board[x][y]]++;
+	heightfield[board[x][findcoord(y, +1)]]++;
+
+	heightfield[board[findcoord(x, +1)][findcoord(y, -1)]]++;
+	heightfield[board[findcoord(x, +1)][y]]++;
+	heightfield[board[findcoord(x, +1)][findcoord(y, +1)]]++;
+
+	if ((heightfield[2] == 0) && (heightfield[1] < heightfield[0]) && (heightfield[0] >= threshold)) {
+		board[x][y] = 0;
+		return 0;
+	} else if ((heightfield[0] == 0) && (heightfield[1] < heightfield[2]) && (heightfield[2] >= threshold)) {
+		board[x][y] = 2;
+		return 2;
+	} else if (heightfield[1] >= threshold) {
+		board[x][y] = 1;
+		return 1;
+	} else {
+		return 0;
+	}
+}
+
+int KattonGenerator::randomflip(int numberofplaces, int inWater) {
+	int i, x, y, temp;
+	for (i = 0; i < numberofplaces; i++) {
+		x = getRandomNumber() % size;
+		y = getRandomNumber() % size;
+		if (board[x][y] == 0) {
+			temp = getRandomNumber() % inWater;
+			if (temp <= 50) {
+				board[x][y] = 1;
+			}
+		} else if (board[x][y] == 2) {
+			board[x][y] = 1;
+		} else if (board[x][y] == 1) {
+
+			temp = getRandomNumber() % 2;
+			int heightfield[3] = {0, 0, 0};
+
+			heightfield[board[findcoord(x, -1)][findcoord(y, -1)]]++;
+			heightfield[board[findcoord(x, -1)][y]]++;
+			heightfield[board[findcoord(x, -1)][findcoord(y, +1)]]++;
+
+			heightfield[board[x][findcoord(y, -1)]]++;
+			heightfield[board[x][findcoord(y, +1)]]++;
+
+			heightfield[board[findcoord(x, +1)][findcoord(y, -1)]]++;
+			heightfield[board[findcoord(x, +1)][y]]++;
+			heightfield[board[findcoord(x, +1)][findcoord(y, +1)]]++;
+			temp = getRandomNumber() % 2;
+			if (heightfield[0] == 0) {
+				board[x][y] = 2;
+			} else if (heightfield[2] == 0) {
+				board[x][y] = 0;
+			}
+		}
+	}
+	return 0;
+}
+
+} // End of namespace Scumm
diff --git a/engines/scumm/he/moonbase/map_katton.h b/engines/scumm/he/moonbase/map_katton.h
new file mode 100644
index 00000000000..ba92db33d7b
--- /dev/null
+++ b/engines/scumm/he/moonbase/map_katton.h
@@ -0,0 +1,77 @@
+/* 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 SCUMM_HE_MOONBASE_MAP_KATTON
+#define SCUMM_HE_MOONBASE_MAP_KATTON
+
+#ifdef ENABLE_HE
+
+#include "engines/scumm/he/moonbase/map_mif.h"
+
+#define TEMP_REPLACEMENT_NUMA 5
+#define NEVER_USED_NUM 99
+
+namespace Scumm {
+
+class KattonGenerator {
+public:
+	KattonGenerator(int seed);
+	~KattonGenerator();
+
+	MapFile *generateMap(int water, int tileSet, int mapSize, int energy, int terrain);
+
+private:
+	int _seed;
+
+	int size; // 32, 40, 48, or 56
+	int tileset;
+	int startloc[20][2];
+	int board[MAX_TILE_COUNT][MAX_TILE_COUNT];
+	int special[MAX_TILE_COUNT][MAX_TILE_COUNT];
+
+	int getRandomNumber();
+
+	int min(int a, int b, int c);
+	int distance(int x1, int y1, int x2, int y2);
+	int plusminus(int max);
+	int fillboards(int num);
+	int randomplace(int numberofplaces, int placer);
+	int randomflip(int numberofplaces, int inWater);
+	// stringiness: 0 = no change/random, 1 = no back, 2 = back goes forwards
+	int randomsplotch(int length, int stringiness, int placer, int x, int y);
+	int goodforwater(int x, int y);
+	int randomwater(int length, int stringiness, int x, int y);
+	int goodforenergy(int x, int y, int poolsize);
+	int findcoord(int value, int move);
+	int replacenum(int replacee, int replacer);
+	int fattenone(int x, int y, int howfat, int middle, int ignorer, int replacer);
+	// howfat: postive 1-5 for distance, -100 to 0 for random 3 spread from 2 to 5.
+	int fattenall(int howfat, int middle, int ignorer, int replacer);
+	int findstartloc();
+	int whatheightstartloc(int x, int y);
+	int tileaverage(int x, int y, int threshold);
+};
+
+} // End of namespace Scumm
+
+#endif // ENABLE_HE
+
+#endif // SCUMM_HE_MOONBASE_MAP_KATTON
diff --git a/engines/scumm/he/moonbase/map_main.cpp b/engines/scumm/he/moonbase/map_main.cpp
index 06159467b82..241dea9a633 100644
--- a/engines/scumm/he/moonbase/map_main.cpp
+++ b/engines/scumm/he/moonbase/map_main.cpp
@@ -28,7 +28,9 @@
 
 #include "scumm/he/moonbase/map_data.h"
 #include "scumm/he/moonbase/map_main.h"
+
 #include "scumm/he/moonbase/map_spiff.h"
+#include "scumm/he/moonbase/map_katton.h"
 
 namespace Scumm {
 
@@ -59,6 +61,8 @@ bool Map::generateNewMap() {
 	// Don't randomly pick nonstandard map sizes.
 	int mapSize = _rnd.getRandomNumberRngSigned(4, 8) * 8;
 
+	uint8 generator = _rnd.getRandomNumberRng(1, 2);
+
 	int tileSet = _rnd.getRandomNumberRngSigned(1, 6);
 
 	// Only use [2, 3, 4] of the legal [0, 1, 2, 3, 4, 5, 6]
@@ -69,7 +73,7 @@ bool Map::generateNewMap() {
 	// 32767 is RAND_MAX on Windows
 	int seed = _rnd.getRandomNumber(32767);
 
-	return generateMapWithInfo(SPIFF_GEN, seed, mapSize, tileSet, energy, terrain, water);
+	return generateMapWithInfo(generator, seed, mapSize, tileSet, energy, terrain, water);
 }
 
 bool Map::generateMapWithInfo(uint8 generator, int seed, int mapSize, int tileset, int energy, int terrain, int water) {
@@ -88,6 +92,12 @@ bool Map::generateMapWithInfo(uint8 generator, int seed, int mapSize, int tilese
 		_generatedMap = spiff.generateMap(water, tileset, mapSize, energy, terrain);
 		break;
 	}
+	case KATTON_GEN:
+	{
+		KattonGenerator katton = KattonGenerator(seed);
+		_generatedMap = katton.generateMap(water, tileset, mapSize, energy, terrain);
+		break;
+	}
 	default:
 		error("Map: Got unknown generator: %d", generator);
 		return false;
diff --git a/engines/scumm/module.mk b/engines/scumm/module.mk
index ee893c37bc4..ff976ab027d 100644
--- a/engines/scumm/module.mk
+++ b/engines/scumm/module.mk
@@ -175,6 +175,7 @@ MODULE_OBJS += \
 	he/moonbase/ai_tree.o \
 	he/moonbase/ai_types.o \
 	he/moonbase/ai_weapon.o \
+	he/moonbase/map_katton.o \
 	he/moonbase/map_main.o \
 	he/moonbase/map_mif.o \
 	he/moonbase/map_spiff.o \


Commit: 79a5e12ed105836874ef538255d874ee5b191b55
    https://github.com/scummvm/scummvm/commit/79a5e12ed105836874ef538255d874ee5b191b55
Author: Little Cat (toontownlittlecat at gmail.com)
Date: 2024-05-12T15:08:27+02:00

Commit Message:
SCUMM HE: Fix generated map names.

Changed paths:
    engines/scumm/he/moonbase/map_katton.cpp
    engines/scumm/he/moonbase/map_spiff.cpp


diff --git a/engines/scumm/he/moonbase/map_katton.cpp b/engines/scumm/he/moonbase/map_katton.cpp
index e27a815dee3..71d4f67dbc0 100644
--- a/engines/scumm/he/moonbase/map_katton.cpp
+++ b/engines/scumm/he/moonbase/map_katton.cpp
@@ -269,7 +269,7 @@ MapFile *KattonGenerator::generateMap(int water, int tileSet, int mapSize, int e
 
 	//****************************************Do that saving thing that you do, BABY!
 	MIF mif = MIF();
-	Common::sprintf_s(mif.name, "Katton %04X", _seed);
+	Common::sprintf_s(mif.name, "Katton %04X", (uint16)_seed);
 	mif.dimension = size;
 	mif.mapType = tileset;
 	for (j = 0; j < size; j++) {
diff --git a/engines/scumm/he/moonbase/map_spiff.cpp b/engines/scumm/he/moonbase/map_spiff.cpp
index 8be3ee31a16..c73ac2b45ec 100644
--- a/engines/scumm/he/moonbase/map_spiff.cpp
+++ b/engines/scumm/he/moonbase/map_spiff.cpp
@@ -70,7 +70,7 @@ MapFile *SpiffGenerator::generateMap(int water, int tileset, int mapSize, int en
 	levelMap[LOW] = 0;
 
 	mif.mapType = tileset;
-	Common::sprintf_s(mif.name, "Spiff %04X", _seed);
+	Common::sprintf_s(mif.name, "Spiff %04X", (uint16)_seed);
 
 	mif.dimension = totalMapSizeG;
 


Commit: 9a6a4efa82274dd0dc498d039047fd0f7bdbc002
    https://github.com/scummvm/scummvm/commit/9a6a4efa82274dd0dc498d039047fd0f7bdbc002
Author: Little Cat (toontownlittlecat at gmail.com)
Date: 2024-05-12T15:08:27+02:00

Commit Message:
SCUMM HE: Fix compile errors on Windows.

Changed paths:
    engines/scumm/he/moonbase/map_katton.cpp


diff --git a/engines/scumm/he/moonbase/map_katton.cpp b/engines/scumm/he/moonbase/map_katton.cpp
index 71d4f67dbc0..efcb327d8b1 100644
--- a/engines/scumm/he/moonbase/map_katton.cpp
+++ b/engines/scumm/he/moonbase/map_katton.cpp
@@ -77,7 +77,7 @@ MapFile *KattonGenerator::generateMap(int water, int tileSet, int mapSize, int e
 	int numwaterplaces = 0, numwatersplotches, multiplier;
 	short int goodwater[1600][2];
 	// used in making energy
-	int maxnumclose, maxnumfar, maxnumrand, smallmed, goodplaceClose[300][2], goodplaceFar[300][2], numplaceClose, numplaceFar, placeFar[3], placeClose[2], counter, counterpools;
+	int maxnumclose = 0, maxnumfar = 0, maxnumrand = 0, smallmed = 0, goodplaceClose[300][2], goodplaceFar[300][2], numplaceClose, numplaceFar, placeFar[3], placeClose[2], counter, counterpools;
 
 	//****************************************Make the basic landmass shapes.
 
@@ -375,7 +375,7 @@ int KattonGenerator::randomplace(int numberofplaces, int placer) {
 }
 
 int KattonGenerator::randomsplotch(int length, int stringiness, int placer, int x, int y) {
-	int currx, curry, direction = 10, prevdirection, movex, movey, i = 0;
+	int currx, curry, direction = 10, prevdirection, movex = 0, movey = 0, i = 0;
 	currx = x;
 	curry = y;
 	while (i <= length) {


Commit: b60f4d4069b42d82f5c288623e25295e5d5a8e22
    https://github.com/scummvm/scummvm/commit/b60f4d4069b42d82f5c288623e25295e5d5a8e22
Author: Little Cat (toontownlittlecat at gmail.com)
Date: 2024-05-12T15:08:27+02:00

Commit Message:
SCUMM HE: Save generated map alongside replays.

Changed paths:
    engines/scumm/he/moonbase/map_main.cpp
    engines/scumm/he/moonbase/map_main.h
    engines/scumm/he/script_v100he.cpp
    engines/scumm/he/script_v80he.cpp


diff --git a/engines/scumm/he/moonbase/map_main.cpp b/engines/scumm/he/moonbase/map_main.cpp
index 241dea9a633..cd2fac932db 100644
--- a/engines/scumm/he/moonbase/map_main.cpp
+++ b/engines/scumm/he/moonbase/map_main.cpp
@@ -44,9 +44,7 @@ Map::Map(ScummEngine_v100he *vm) : _vm(vm), _rnd("moonbase") {
 }
 
 Map::~Map() {
-	if (_generatedMap) {
-		delete _generatedMap;
-	}
+	deleteMap();
 }
 
 bool Map::generateNewMap() {
@@ -77,10 +75,7 @@ bool Map::generateNewMap() {
 }
 
 bool Map::generateMapWithInfo(uint8 generator, int seed, int mapSize, int tileset, int energy, int terrain, int water) {
-	if (_generatedMap) {
-		// Delete old map.
-		delete _generatedMap;
-	}
+	deleteMap();
 
 	_seed = seed;
 
@@ -112,6 +107,16 @@ bool Map::generateMapWithInfo(uint8 generator, int seed, int mapSize, int tilese
 	return true;
 }
 
+void Map::deleteMap() {
+	if (_mapGenerated) {
+		// Delete old map.
+		delete _generatedMap;
+
+		_mapGenerated = false;
+		debug(1, "Map: Deleted.");
+	}
+}
+
 Common::SeekableReadStream *Map::makeWiz() {
 	unsigned short wiz [139][139];
 	int i, j;
@@ -190,7 +195,10 @@ Common::SeekableReadStream *Map::substituteFile(const byte *fileName) {
 			return makeWiz();
 		}
 
-		if (!strcmp((const char *)fileName, "map\\moon001.map")) {
+		if (!strcmp((const char *)fileName, "map\\moon001.map") ||
+		    !strcmp((const char *)fileName, "user\\Temp.map")) {
+			// (The Temp.map name is used when the game saves the map alongside
+			// replay data)
 			// Return new ReadStream but do not dispose it.  We'll handle
 			// that ourselves.
 			return new Common::MemoryReadStream((byte *)_generatedMap, sizeof(MapFile));
diff --git a/engines/scumm/he/moonbase/map_main.h b/engines/scumm/he/moonbase/map_main.h
index 861f268aecf..567d3a33bf3 100644
--- a/engines/scumm/he/moonbase/map_main.h
+++ b/engines/scumm/he/moonbase/map_main.h
@@ -43,10 +43,16 @@ public:
 	bool generateMapWithInfo(uint8 generator, int seed, int mapSize, int tileset, int energy, int terrain, int water);
 	Common::SeekableReadStream *substituteFile(const byte *fileName);
 
+	void deleteMap();
+
 	uint32 getSeed() const {
 		return _seed;
 	}
 
+	bool mapGenerated() const {
+		return _mapGenerated;
+	}
+
 private:
 	ScummEngine_v100he *_vm;
 
diff --git a/engines/scumm/he/script_v100he.cpp b/engines/scumm/he/script_v100he.cpp
index d642b30e55b..113e3c4897c 100644
--- a/engines/scumm/he/script_v100he.cpp
+++ b/engines/scumm/he/script_v100he.cpp
@@ -2171,6 +2171,26 @@ void ScummEngine_v100he::o100_startScript() {
 		// (gGameMode == GAME-MODE-MULTIPLAYER-HOST || gGameMode == GAME-MODE-TCPIP-HOST ||
 		//  gGameMode == GAME-MODE-SINGLEPLAYER-SKIRMISH)
 		_moonbase->_map->generateNewMap();
+	} else if (_game.id == GID_MOONBASE && _roomResource == 5 &&
+		((!strcmp(_game.variant, "1.1") && script == 2252) || script == 2251) &&
+		readArray(231, readVar(230) + 1, 10) == 1 && _moonbase->_map->mapGenerated()) {
+		// (setup-gameoversetup)
+		// If we are playing on a generated map, we have to indicate that we are
+		// playing on a temporary map (normally happens if a host choses their custom
+		// made map during multiplayer setup).  That way, the map properly gets saved
+		// alongside replays.  Bonus side-effect: The players can save the map itself
+		// if they'd like.
+
+		// gMapSaved = FALSE (This gets set to true if player is the host)
+		writeVar(272, 0);
+
+		// gSetupArray[(gMaxPlayers + 1)][SETUP-MAP] = 66
+		// (The game checks if it's greater than 65)
+		writeArray(231, readVar(230) + 1, 10, 66);
+	} else if (_game.id == GID_MOONBASE && _roomResource == 5 && script == 2048) {
+		// (setup-mainmenu)
+		// Delete generated map if there is any.
+		_moonbase->_map->deleteMap();
 	}
 
 	runScript(script, (flags == SO_BAK || flags == SO_BAKREC), (flags == SO_REC || flags == SO_BAKREC), args);
diff --git a/engines/scumm/he/script_v80he.cpp b/engines/scumm/he/script_v80he.cpp
index 03c98472481..b10fac58e76 100644
--- a/engines/scumm/he/script_v80he.cpp
+++ b/engines/scumm/he/script_v80he.cpp
@@ -36,6 +36,9 @@
 #include "scumm/scumm.h"
 #include "scumm/he/sound_he.h"
 
+#include "scumm/he/moonbase/moonbase.h"
+#include "scumm/he/moonbase/map_main.h"
+
 namespace Scumm {
 
 #define OPCODE(i, x)	_opcodes[i]._OPCODE(ScummEngine_v80he, x)
@@ -242,6 +245,12 @@ void ScummEngine_v80he::o80_writeConfigFile() {
 			memcpy(section, "BluesTreasureHunt-Disc1\0", 24);
 		else if (!strcmp((char *)section, "Blue'sTreasureHunt-Disc2"))
 			memcpy(section, "BluesTreasureHunt-Disc2\0", 24);
+	} else if (_game.id == GID_MOONBASE && !strcmp((char *)option, "5-10") &&
+		!strcmp((char *)string, "1") && _moonbase->_map->mapGenerated()) {
+		// If we're playing on a generated map, make sure that the SETUP-MAP
+		// value gets stored to 66 (higher than 65), or else the replay will
+		// load the incorrect map.
+		memcpy(string, "66\0", 3);
 	}
 
 	Common::INIFile iniFile;


Commit: 8a6dacc607608ac1453e0149559fa4bb51f53b88
    https://github.com/scummvm/scummvm/commit/8a6dacc607608ac1453e0149559fa4bb51f53b88
Author: Little Cat (toontownlittlecat at gmail.com)
Date: 2024-05-12T15:08:27+02:00

Commit Message:
SCUMM HE: Add toggle setting for generated maps.

Changed paths:
    engines/scumm/dialogs.cpp
    engines/scumm/dialogs.h
    engines/scumm/he/moonbase/map_main.cpp


diff --git a/engines/scumm/dialogs.cpp b/engines/scumm/dialogs.cpp
index 9055e7800a1..ae169637f21 100644
--- a/engines/scumm/dialogs.cpp
+++ b/engines/scumm/dialogs.cpp
@@ -1688,6 +1688,9 @@ HENetworkGameOptionsWidget::HENetworkGameOptionsWidget(GuiObject *boss, const Co
 		_enableSessionServer = new GUI::CheckboxWidget(widgetsBoss(), "HENetworkGameOptionsDialog.EnableSessionServer", _("Enable connection to Multiplayer Server"), _("Toggles the connection to the server that allows hosting and joining online multiplayer games over the Internet."), kEnableSessionCmd);
 		_enableLANBroadcast = new GUI::CheckboxWidget(widgetsBoss(), "HENetworkGameOptionsDialog.EnableLANBroadcast", _("Host games over LAN"), _("Allows the game sessions to be discovered over your local area network."));
 
+		if (_gameid == "moonbase")
+			_generateRandomMaps = new GUI::CheckboxWidget(widgetsBoss(), "HENetworkGameOptionsDialog.GenerateRandomMaps", _("Generate random maps"), _("Allow random map generation (Based from Moonbase Console)."));
+
 		_sessionServerAddr = new GUI::EditTextWidget(widgetsBoss(), "HENetworkGameOptionsDialog.SessionServerAddress", Common::U32String(""), _("Address of the server to connect to for hosting and joining online game sessions."));
 
 		_serverResetButton = addClearButton(widgetsBoss(), "HENetworkGameOptionsDialog.ServerReset", kResetServersCmd);
@@ -1716,6 +1719,7 @@ void HENetworkGameOptionsWidget::load() {
 	} else {
 		bool enableSessionServer = true;
 		bool enableLANBroadcast = true;
+		bool generateRandomMaps = false;
 		Common::String sessionServerAddr = "multiplayer.scummvm.org";
 
 		if (ConfMan.hasKey("enable_session_server", _domain))
@@ -1730,6 +1734,10 @@ void HENetworkGameOptionsWidget::load() {
 			sessionServerAddr = ConfMan.get("session_server", _domain);
 		_sessionServerAddr->setEditString(sessionServerAddr);
 		_sessionServerAddr->setEnabled(enableSessionServer);
+
+		if (ConfMan.hasKey("generate_random_maps", _domain))
+			generateRandomMaps = ConfMan.getBool("generate_random_maps", _domain);
+		_generateRandomMaps->setState(generateRandomMaps);
 	}
 }
 
@@ -1745,6 +1753,8 @@ bool HENetworkGameOptionsWidget::save() {
 		ConfMan.setBool("enable_session_server", _enableSessionServer->getState(), _domain);
 		ConfMan.setBool("enable_lan_broadcast", _enableLANBroadcast->getState(), _domain);
 		ConfMan.set("session_server", _sessionServerAddr->getEditString(), _domain);
+		if (_gameid == "moonbase")
+			ConfMan.setBool("generate_random_maps", _generateRandomMaps->getState(), _domain);
 	}
 	return true;
 }
@@ -1772,6 +1782,7 @@ void HENetworkGameOptionsWidget::defineLayout(GUI::ThemeEval &layouts, const Com
 				.addPadding(0, 0, 12, 0)
 				.addWidget("EnableSessionServer", "Checkbox")
 				.addWidget("EnableLANBroadcast", "Checkbox")
+				.addWidget("GenerateRandomMaps", "Checkbox")
 				.addLayout(GUI::ThemeLayout::kLayoutHorizontal, 12)
 					.addPadding(0, 0, 12, 0)
 					.addWidget("SessionServerLabel", "OptionsLabel")
diff --git a/engines/scumm/dialogs.h b/engines/scumm/dialogs.h
index 00f78024ea1..1c795123805 100644
--- a/engines/scumm/dialogs.h
+++ b/engines/scumm/dialogs.h
@@ -414,6 +414,8 @@ private:
 
 	GUI::CheckboxWidget *_enableLANBroadcast;
 
+	GUI::CheckboxWidget *_generateRandomMaps;
+
 	GUI::EditTextWidget *_lobbyServerAddr;
 
 	GUI::CheckboxWidget *_enableCompetitiveMods;
diff --git a/engines/scumm/he/moonbase/map_main.cpp b/engines/scumm/he/moonbase/map_main.cpp
index cd2fac932db..09a77320e40 100644
--- a/engines/scumm/he/moonbase/map_main.cpp
+++ b/engines/scumm/he/moonbase/map_main.cpp
@@ -20,6 +20,7 @@
  */
 
 #include "common/compression/deflate.h"
+#include "common/config-manager.h"
 
 #include "common/memstream.h"
 #include "common/bufferedstream.h"
@@ -48,6 +49,8 @@ Map::~Map() {
 }
 
 bool Map::generateNewMap() {
+	if (!ConfMan.getBool("generate_random_maps"))
+		return false;
 
 	// TODO: Show a dialog allowing the user to customize options.
 


Commit: 2e2e2c41bee240a02cfa82e135a093f76b76519c
    https://github.com/scummvm/scummvm/commit/2e2e2c41bee240a02cfa82e135a093f76b76519c
Author: Little Cat (toontownlittlecat at gmail.com)
Date: 2024-05-12T15:08:27+02:00

Commit Message:
SCUMM HE: GUI: Add map generator dialog and bump theme version.

Changed paths:
  A engines/scumm/he/moonbase/dialog-mapgenerator.cpp
  A engines/scumm/he/moonbase/dialog-mapgenerator.h
    engines/scumm/module.mk
    gui/ThemeEngine.h
    gui/themes/common/highres_layout.stx
    gui/themes/common/lowres_layout.stx
    gui/themes/default.inc
    gui/themes/residualvm.zip
    gui/themes/residualvm/THEMERC
    gui/themes/scummclassic.zip
    gui/themes/scummclassic/THEMERC
    gui/themes/scummclassic/classic_layout.stx
    gui/themes/scummclassic/classic_layout_lowres.stx
    gui/themes/scummmodern.zip
    gui/themes/scummmodern/THEMERC
    gui/themes/scummremastered.zip
    gui/themes/scummremastered/THEMERC


diff --git a/engines/scumm/he/moonbase/dialog-mapgenerator.cpp b/engines/scumm/he/moonbase/dialog-mapgenerator.cpp
new file mode 100644
index 00000000000..3d6f7956dae
--- /dev/null
+++ b/engines/scumm/he/moonbase/dialog-mapgenerator.cpp
@@ -0,0 +1,375 @@
+/* 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/config-manager.h"
+#include "common/translation.h"
+
+#include "scumm/he/moonbase/map_main.h"
+#include "scumm/he/moonbase/dialog-mapgenerator.h"
+
+namespace Scumm {
+
+enum {
+	kAlgorCmd = 'ALGR',
+	kAlgorRandCmd = 'ALRM',
+
+	kSizeCmd = 'SIZE',
+	kSizeRandCmd = 'SZRM',
+
+	kTileCmd = 'TILE',
+	kTileRandCmd = 'TLRM',
+
+	kEnergyCmd = 'ENGY',
+	kEnergyRandCmd = 'EGRM',
+
+	kTerrainCmd = 'TRIN',
+	kTerrainRandCmd = 'TRRM',
+
+	kWaterCmd = 'WTER',
+	kWaterRandCmd = 'WTRM',
+
+	kCancelCmd = 'CNCL',
+	kGenerateCmd = 'GNRT'
+};
+
+MapGeneratorDialog::MapGeneratorDialog(bool demo) : Dialog("MapGenerator"), _refreshing(false) {
+	// I18N: Random map generator for Moonbase Commander
+	_dialogTitle = new GUI::StaticTextWidget(this, "MapGenerator.Title", _("Random Map Options"));
+	_dialogTitle->setAlign(Graphics::kTextAlignCenter);
+
+	// I18N: Map generator algorthims
+	_algorDesc = new GUI::StaticTextWidget(this, "MapGenerator.Algorithm", _("Algorithm"));
+	_algorDesc->setAlign(Graphics::kTextAlignLeft);
+	_algorGroup = new GUI::RadiobuttonGroup(this, kAlgorCmd);
+	// I18N: Spiff algorthim
+	_algorSpiff = new GUI::RadiobuttonWidget(this, "MapGenerator.AlgorithmSpiff", _algorGroup, SPIFF_GEN, _("Spiff"));
+	// I18N: Katton algorthim
+	_algorSpiff = new GUI::RadiobuttonWidget(this, "MapGenerator.AlgorithmKatton", _algorGroup, KATTON_GEN, _("Katton"));
+	// I18N: Random algorthim
+	_algorRandom = new GUI::CheckboxWidget(this, "MapGenerator.AlgorithmRandom", _("Random"), _("Picks the map algorithm randomly."), kAlgorRandCmd);
+
+	// I18N: Map sizes
+	_sizeDesc = new GUI::StaticTextWidget(this, "MapGenerator.Size", _("Size"));
+	_sizeDesc->setAlign(Graphics::kTextAlignCenter);
+
+	_sizeGroup = new GUI::RadiobuttonGroup(this, kSizeCmd);
+	_sizeSmall = new GUI::RadiobuttonWidget(this, "MapGenerator.SizeSmall", _sizeGroup, 4, _("Small"));
+	_sizeMedium = new GUI::RadiobuttonWidget(this, "MapGenerator.SizeMedium", _sizeGroup, 5, _("Medium"));
+	_sizeLarge = new GUI::RadiobuttonWidget(this, "MapGenerator.SizeLarge", _sizeGroup, 6, _("Large"));
+	_sizeHuge = new GUI::RadiobuttonWidget(this, "MapGenerator.SizeHuge", _sizeGroup, 7, _("Huge"));
+	_sizeSAI = new GUI::RadiobuttonWidget(this, "MapGenerator.SizeSAI", _sizeGroup, 8, _("SAI"));
+	_sizeRidiculous = new GUI::RadiobuttonWidget(this, "MapGenerator.SizeRidiculous", _sizeGroup, 9, _("Ridiculous"));
+	_sizeMax = new GUI::RadiobuttonWidget(this, "MapGenerator.SizeMax", _sizeGroup, 10, _("Max"));
+	// I18N: Random map size
+	_sizeRandom = new GUI::CheckboxWidget(this, "MapGenerator.SizeRandom", _("Random"), _("Picks the map size randomly."), kSizeRandCmd);
+
+	// I18N: Map tilesets
+	_tileDesc = new GUI::StaticTextWidget(this, "MapGenerator.Tileset", _("Tileset"));
+	_tileDesc->setAlign(Graphics::kTextAlignCenter);
+	_tileGroup = new GUI::RadiobuttonGroup(this, kTileCmd);
+	_tileTerrandra = new GUI::RadiobuttonWidget(this, "MapGenerator.TilesetTerrandra", _tileGroup, 1, Common::U32String("Terrandra"));
+	_tileZanateros = new GUI::RadiobuttonWidget(this, "MapGenerator.TilesetZanateros", _tileGroup, 2, Common::U32String("Zanateros"));
+	// Demo version of the game only has tilesets 1, 2, 4 and 6.  Don't create buttons for
+	// missing tiles.
+	if (!demo)
+		_tileDrijim = new GUI::RadiobuttonWidget(this, "MapGenerator.TilesetDaijim", _tileGroup, 3, Common::U32String("Daijim 3"));
+	_tileKyanite = new GUI::RadiobuttonWidget(this, "MapGenerator.TilesetKyanite", _tileGroup, 4, Common::U32String("Kyanite"));
+	if (!demo)
+		_tileEmerau = new GUI::RadiobuttonWidget(this, "MapGenerator.TilesetEmerau", _tileGroup, 5, Common::U32String("Emerau Glyph"));
+	_tileAblation = new GUI::RadiobuttonWidget(this, "MapGenerator.TilesetAblation", _tileGroup, 6, Common::U32String("Ablation Land"));
+	// I18N: Random tileset
+	_tileRandom = new GUI::CheckboxWidget(this, "MapGenerator.TilesetRandom", _("Random"), _("Picks the map tileset randomly."), kTileRandCmd);
+
+	// I18N: Percentage of energy pools
+	_energyDesc = new GUI::StaticTextWidget(this, "MapGenerator.Energy", _("Energy"));
+	_energyDesc->setAlign(Graphics::kTextAlignCenter);
+	_energySlider = new GUI::SliderWidget(this, "MapGenerator.EnergySlider", Common::U32String(), kEnergyCmd);
+	_energySlider->setMinValue(0); _energySlider->setMaxValue(6);
+	// I18N: Energy slider label
+	_energyLabel = new GUI::StaticTextWidget(this, "MapGenerator.EnergySliderLabel", _("Scarce - Lots"), Common::U32String());
+	_energyLabel->setAlign(Graphics::kTextAlignCenter);
+
+
+	// I18N: Random percentage of energy pools
+	_energyRandom = new GUI::CheckboxWidget(this, "MapGenerator.EnergyRandom", _("Random"), _("Picks the random amount of energy pools."), kEnergyRandCmd);
+
+	// I18N: Percentage of terrain
+	_terrainDesc = new GUI::StaticTextWidget(this, "MapGenerator.Terrain", _("Terrain"));
+	_terrainDesc->setAlign(Graphics::kTextAlignCenter);
+	_terrainSlider = new GUI::SliderWidget(this, "MapGenerator.TerrainSlider", Common::U32String(), kTerrainCmd);
+	_terrainSlider->setMinValue(0); _terrainSlider->setMaxValue(6);
+	// I18N: Terrain slider label
+	_terrainLabel = new GUI::StaticTextWidget(this, "MapGenerator.TerrainSliderLabel", _("Barren - Rough"), Common::U32String());
+	_terrainLabel->setAlign(Graphics::kTextAlignCenter);
+
+	// I18N: Random percentage of terrain
+	_terrainRandom = new GUI::CheckboxWidget(this, "MapGenerator.TerrainRandom", _("Random"), _("Picks the random amount of terrain level."), kTerrainRandCmd);
+
+	// I18N: Percentage of water
+	_waterDesc = new GUI::StaticTextWidget(this, "MapGenerator.Water", _("Water"));
+	_waterDesc->setAlign(Graphics::kTextAlignCenter);
+	_waterSlider = new GUI::SliderWidget(this, "MapGenerator.WaterSlider", Common::U32String(), kWaterCmd);
+	_waterSlider->setMinValue(0); _waterSlider->setMaxValue(6);
+	// I18N: Water slider label
+	_waterLabel = new GUI::StaticTextWidget(this, "MapGenerator.WaterSliderLabel", _("Driest - Wettest"), Common::U32String());
+	_waterLabel->setAlign(Graphics::kTextAlignCenter);
+
+	// I18N: Random percentage of water
+	_waterRandom = new GUI::CheckboxWidget(this, "MapGenerator.WaterRandom", _("Random"), _("Picks the random amount of water."), kWaterRandCmd);
+
+	_cancelButton = new GUI::ButtonWidget(this, "MapGenerator.Cancel", _("Cancel"), Common::U32String(), kCancelCmd);
+	// I18N: Generate new map
+	_generateButton = new GUI::ButtonWidget(this, "MapGenerator.Generate", _("Generate"), Common::U32String(), kGenerateCmd);
+	refresh();
+}
+
+void MapGeneratorDialog::refresh() {
+	_refreshing = true;
+
+	//  ALGORITHM
+	bool randomAlgorithm = true;
+	if (ConfMan.hasKey("map_algorithm"))
+		randomAlgorithm = ConfMan.getInt("map_algorithm") == 0;
+
+	_algorGroup->setEnabled(!randomAlgorithm);
+	_algorRandom->setState(randomAlgorithm);
+
+	if (!randomAlgorithm)
+		_algorGroup->setValue(ConfMan.getInt("map_algorithm"));
+
+	// SIZE
+	bool randomSize = true;
+	if (ConfMan.hasKey("map_size"))
+		randomSize = ConfMan.getInt("map_size") == 0;
+
+	_sizeGroup->setEnabled(!randomSize);
+	_sizeRandom->setState(randomSize);
+
+	if (!randomSize)
+		_sizeGroup->setValue(ConfMan.getInt("map_size"));
+
+	// TILESET
+	bool randomTileset = true;
+	if (ConfMan.hasKey("map_tileset"))
+		randomTileset = ConfMan.getInt("map_tileset") == 0;
+
+	_tileGroup->setEnabled(!randomTileset);
+	_tileRandom->setState(randomTileset);
+
+	if (!randomTileset)
+		_tileGroup->setValue(ConfMan.getInt("map_tileset"));
+
+	// ENERGY
+	bool randomEnergy = true;
+	if (ConfMan.hasKey("map_energy"))
+		randomEnergy = ConfMan.getInt("map_energy") == -1;
+
+	_energySlider->setEnabled(!randomEnergy);
+	_energyRandom->setState(randomEnergy);
+
+	if (!randomEnergy)
+		_energySlider->setValue(ConfMan.getInt("map_energy"));
+	else if (ConfMan.hasKey("prev_map_energy"))
+		_energySlider->setValue(ConfMan.getInt("prev_map_energy"));
+	else
+		_energySlider->setValue(3);
+
+	// TERRAIN
+	bool randomTerrain = true;
+	if (ConfMan.hasKey("map_terrain"))
+		randomTerrain = ConfMan.getInt("map_terrain") == -1;
+
+	_terrainSlider->setEnabled(!randomTerrain);
+	_terrainRandom->setState(randomTerrain);
+
+	if (!randomTerrain)
+		_terrainSlider->setValue(ConfMan.getInt("map_terrain"));
+	else if (ConfMan.hasKey("prev_map_terrain"))
+		_terrainSlider->setValue(ConfMan.getInt("prev_map_terrain"));
+	else
+		_terrainSlider->setValue(3);
+
+
+	// WATER
+	bool randomWater = true;
+	if (ConfMan.hasKey("map_water"))
+		randomWater = ConfMan.getInt("map_water") == -1;
+
+	_waterSlider->setEnabled(!randomWater);
+	_waterRandom->setState(randomWater);
+
+	if (!randomWater)
+		_waterSlider->setValue(ConfMan.getInt("map_water"));
+	else if (ConfMan.hasKey("prev_map_water"))
+		_waterSlider->setValue(ConfMan.getInt("prev_map_water"));
+	else
+		_waterSlider->setValue(3);
+
+	drawDialog(GUI::kDrawLayerForeground);
+
+	_refreshing = false;
+}
+
+void MapGeneratorDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data) {
+	if (_refreshing)
+		return;
+
+	switch(cmd) {
+	case kAlgorCmd:
+		ConfMan.setInt("map_algorithm", data);
+		ConfMan.flushToDisk();
+		break;
+	case kAlgorRandCmd:
+		if (data == 1) {
+			if (ConfMan.hasKey("map_algorithm") && ConfMan.getInt("map_algorithm") != 0)
+				// Store previous value
+				ConfMan.setInt("prev_map_algorithm", ConfMan.getInt("map_algorithm"));
+			ConfMan.setInt("map_algorithm", 0);
+		} else {
+			// Restore previous value
+			int previousValue = SPIFF_GEN;
+			if (ConfMan.hasKey("prev_map_algorithm"))
+				previousValue = ConfMan.getInt("prev_map_algorithm");
+			ConfMan.setInt("map_algorithm", previousValue);
+		}
+
+		ConfMan.flushToDisk();
+		refresh();
+		break;
+	case kSizeCmd:
+		ConfMan.setInt("map_size", data);
+		ConfMan.flushToDisk();
+		break;
+	case kSizeRandCmd:
+		if (data == 1) {
+			if (ConfMan.hasKey("map_size") && ConfMan.getInt("map_size") != 0)
+				// Store previous value
+				ConfMan.setInt("prev_map_size", ConfMan.getInt("map_size"));
+			ConfMan.setInt("map_size", 0);
+		} else {
+			// Restore previous value
+			int previousValue = 4;
+			if (ConfMan.hasKey("prev_map_size"))
+				previousValue = ConfMan.getInt("prev_map_size");
+			ConfMan.setInt("map_size", previousValue);
+		}
+
+		ConfMan.flushToDisk();
+		refresh();
+		break;
+	case kTileCmd:
+		ConfMan.setInt("map_tileset", data);
+		ConfMan.flushToDisk();
+		break;
+	case kTileRandCmd:
+		if (data == 1) {
+			if (ConfMan.hasKey("map_tileset") && ConfMan.getInt("map_tileset") != 0)
+				// Store previous value
+				ConfMan.setInt("prev_map_tileset", ConfMan.getInt("map_tileset"));
+			ConfMan.setInt("map_tileset", 0);
+		} else {
+			// Restore previous value
+			int previousValue = 5;
+			if (ConfMan.hasKey("prev_map_tileset"))
+				previousValue = ConfMan.getInt("prev_map_tileset");
+			ConfMan.setInt("map_tileset", previousValue);
+		}
+
+		ConfMan.flushToDisk();
+		refresh();
+		break;
+	case kEnergyCmd:
+		ConfMan.setInt("map_energy", data);
+		ConfMan.flushToDisk();
+		break;
+	case kEnergyRandCmd:
+		if (data == 1) {
+			if (ConfMan.hasKey("map_energy") && ConfMan.getInt("map_energy") != -1)
+				// Store previous value
+				ConfMan.setInt("prev_map_energy", ConfMan.getInt("map_energy"));
+			ConfMan.setInt("map_energy", -1);
+		} else {
+			// Restore previous value
+			int previousValue = 3;
+			if (ConfMan.hasKey("prev_map_energy"))
+				previousValue = ConfMan.getInt("prev_map_energy");
+			ConfMan.setInt("map_energy", previousValue);
+		}
+
+		ConfMan.flushToDisk();
+		refresh();
+		break;
+	case kTerrainCmd:
+		ConfMan.setInt("map_terrain", data);
+		ConfMan.flushToDisk();
+		break;
+	case kTerrainRandCmd:
+		if (data == 1) {
+			if (ConfMan.hasKey("map_terrain") && ConfMan.getInt("map_terrain") != -1)
+				// Store previous value
+				ConfMan.setInt("prev_map_terrain", ConfMan.getInt("map_terrain"));
+			ConfMan.setInt("map_terrain", -1);
+		} else {
+			// Restore previous value
+			int previousValue = 3;
+			if (ConfMan.hasKey("prev_map_terrain"))
+				previousValue = ConfMan.getInt("prev_map_terrain");
+			ConfMan.setInt("map_terrain", previousValue);
+		}
+
+		ConfMan.flushToDisk();
+		refresh();
+		break;
+	case kWaterCmd:
+		ConfMan.setInt("map_water", data);
+		ConfMan.flushToDisk();
+		break;
+	case kWaterRandCmd:
+		if (data == 1) {
+			if (ConfMan.hasKey("map_water") && ConfMan.getInt("map_water") != -1)
+				// Store previous value
+				ConfMan.setInt("prev_map_water", ConfMan.getInt("map_water"));
+			ConfMan.setInt("map_water", -1);
+		} else {
+			// Restore previous value
+			int previousValue = 3;
+			if (ConfMan.hasKey("prev_map_water"))
+				previousValue = ConfMan.getInt("prev_map_water");
+			ConfMan.setInt("map_water", previousValue);
+		}
+
+		ConfMan.flushToDisk();
+		refresh();
+		break;
+	case kCancelCmd:
+		setResult(0);
+		close();
+		break;
+	case kGenerateCmd:
+		setResult(1);
+		close();
+		break;
+	default:
+		Dialog::handleCommand(sender, cmd, data);
+	}
+}
+
+} // End of namespace Scumm
diff --git a/engines/scumm/he/moonbase/dialog-mapgenerator.h b/engines/scumm/he/moonbase/dialog-mapgenerator.h
new file mode 100644
index 00000000000..4d14237b68e
--- /dev/null
+++ b/engines/scumm/he/moonbase/dialog-mapgenerator.h
@@ -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/>.
+ *
+ */
+
+#ifndef SCUMM_DIALOG_MAP_GENERATOR_H
+#define SCUMM_DIALOG_MAP_GENERATOR_H
+
+#include "gui/dialog.h"
+#include "gui/widget.h"
+
+namespace Scumm {
+
+class MapGeneratorDialog : public Dialog {
+public:
+	MapGeneratorDialog(bool demo);
+
+	void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data) override;
+
+private:
+	void refresh();
+	bool _refreshing;
+
+	GUI::StaticTextWidget *_dialogTitle;
+
+	GUI::StaticTextWidget *_algorDesc;
+	GUI::RadiobuttonGroup *_algorGroup;
+	GUI::RadiobuttonWidget *_algorSpiff;
+	GUI::RadiobuttonWidget *_algorKatton;
+	GUI::CheckboxWidget *_algorRandom;
+
+	GUI::StaticTextWidget *_sizeDesc;
+	GUI::RadiobuttonGroup *_sizeGroup;
+	GUI::RadiobuttonWidget *_sizeSmall;
+	GUI::RadiobuttonWidget *_sizeMedium;
+	GUI::RadiobuttonWidget *_sizeLarge;
+	GUI::RadiobuttonWidget *_sizeHuge;
+	GUI::RadiobuttonWidget *_sizeSAI;
+	GUI::RadiobuttonWidget *_sizeRidiculous;
+	GUI::RadiobuttonWidget *_sizeMax;
+	GUI::CheckboxWidget *_sizeRandom;
+
+	GUI::StaticTextWidget *_tileDesc;
+	GUI::RadiobuttonGroup *_tileGroup;
+	GUI::RadiobuttonWidget *_tileAblation;
+	GUI::RadiobuttonWidget *_tileEmerau;
+	GUI::RadiobuttonWidget *_tileKyanite;
+	GUI::RadiobuttonWidget *_tileDrijim;
+	GUI::RadiobuttonWidget *_tileZanateros;
+	GUI::RadiobuttonWidget *_tileTerrandra;
+	GUI::CheckboxWidget *_tileRandom;
+
+	GUI::StaticTextWidget *_energyDesc;
+	GUI::SliderWidget *_energySlider;
+	GUI::StaticTextWidget *_energyLabel;
+	GUI::CheckboxWidget *_energyRandom;
+
+	GUI::StaticTextWidget *_terrainDesc;
+	GUI::SliderWidget *_terrainSlider;
+	GUI::StaticTextWidget *_terrainLabel;
+	GUI::CheckboxWidget *_terrainRandom;
+
+	GUI::StaticTextWidget *_waterDesc;
+	GUI::SliderWidget *_waterSlider;
+	GUI::StaticTextWidget *_waterLabel;
+	GUI::CheckboxWidget *_waterRandom;
+
+	GUI::ButtonWidget *_cancelButton;
+	GUI::ButtonWidget *_generateButton;
+};
+
+} // End of namespace Scumm
+
+#endif
diff --git a/engines/scumm/module.mk b/engines/scumm/module.mk
index ff976ab027d..3d94bd012a6 100644
--- a/engines/scumm/module.mk
+++ b/engines/scumm/module.mk
@@ -175,6 +175,7 @@ MODULE_OBJS += \
 	he/moonbase/ai_tree.o \
 	he/moonbase/ai_types.o \
 	he/moonbase/ai_weapon.o \
+	he/moonbase/dialog-mapgenerator.o \
 	he/moonbase/map_katton.o \
 	he/moonbase/map_main.o \
 	he/moonbase/map_mif.o \
diff --git a/gui/ThemeEngine.h b/gui/ThemeEngine.h
index acc1b3d6be9..63403a5f539 100644
--- a/gui/ThemeEngine.h
+++ b/gui/ThemeEngine.h
@@ -36,7 +36,7 @@
 #include "graphics/pixelformat.h"
 
 
-#define SCUMMVM_THEME_VERSION_STR "SCUMMVM_STX0.9.15"
+#define SCUMMVM_THEME_VERSION_STR "SCUMMVM_STX0.9.16"
 
 class OSystem;
 
diff --git a/gui/themes/common/highres_layout.stx b/gui/themes/common/highres_layout.stx
index ba86bee9e5c..842d7ec8f45 100644
--- a/gui/themes/common/highres_layout.stx
+++ b/gui/themes/common/highres_layout.stx
@@ -2646,4 +2646,140 @@
 		</layout>
 	</dialog>
 
+	<dialog name = 'MapGenerator' overlays = 'screen_center' shading = 'dim'>
+		<layout type = 'vertical' padding = '8, 8, 8, 8' align = 'center'>
+			<widget name = 'Title'
+					width = '480'
+					height = 'Globals.Line.Height'
+					textalign = 'center'
+			/>
+			<layout type = 'horizontal' padding = '8, 8, 8, 8'>
+				<layout type = 'vertical' padding = '0, 0, 16, 16'>
+					<widget name = 'Algorithm'
+						type = 'OptionsLabel'
+					/>
+					<widget name = 'AlgorithmSpiff'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'AlgorithmKatton'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'AlgorithmRandom'
+						type = 'Checkbox'
+					/>
+				</layout>
+				<layout type = 'vertical' padding = '0, 0, 16, 16'>
+					<widget name = 'Size'
+						type = 'OptionsLabel'
+					/>
+					<widget name = 'SizeSmall'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'SizeMedium'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'SizeLarge'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'SizeHuge'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'SizeSAI'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'SizeRidiculous'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'SizeMax'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'SizeRandom'
+						type = 'Checkbox'
+					/>
+				</layout>
+				<layout type = 'vertical' padding = '0, 0, 16, 16'>
+					<widget name = 'Tileset'
+						type = 'OptionsLabel'
+					/>
+					<widget name = 'TilesetTerrandra'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'TilesetZanateros'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'TilesetDaijim'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'TilesetKyanite'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'TilesetEmerau'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'TilesetAblation'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'TilesetRandom'
+						type = 'Checkbox'
+					/>
+				</layout>
+			</layout>
+			<layout type = 'horizontal' padding = '8, 8, 8, 8'>
+				<layout type = 'vertical' padding = '0, 0, 16, 16'>
+					<widget name = 'Energy'
+						type = 'OptionsLabel'
+					/>
+					<widget name = 'EnergySlider'
+						type = 'Slider'
+						rtl = 'no'
+					/>
+					<widget name = 'EnergySliderLabel'
+							type = 'OptionsLabel'
+					/>
+					<widget name = 'EnergyRandom'
+						type = 'Checkbox'
+					/>
+				</layout>
+				<layout type = 'vertical' padding = '0, 0, 16, 16'>
+					<widget name = 'Terrain'
+						type = 'OptionsLabel'
+					/>
+					<widget name = 'TerrainSlider'
+						type = 'Slider'
+						rtl = 'no'
+					/>
+					<widget name = 'TerrainSliderLabel'
+							type = 'OptionsLabel'
+					/>
+					<widget name = 'TerrainRandom'
+						type = 'Checkbox'
+					/>
+				</layout>
+				<layout type = 'vertical' padding = '0, 0, 16, 16'>
+					<widget name = 'Water'
+						type = 'OptionsLabel'
+					/>
+					<widget name = 'WaterSlider'
+						type = 'Slider'
+						rtl = 'no'
+					/>
+					<widget name = 'WaterSliderLabel'
+							type = 'OptionsLabel'
+					/>
+					<widget name = 'WaterRandom'
+						type = 'Checkbox'
+					/>
+				</layout>
+			</layout>
+			<layout type = 'horizontal' padding = '8, 8, 8, 8'>
+				<widget name = 'Cancel'
+						type = 'Button'
+				/>
+				<widget name = 'Generate'
+						type = 'Button'
+				/>
+			</layout>
+		</layout>
+	</dialog>
+
 </layout_info>
diff --git a/gui/themes/common/lowres_layout.stx b/gui/themes/common/lowres_layout.stx
index 5d6d6f29090..732fa05caac 100644
--- a/gui/themes/common/lowres_layout.stx
+++ b/gui/themes/common/lowres_layout.stx
@@ -2461,4 +2461,140 @@
 		</layout>
 	</dialog>
 
+	<dialog name = 'MapGenerator' overlays = 'screen_center' shading = 'dim'>
+		<layout type = 'vertical' padding = '8, 8, 8, 8' align = 'center'>
+			<widget name = 'Title'
+					width = '480'
+					height = 'Globals.Line.Height'
+					textalign = 'center'
+			/>
+			<layout type = 'horizontal' padding = '8, 8, 8, 8'>
+				<layout type = 'vertical' padding = '0, 0, 16, 16'>
+					<widget name = 'Algorithm'
+						type = 'OptionsLabel'
+					/>
+					<widget name = 'AlgorithmSpiff'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'AlgorithmKatton'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'AlgorithmRandom'
+						type = 'Checkbox'
+					/>
+				</layout>
+				<layout type = 'vertical' padding = '0, 0, 16, 16'>
+					<widget name = 'Size'
+						type = 'OptionsLabel'
+					/>
+					<widget name = 'SizeSmall'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'SizeMedium'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'SizeLarge'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'SizeHuge'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'SizeSAI'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'SizeRidiculous'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'SizeMax'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'SizeRandom'
+						type = 'Checkbox'
+					/>
+				</layout>
+				<layout type = 'vertical' padding = '0, 0, 16, 16'>
+					<widget name = 'Tileset'
+						type = 'OptionsLabel'
+					/>
+					<widget name = 'TilesetTerrandra'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'TilesetZanateros'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'TilesetDaijim'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'TilesetKyanite'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'TilesetEmerau'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'TilesetAblation'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'TilesetRandom'
+						type = 'Checkbox'
+					/>
+				</layout>
+			</layout>
+			<layout type = 'horizontal' padding = '8, 8, 8, 8'>
+				<layout type = 'vertical' padding = '0, 0, 16, 16'>
+					<widget name = 'Energy'
+						type = 'OptionsLabel'
+					/>
+					<widget name = 'EnergySlider'
+						type = 'Slider'
+						rtl = 'no'
+					/>
+					<widget name = 'EnergySliderLabel'
+							type = 'OptionsLabel'
+					/>
+					<widget name = 'EnergyRandom'
+						type = 'Checkbox'
+					/>
+				</layout>
+				<layout type = 'vertical' padding = '0, 0, 16, 16'>
+					<widget name = 'Terrain'
+						type = 'OptionsLabel'
+					/>
+					<widget name = 'TerrainSlider'
+						type = 'Slider'
+						rtl = 'no'
+					/>
+					<widget name = 'TerrainSliderLabel'
+							type = 'OptionsLabel'
+					/>
+					<widget name = 'TerrainRandom'
+						type = 'Checkbox'
+					/>
+				</layout>
+				<layout type = 'vertical' padding = '0, 0, 16, 16'>
+					<widget name = 'Water'
+						type = 'OptionsLabel'
+					/>
+					<widget name = 'WaterSlider'
+						type = 'Slider'
+						rtl = 'no'
+					/>
+					<widget name = 'WaterSliderLabel'
+							type = 'OptionsLabel'
+					/>
+					<widget name = 'WaterRandom'
+						type = 'Checkbox'
+					/>
+				</layout>
+			</layout>
+			<layout type = 'horizontal' padding = '8, 8, 8, 8'>
+				<widget name = 'Cancel'
+						type = 'Button'
+				/>
+				<widget name = 'Generate'
+						type = 'Button'
+				/>
+			</layout>
+		</layout>
+	</dialog>
+
 </layout_info>
diff --git a/gui/themes/default.inc b/gui/themes/default.inc
index 2dcc27c0fb8..cc53c177be0 100644
--- a/gui/themes/default.inc
+++ b/gui/themes/default.inc
@@ -3600,6 +3600,141 @@ const char *defaultXML1 = "<?xml version = '1.0'?>"
 "</layout>"
 "</layout>"
 "</dialog>"
+"<dialog name='MapGenerator' overlays='screen_center' shading='dim'>"
+"<layout type='vertical' padding='8,8,8,8' align='center'>"
+"<widget name='Title' "
+"width='480' "
+"height='Globals.Line.Height' "
+"textalign='center' "
+"/>"
+"<layout type='horizontal' padding='8,8,8,8'>"
+"<layout type='vertical' padding='0,0,16,16'>"
+"<widget name='Algorithm' "
+"type='OptionsLabel' "
+"/>"
+"<widget name='AlgorithmSpiff' "
+"type='Radiobutton' "
+"/>"
+"<widget name='AlgorithmKatton' "
+"type='Radiobutton' "
+"/>"
+"<widget name='AlgorithmRandom' "
+"type='Checkbox' "
+"/>"
+"</layout>"
+"<layout type='vertical' padding='0,0,16,16'>"
+"<widget name='Size' "
+"type='OptionsLabel' "
+"/>"
+"<widget name='SizeSmall' "
+"type='Radiobutton' "
+"/>"
+"<widget name='SizeMedium' "
+"type='Radiobutton' "
+"/>"
+"<widget name='SizeLarge' "
+"type='Radiobutton' "
+"/>"
+"<widget name='SizeHuge' "
+"type='Radiobutton' "
+"/>"
+"<widget name='SizeSAI' "
+"type='Radiobutton' "
+"/>"
+"<widget name='SizeRidiculous' "
+"type='Radiobutton' "
+"/>"
+"<widget name='SizeMax' "
+"type='Radiobutton' "
+"/>"
+"<widget name='SizeRandom' "
+"type='Checkbox' "
+"/>"
+"</layout>"
+"<layout type='vertical' padding='0,0,16,16'>"
+"<widget name='Tileset' "
+"type='OptionsLabel' "
+"/>"
+"<widget name='TilesetTerrandra' "
+"type='Radiobutton' "
+"/>"
+"<widget name='TilesetZanateros' "
+"type='Radiobutton' "
+"/>"
+"<widget name='TilesetDaijim' "
+"type='Radiobutton' "
+"/>"
+"<widget name='TilesetKyanite' "
+"type='Radiobutton' "
+"/>"
+"<widget name='TilesetEmerau' "
+"type='Radiobutton' "
+"/>"
+"<widget name='TilesetAblation' "
+"type='Radiobutton' "
+"/>"
+"<widget name='TilesetRandom' "
+"type='Checkbox' "
+"/>"
+"</layout>"
+"</layout>"
+"<layout type='horizontal' padding='8,8,8,8'>"
+"<layout type='vertical' padding='0,0,16,16'>"
+"<widget name='Energy' "
+"type='OptionsLabel' "
+"/>"
+"<widget name='EnergySlider' "
+"type='Slider' "
+"rtl='no' "
+"/>"
+"<widget name='EnergySliderLabel' "
+"type='OptionsLabel' "
+"/>"
+"<widget name='EnergyRandom' "
+"type='Checkbox' "
+"/>"
+"</layout>"
+"<layout type='vertical' padding='0,0,16,16'>"
+"<widget name='Terrain' "
+"type='OptionsLabel' "
+"/>"
+"<widget name='TerrainSlider' "
+"type='Slider' "
+"rtl='no' "
+"/>"
+"<widget name='TerrainSliderLabel' "
+"type='OptionsLabel' "
+"/>"
+"<widget name='TerrainRandom' "
+"type='Checkbox' "
+"/>"
+"</layout>"
+"<layout type='vertical' padding='0,0,16,16'>"
+"<widget name='Water' "
+"type='OptionsLabel' "
+"/>"
+"<widget name='WaterSlider' "
+"type='Slider' "
+"rtl='no' "
+"/>"
+"<widget name='WaterSliderLabel' "
+"type='OptionsLabel' "
+"/>"
+"<widget name='WaterRandom' "
+"type='Checkbox' "
+"/>"
+"</layout>"
+"</layout>"
+"<layout type='horizontal' padding='8,8,8,8'>"
+"<widget name='Cancel' "
+"type='Button' "
+"/>"
+"<widget name='Generate' "
+"type='Button' "
+"/>"
+"</layout>"
+"</layout>"
+"</dialog>"
 "</layout_info>"
 ;
  const char *defaultXML4 = "<layout_info resolution='y<H'>"
@@ -5739,6 +5874,141 @@ const char *defaultXML1 = "<?xml version = '1.0'?>"
 "</layout>"
 "</layout>"
 "</dialog>"
+"<dialog name='MapGenerator' overlays='screen_center' shading='dim'>"
+"<layout type='vertical' padding='8,8,8,8' align='center'>"
+"<widget name='Title' "
+"width='480' "
+"height='Globals.Line.Height' "
+"textalign='center' "
+"/>"
+"<layout type='horizontal' padding='8,8,8,8'>"
+"<layout type='vertical' padding='0,0,16,16'>"
+"<widget name='Algorithm' "
+"type='OptionsLabel' "
+"/>"
+"<widget name='AlgorithmSpiff' "
+"type='Radiobutton' "
+"/>"
+"<widget name='AlgorithmKatton' "
+"type='Radiobutton' "
+"/>"
+"<widget name='AlgorithmRandom' "
+"type='Checkbox' "
+"/>"
+"</layout>"
+"<layout type='vertical' padding='0,0,16,16'>"
+"<widget name='Size' "
+"type='OptionsLabel' "
+"/>"
+"<widget name='SizeSmall' "
+"type='Radiobutton' "
+"/>"
+"<widget name='SizeMedium' "
+"type='Radiobutton' "
+"/>"
+"<widget name='SizeLarge' "
+"type='Radiobutton' "
+"/>"
+"<widget name='SizeHuge' "
+"type='Radiobutton' "
+"/>"
+"<widget name='SizeSAI' "
+"type='Radiobutton' "
+"/>"
+"<widget name='SizeRidiculous' "
+"type='Radiobutton' "
+"/>"
+"<widget name='SizeMax' "
+"type='Radiobutton' "
+"/>"
+"<widget name='SizeRandom' "
+"type='Checkbox' "
+"/>"
+"</layout>"
+"<layout type='vertical' padding='0,0,16,16'>"
+"<widget name='Tileset' "
+"type='OptionsLabel' "
+"/>"
+"<widget name='TilesetTerrandra' "
+"type='Radiobutton' "
+"/>"
+"<widget name='TilesetZanateros' "
+"type='Radiobutton' "
+"/>"
+"<widget name='TilesetDaijim' "
+"type='Radiobutton' "
+"/>"
+"<widget name='TilesetKyanite' "
+"type='Radiobutton' "
+"/>"
+"<widget name='TilesetEmerau' "
+"type='Radiobutton' "
+"/>"
+"<widget name='TilesetAblation' "
+"type='Radiobutton' "
+"/>"
+"<widget name='TilesetRandom' "
+"type='Checkbox' "
+"/>"
+"</layout>"
+"</layout>"
+"<layout type='horizontal' padding='8,8,8,8'>"
+"<layout type='vertical' padding='0,0,16,16'>"
+"<widget name='Energy' "
+"type='OptionsLabel' "
+"/>"
+"<widget name='EnergySlider' "
+"type='Slider' "
+"rtl='no' "
+"/>"
+"<widget name='EnergySliderLabel' "
+"type='OptionsLabel' "
+"/>"
+"<widget name='EnergyRandom' "
+"type='Checkbox' "
+"/>"
+"</layout>"
+"<layout type='vertical' padding='0,0,16,16'>"
+"<widget name='Terrain' "
+"type='OptionsLabel' "
+"/>"
+"<widget name='TerrainSlider' "
+"type='Slider' "
+"rtl='no' "
+"/>"
+"<widget name='TerrainSliderLabel' "
+"type='OptionsLabel' "
+"/>"
+"<widget name='TerrainRandom' "
+"type='Checkbox' "
+"/>"
+"</layout>"
+"<layout type='vertical' padding='0,0,16,16'>"
+"<widget name='Water' "
+"type='OptionsLabel' "
+"/>"
+"<widget name='WaterSlider' "
+"type='Slider' "
+"rtl='no' "
+"/>"
+"<widget name='WaterSliderLabel' "
+"type='OptionsLabel' "
+"/>"
+"<widget name='WaterRandom' "
+"type='Checkbox' "
+"/>"
+"</layout>"
+"</layout>"
+"<layout type='horizontal' padding='8,8,8,8'>"
+"<widget name='Cancel' "
+"type='Button' "
+"/>"
+"<widget name='Generate' "
+"type='Button' "
+"/>"
+"</layout>"
+"</layout>"
+"</dialog>"
 "</layout_info>"
 ;
 const char *defaultXML[] = { defaultXML1, defaultXML2, defaultXML3, defaultXML4 };
diff --git a/gui/themes/residualvm.zip b/gui/themes/residualvm.zip
index 356919cda76..eb2429c93e0 100644
Binary files a/gui/themes/residualvm.zip and b/gui/themes/residualvm.zip differ
diff --git a/gui/themes/residualvm/THEMERC b/gui/themes/residualvm/THEMERC
index a249028486e..132659d2bf5 100644
--- a/gui/themes/residualvm/THEMERC
+++ b/gui/themes/residualvm/THEMERC
@@ -1,3 +1,3 @@
-[SCUMMVM_STX0.9.15:ResidualVM Modern Theme Remastered:No Author]
+[SCUMMVM_STX0.9.16:ResidualVM Modern Theme Remastered:No Author]
 %using ../common
 %using ../common-svg
diff --git a/gui/themes/scummclassic.zip b/gui/themes/scummclassic.zip
index 93c6e330144..40fcaa32f7e 100644
Binary files a/gui/themes/scummclassic.zip and b/gui/themes/scummclassic.zip differ
diff --git a/gui/themes/scummclassic/THEMERC b/gui/themes/scummclassic/THEMERC
index 43910d47daf..415cdd8ed7d 100644
--- a/gui/themes/scummclassic/THEMERC
+++ b/gui/themes/scummclassic/THEMERC
@@ -1 +1 @@
-[SCUMMVM_STX0.9.15:ScummVM Classic Theme:No Author]
+[SCUMMVM_STX0.9.16:ScummVM Classic Theme:No Author]
diff --git a/gui/themes/scummclassic/classic_layout.stx b/gui/themes/scummclassic/classic_layout.stx
index 21f56690975..b6e1ba97589 100644
--- a/gui/themes/scummclassic/classic_layout.stx
+++ b/gui/themes/scummclassic/classic_layout.stx
@@ -2291,4 +2291,140 @@
 		</layout>
 	</dialog>
 
+	<dialog name = 'MapGenerator' overlays = 'screen_center' shading = 'dim'>
+		<layout type = 'vertical' padding = '8, 8, 8, 8' align = 'center'>
+			<widget name = 'Title'
+					width = '480'
+					height = 'Globals.Line.Height'
+					textalign = 'center'
+			/>
+			<layout type = 'horizontal' padding = '8, 8, 8, 8'>
+				<layout type = 'vertical' padding = '0, 0, 16, 16'>
+					<widget name = 'Algorithm'
+						type = 'OptionsLabel'
+					/>
+					<widget name = 'AlgorithmSpiff'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'AlgorithmKatton'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'AlgorithmRandom'
+						type = 'Checkbox'
+					/>
+				</layout>
+				<layout type = 'vertical' padding = '0, 0, 16, 16'>
+					<widget name = 'Size'
+						type = 'OptionsLabel'
+					/>
+					<widget name = 'SizeSmall'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'SizeMedium'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'SizeLarge'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'SizeHuge'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'SizeSAI'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'SizeRidiculous'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'SizeMax'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'SizeRandom'
+						type = 'Checkbox'
+					/>
+				</layout>
+				<layout type = 'vertical' padding = '0, 0, 16, 16'>
+					<widget name = 'Tileset'
+						type = 'OptionsLabel'
+					/>
+					<widget name = 'TilesetTerrandra'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'TilesetZanateros'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'TilesetDaijim'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'TilesetKyanite'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'TilesetEmerau'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'TilesetAblation'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'TilesetRandom'
+						type = 'Checkbox'
+					/>
+				</layout>
+			</layout>
+			<layout type = 'horizontal' padding = '8, 8, 8, 8'>
+				<layout type = 'vertical' padding = '0, 0, 16, 16'>
+					<widget name = 'Energy'
+						type = 'OptionsLabel'
+					/>
+					<widget name = 'EnergySlider'
+						type = 'Slider'
+						rtl = 'no'
+					/>
+					<widget name = 'EnergySliderLabel'
+							type = 'OptionsLabel'
+					/>
+					<widget name = 'EnergyRandom'
+						type = 'Checkbox'
+					/>
+				</layout>
+				<layout type = 'vertical' padding = '0, 0, 16, 16'>
+					<widget name = 'Terrain'
+						type = 'OptionsLabel'
+					/>
+					<widget name = 'TerrainSlider'
+						type = 'Slider'
+						rtl = 'no'
+					/>
+					<widget name = 'TerrainSliderLabel'
+							type = 'OptionsLabel'
+					/>
+					<widget name = 'TerrainRandom'
+						type = 'Checkbox'
+					/>
+				</layout>
+				<layout type = 'vertical' padding = '0, 0, 16, 16'>
+					<widget name = 'Water'
+						type = 'OptionsLabel'
+					/>
+					<widget name = 'WaterSlider'
+						type = 'Slider'
+						rtl = 'no'
+					/>
+					<widget name = 'WaterSliderLabel'
+							type = 'OptionsLabel'
+					/>
+					<widget name = 'WaterRandom'
+						type = 'Checkbox'
+					/>
+				</layout>
+			</layout>
+			<layout type = 'horizontal' padding = '8, 8, 8, 8'>
+				<widget name = 'Cancel'
+						type = 'Button'
+				/>
+				<widget name = 'Generate'
+						type = 'Button'
+				/>
+			</layout>
+		</layout>
+	</dialog>
+
 </layout_info>
diff --git a/gui/themes/scummclassic/classic_layout_lowres.stx b/gui/themes/scummclassic/classic_layout_lowres.stx
index 6fee29b269d..1e160680d79 100644
--- a/gui/themes/scummclassic/classic_layout_lowres.stx
+++ b/gui/themes/scummclassic/classic_layout_lowres.stx
@@ -2268,4 +2268,140 @@
 		</layout>
 	</dialog>
 
+	<dialog name = 'MapGenerator' overlays = 'screen_center' shading = 'dim'>
+		<layout type = 'vertical' padding = '8, 8, 8, 8' align = 'center'>
+			<widget name = 'Title'
+					width = '480'
+					height = 'Globals.Line.Height'
+					textalign = 'center'
+			/>
+			<layout type = 'horizontal' padding = '8, 8, 8, 8'>
+				<layout type = 'vertical' padding = '0, 0, 16, 16'>
+					<widget name = 'Algorithm'
+						type = 'OptionsLabel'
+					/>
+					<widget name = 'AlgorithmSpiff'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'AlgorithmKatton'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'AlgorithmRandom'
+						type = 'Checkbox'
+					/>
+				</layout>
+				<layout type = 'vertical' padding = '0, 0, 16, 16'>
+					<widget name = 'Size'
+						type = 'OptionsLabel'
+					/>
+					<widget name = 'SizeSmall'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'SizeMedium'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'SizeLarge'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'SizeHuge'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'SizeSAI'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'SizeRidiculous'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'SizeMax'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'SizeRandom'
+						type = 'Checkbox'
+					/>
+				</layout>
+				<layout type = 'vertical' padding = '0, 0, 16, 16'>
+					<widget name = 'Tileset'
+						type = 'OptionsLabel'
+					/>
+					<widget name = 'TilesetTerrandra'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'TilesetZanateros'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'TilesetDaijim'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'TilesetKyanite'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'TilesetEmerau'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'TilesetAblation'
+						type = 'Radiobutton'
+					/>
+					<widget name = 'TilesetRandom'
+						type = 'Checkbox'
+					/>
+				</layout>
+			</layout>
+			<layout type = 'horizontal' padding = '8, 8, 8, 8'>
+				<layout type = 'vertical' padding = '0, 0, 16, 16'>
+					<widget name = 'Energy'
+						type = 'OptionsLabel'
+					/>
+					<widget name = 'EnergySlider'
+						type = 'Slider'
+						rtl = 'no'
+					/>
+					<widget name = 'EnergySliderLabel'
+							type = 'OptionsLabel'
+					/>
+					<widget name = 'EnergyRandom'
+						type = 'Checkbox'
+					/>
+				</layout>
+				<layout type = 'vertical' padding = '0, 0, 16, 16'>
+					<widget name = 'Terrain'
+						type = 'OptionsLabel'
+					/>
+					<widget name = 'TerrainSlider'
+						type = 'Slider'
+						rtl = 'no'
+					/>
+					<widget name = 'TerrainSliderLabel'
+							type = 'OptionsLabel'
+					/>
+					<widget name = 'TerrainRandom'
+						type = 'Checkbox'
+					/>
+				</layout>
+				<layout type = 'vertical' padding = '0, 0, 16, 16'>
+					<widget name = 'Water'
+						type = 'OptionsLabel'
+					/>
+					<widget name = 'WaterSlider'
+						type = 'Slider'
+						rtl = 'no'
+					/>
+					<widget name = 'WaterSliderLabel'
+							type = 'OptionsLabel'
+					/>
+					<widget name = 'WaterRandom'
+						type = 'Checkbox'
+					/>
+				</layout>
+			</layout>
+			<layout type = 'horizontal' padding = '8, 8, 8, 8'>
+				<widget name = 'Cancel'
+						type = 'Button'
+				/>
+				<widget name = 'Generate'
+						type = 'Button'
+				/>
+			</layout>
+		</layout>
+	</dialog>
+
 </layout_info>
diff --git a/gui/themes/scummmodern.zip b/gui/themes/scummmodern.zip
index 0ffee7668ec..ac81bc9ddff 100644
Binary files a/gui/themes/scummmodern.zip and b/gui/themes/scummmodern.zip differ
diff --git a/gui/themes/scummmodern/THEMERC b/gui/themes/scummmodern/THEMERC
index a61788da058..17da4808d16 100644
--- a/gui/themes/scummmodern/THEMERC
+++ b/gui/themes/scummmodern/THEMERC
@@ -1,2 +1,2 @@
-[SCUMMVM_STX0.9.15:ScummVM Modern Theme:No Author]
+[SCUMMVM_STX0.9.16:ScummVM Modern Theme:No Author]
 %using ../common
diff --git a/gui/themes/scummremastered.zip b/gui/themes/scummremastered.zip
index e07defb1436..fe542ca3323 100644
Binary files a/gui/themes/scummremastered.zip and b/gui/themes/scummremastered.zip differ
diff --git a/gui/themes/scummremastered/THEMERC b/gui/themes/scummremastered/THEMERC
index b973a46c7da..7c4f21621a7 100644
--- a/gui/themes/scummremastered/THEMERC
+++ b/gui/themes/scummremastered/THEMERC
@@ -1,3 +1,3 @@
-[SCUMMVM_STX0.9.15:ScummVM Modern Theme Remastered:No Author]
+[SCUMMVM_STX0.9.16:ScummVM Modern Theme Remastered:No Author]
 %using ../common
 %using ../common-svg


Commit: 289e181de0493f1d2f38e917854f285d43f380f6
    https://github.com/scummvm/scummvm/commit/289e181de0493f1d2f38e917854f285d43f380f6
Author: Little Cat (toontownlittlecat at gmail.com)
Date: 2024-05-12T15:08:27+02:00

Commit Message:
SCUMM HE: Use new map generator dialog.

Changed paths:
    engines/scumm/he/intern_he.h
    engines/scumm/he/moonbase/map_main.cpp
    engines/scumm/scumm.cpp


diff --git a/engines/scumm/he/intern_he.h b/engines/scumm/he/intern_he.h
index 73e926bf5c0..b3dbd56e873 100644
--- a/engines/scumm/he/intern_he.h
+++ b/engines/scumm/he/intern_he.h
@@ -1103,6 +1103,9 @@ protected:
 	byte VAR_REMOTE_START_SCRIPT;
 	byte VAR_NETWORK_AVAILABLE;
 	byte VAR_NETWORK_RECEIVE_ARRAY_SCRIPT;
+
+public:
+	bool mapGeneratorDialog(bool demo);
 };
 
 class ScummEngine_vCUPhe : public Engine {
diff --git a/engines/scumm/he/moonbase/map_main.cpp b/engines/scumm/he/moonbase/map_main.cpp
index 09a77320e40..71113f73dd8 100644
--- a/engines/scumm/he/moonbase/map_main.cpp
+++ b/engines/scumm/he/moonbase/map_main.cpp
@@ -49,27 +49,80 @@ Map::~Map() {
 }
 
 bool Map::generateNewMap() {
+	deleteMap();
+
 	if (!ConfMan.getBool("generate_random_maps"))
 		return false;
 
-	// TODO: Show a dialog allowing the user to customize options.
+	// Show a dialog allowing the user to customize options.
+	if (!_vm->mapGeneratorDialog(!strcmp(_vm->_game.variant, "Demo")))
+		// They have clicked cancel, abort.
+		return false;
 
 	// Create a new seed just for the below values.  This is to
 	// ensure these are truely random after generating a previous
 	// map (or to debug with a prefixed seed).
 	_rnd.generateNewSeed();
 
-	// Don't randomly pick nonstandard map sizes.
-	int mapSize = _rnd.getRandomNumberRngSigned(4, 8) * 8;
-
-	uint8 generator = _rnd.getRandomNumberRng(1, 2);
-
-	int tileSet = _rnd.getRandomNumberRngSigned(1, 6);
+	int mapSize = 0;
+	if (ConfMan.hasKey("map_size"))
+		mapSize = ConfMan.getInt("map_size");
+	if (mapSize < 4 || mapSize > 10)
+		// Don't randomly pick nonstandard map sizes.
+		mapSize = _rnd.getRandomNumberRngSigned(4, 8);
+
+	mapSize *= 8;
+
+	uint8 generator = 0;
+	if (ConfMan.hasKey("map_algorithm"))
+		generator = ConfMan.getInt("map_algorithm");
+	if (generator < SPIFF_GEN || generator > KATTON_GEN)
+		generator = _rnd.getRandomNumberRng(1, 2);
+
+	int tileSet = 0;
+	if (ConfMan.hasKey("map_tileset"))
+		tileSet = ConfMan.getInt("map_tileset");
+	if (tileSet < 1 || tileSet > 6)
+		tileSet = _rnd.getRandomNumberRngSigned(1, 6);
+
+	if (!strcmp(_vm->_game.variant, "Demo") && (tileSet == 1 ||
+		tileSet == 3 || tileSet == 5)) {
+		// Demo version only has tilesets 1, 2, 4 and 6.
+		switch (_rnd.getRandomNumber(3)) {
+		case 0:
+			tileSet = 1;
+			break;
+		case 1:
+			tileSet = 2;
+			break;
+		case 2:
+			tileSet = 4;
+			break;
+		default:
+			tileSet = 6;
+		}
+	}
 
-	// Only use [2, 3, 4] of the legal [0, 1, 2, 3, 4, 5, 6]
-	int energy = _rnd.getRandomNumberRngSigned(2, 4);
-	int terrain = _rnd.getRandomNumberRngSigned(2, 4);
-	int water = _rnd.getRandomNumberRngSigned(2, 4);
+	int energy = -1;
+	if (ConfMan.hasKey("map_energy"))
+		energy = ConfMan.getInt("map_energy");
+	if (energy < 0 || energy > 6)
+		// Only use [2, 3, 4] of the legal [0, 1, 2, 3, 4, 5, 6]
+		energy = _rnd.getRandomNumberRngSigned(2, 4);
+
+	int terrain = -1;
+	if (ConfMan.hasKey("map_terrain"))
+		terrain = ConfMan.getInt("map_terrain");
+	if (terrain < 0 || terrain > 6)
+		// Only use [2, 3, 4] of the legal [0, 1, 2, 3, 4, 5, 6]
+		terrain = _rnd.getRandomNumberRngSigned(2, 4);
+
+	int water = -1;
+	if (ConfMan.hasKey("map_water"))
+		water = ConfMan.getInt("map_water");
+	if (water < 0 || water > 6)
+		// Only use [2, 3, 4] of the legal [0, 1, 2, 3, 4, 5, 6]
+		water = _rnd.getRandomNumberRngSigned(2, 4);
 
 	// 32767 is RAND_MAX on Windows
 	int seed = _rnd.getRandomNumber(32767);
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index 2cd845aa753..61b5b018ab8 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -99,6 +99,8 @@
 #include "scumm/he/net/net_lobby.h"
 #endif
 #endif
+
+#include "scumm/he/moonbase/dialog-mapgenerator.h"
 #endif
 
 #include "backends/audiocd/audiocd.h"
@@ -3923,6 +3925,15 @@ int ScummEngine_v90he::networkSessionDialog() {
 }
 #endif
 
+#ifdef ENABLE_HE
+bool ScummEngine_v100he::mapGeneratorDialog(bool demo) {
+	// Runs the map generator options dialog
+	// for Moonbase Commander.
+	MapGeneratorDialog dialog(demo);
+	return runDialog(dialog) == 1;
+}
+#endif
+
 #pragma mark -
 #pragma mark --- Miscellaneous ---
 #pragma mark -


Commit: 71d2c5ff6137d6f2cd16ddf1072e9de68b99f0d0
    https://github.com/scummvm/scummvm/commit/71d2c5ff6137d6f2cd16ddf1072e9de68b99f0d0
Author: Little Cat (toontownlittlecat at gmail.com)
Date: 2024-05-12T15:08:27+02:00

Commit Message:
SCUMM HE: Add map generator dialog to POTFILES.

Changed paths:
    engines/scumm/POTFILES


diff --git a/engines/scumm/POTFILES b/engines/scumm/POTFILES
index b2edbba9b75..bd1bfda09f2 100644
--- a/engines/scumm/POTFILES
+++ b/engines/scumm/POTFILES
@@ -8,5 +8,6 @@ engines/scumm/input.cpp
 engines/scumm/metaengine.cpp
 engines/scumm/saveload.cpp
 engines/scumm/scumm.cpp
+engines/scumm/he/moonbase/dialog-mapgenerator.cpp
 engines/scumm/he/sound_he.cpp
 engines/scumm/imuse/drivers/amiga.cpp


Commit: f4c94c7b3ae61890cc11cc539b241ead51ce67d1
    https://github.com/scummvm/scummvm/commit/f4c94c7b3ae61890cc11cc539b241ead51ce67d1
Author: Little Cat (toontownlittlecat at gmail.com)
Date: 2024-05-12T15:08:27+02:00

Commit Message:
SCUMM HE: Hook up map generator to multiplayer.

Changed paths:
    engines/scumm/he/moonbase/map_main.cpp
    engines/scumm/he/moonbase/map_main.h
    engines/scumm/he/net/net_main.cpp
    engines/scumm/he/net/net_main.h
    engines/scumm/he/script_v100he.cpp


diff --git a/engines/scumm/he/moonbase/map_main.cpp b/engines/scumm/he/moonbase/map_main.cpp
index 71113f73dd8..13c155a6a7c 100644
--- a/engines/scumm/he/moonbase/map_main.cpp
+++ b/engines/scumm/he/moonbase/map_main.cpp
@@ -39,9 +39,13 @@ Map::Map(ScummEngine_v100he *vm) : _vm(vm), _rnd("moonbase") {
 	_mapGenerated = false;
 	_generatedMap = nullptr;
 
-	_energy = 0;
-	_terrain = 0;
-	_water = 0;
+	_generator = 0;
+	_size = 0;
+	_seed = 0;
+	_tileset = 0;
+	_energy = -1;
+	_terrain = -1;
+	_water = -1;
 }
 
 Map::~Map() {
@@ -133,7 +137,13 @@ bool Map::generateNewMap() {
 bool Map::generateMapWithInfo(uint8 generator, int seed, int mapSize, int tileset, int energy, int terrain, int water) {
 	deleteMap();
 
+	_generator = generator;
 	_seed = seed;
+	_size = mapSize;
+	_tileset = tileset;
+	_energy = energy;
+	_terrain = terrain;
+	_water = water;
 
 	debug(1, "Map: Generating new map with info: generator = %d, seed = %d, mapSize = %d, tileset = %d , energy = %d, terrain = %d, water = %d.", generator, getSeed(), mapSize, tileset, energy, terrain, water);
 	switch (generator) {
@@ -154,11 +164,6 @@ bool Map::generateMapWithInfo(uint8 generator, int seed, int mapSize, int tilese
 		return false;
 	}
 
-	// Store these for wiz generation.
-	_energy = energy;
-	_terrain = terrain;
-	_water = water;
-
 	_mapGenerated = true;
 	return true;
 }
@@ -167,8 +172,16 @@ void Map::deleteMap() {
 	if (_mapGenerated) {
 		// Delete old map.
 		delete _generatedMap;
+		_generatedMap = nullptr;
 
 		_mapGenerated = false;
+		_generator = 0;
+		_size = 0;
+		_seed = 0;
+		_tileset = 0;
+		_energy = 0;
+		_terrain = 0;
+		_water = 0;
 		debug(1, "Map: Deleted.");
 	}
 }
diff --git a/engines/scumm/he/moonbase/map_main.h b/engines/scumm/he/moonbase/map_main.h
index 567d3a33bf3..0f26e4a405d 100644
--- a/engines/scumm/he/moonbase/map_main.h
+++ b/engines/scumm/he/moonbase/map_main.h
@@ -45,10 +45,34 @@ public:
 
 	void deleteMap();
 
-	uint32 getSeed() const {
+	uint8 getGenerator() const {
+		return _generator;
+	}
+
+	int getSize() const {
+		return _size;
+	}
+
+	int getSeed() const {
 		return _seed;
 	}
 
+	int getTileset() const {
+		return _tileset;
+	}
+
+	int getEnergy() const {
+		return _energy;
+	}
+
+	int getTerrain() const {
+		return _terrain;
+	}
+
+	int getWater() const {
+		return _water;
+	}
+
 	bool mapGenerated() const {
 		return _mapGenerated;
 	}
@@ -61,15 +85,17 @@ private:
 	// they're playing on the same generated map.
 	Common::RandomSource _rnd;
 
+	uint8 _generator;
+	int _size;
 	int _seed;
+	int _tileset;
+	int _energy;
+	int _terrain;
+	int _water;
 
 	bool _mapGenerated;
 	MapFile *_generatedMap;
 
-	// Data for makeWiz:
-	int _energy;
-	int _terrain;
-	int _water;
 	Common::SeekableReadStream *makeWiz();
 };
 
diff --git a/engines/scumm/he/net/net_main.cpp b/engines/scumm/he/net/net_main.cpp
index b550a771284..3a124cefd76 100644
--- a/engines/scumm/he/net/net_main.cpp
+++ b/engines/scumm/he/net/net_main.cpp
@@ -23,6 +23,11 @@
 #include "common/config-manager.h"
 
 #include "scumm/he/intern_he.h"
+
+// For random map generation
+#include "scumm/he/moonbase/moonbase.h"
+#include "scumm/he/moonbase/map_main.h"
+
 #include "scumm/he/net/net_main.h"
 #include "scumm/he/net/net_defines.h"
 
@@ -69,6 +74,14 @@ Net::Net(ScummEngine_v90he *vm) : _latencyTime(1), _fakeLatency(false), _vm(vm)
 	_sessionName = Common::String();
 	_sessions = Common::Array<Session>();
 
+	_mapGenerator = 0;
+	_mapSeed = 0;
+	_mapSize = 0;
+	_mapTileset = 0;
+	_mapEnergy = 0;
+	_mapTerrain = 0;
+	_mapWater = 0;
+
 	_hostPort = 0;
 
 	_hostDataQueue = Common::Queue<Common::JSONValue *>();
@@ -169,6 +182,11 @@ int Net::joinGame(Common::String IP, char *userName) {
 			if (address.host == "255.255.255.255")
 				address.host = _sessions[0].host;
 			address.port = _sessions[0].port;
+
+			if (_gameName == "moonbase" && _sessions[0].mapGenerator > 0) {
+				// Generate the host's map.
+				_vm->_moonbase->_map->generateMapWithInfo(_sessions[0].mapGenerator, _sessions[0].mapSeed, _sessions[0].mapSize, _sessions[0].mapTileset, _sessions[0].mapEnergy, _sessions[0].mapTerrain, _sessions[0].mapWater);
+			}
 			stopQuerySessions();
 		}
 		// We got our address and port, attempt connection:
@@ -276,6 +294,24 @@ int Net::createSession(char *name) {
 
 	_isHost = true;
 
+	Common::String mapData = "{}";
+	if (_gameName == "moonbase") {
+		Map *map = _vm->_moonbase->_map;
+		if (map->generateNewMap()) {
+			// Store the configured map variables
+			_mapGenerator = map->getGenerator();
+			_mapSeed = map->getSeed();
+			_mapSize = map->getSize();
+			_mapTileset = map->getTileset();
+			_mapEnergy = map->getEnergy();
+			_mapTerrain = map->getTerrain();
+			_mapWater = map->getWater();
+			mapData = Common::String::format(
+				"{\"generator\":%d,\"seed\":%d,\"size\":%d,\"tileset\":%d,\"energy\":%d,\"terrain\":%d,\"water\":%d}",
+				_mapGenerator, _mapSeed, _mapSize, _mapTileset, _mapEnergy, _mapTerrain, _mapWater);
+		}
+	}
+
 	bool enableSessionServer = true;
 	bool enableLanBroadcast = true;
 	if (ConfMan.hasKey("enable_session_server"))
@@ -297,8 +333,8 @@ int Net::createSession(char *name) {
 			_sessionServerPeer = 0;
 			// Create session to the session server.
 			Common::String req = Common::String::format(
-				"{\"cmd\":\"host_session\",\"game\":\"%s\",\"version\":\"%s\",\"name\":\"%s\",\"maxplayers\":%d,\"scummvm_version\":\"%s\"}",
-				_gameName.c_str(), _gameVersion.c_str(), name, _maxPlayers, gScummVMFullVersion);
+				"{\"cmd\":\"host_session\",\"game\":\"%s\",\"version\":\"%s\",\"name\":\"%s\",\"maxplayers\":%d,\"scummvm_version\":\"%s\",\"map_data\":%s}",
+				_gameName.c_str(), _gameVersion.c_str(), name, _maxPlayers, gScummVMFullVersion, mapData.c_str());
 			debugC(DEBUG_NETWORK, "NETWORK: Sending to session server: %s", req.c_str());
 			_sessionHost->send(req.c_str(), _sessionServerPeer);
 		} else {
@@ -402,6 +438,11 @@ int Net::doJoinSession(Session session) {
 		return false;
 	}
 
+	if (_gameName == "moonbase" && session.mapGenerator > 0) {
+		// Generate the host's map.
+		_vm->_moonbase->_map->generateMapWithInfo(session.mapGenerator, session.mapSeed, session.mapSize, session.mapTileset, session.mapEnergy, session.mapTerrain, session.mapWater);
+	}
+
 	return true;
 }
 
@@ -478,6 +519,14 @@ int Net::endSession() {
 
 	_isRelayingGame = false;
 
+	_mapGenerator = 0;
+	_mapSeed = 0;
+	_mapSize = 0;
+	_mapTileset = 0;
+	_mapEnergy = 0;
+	_mapTerrain = 0;
+	_mapWater = 0;
+
 	return 1;
 }
 
@@ -958,6 +1007,22 @@ void Net::handleSessionServerData(Common::String data) {
 					session.host = sessionAddress.host;
 					session.port = sessionAddress.port;
 					session.timestamp = g_system->getMillis();
+
+					if (_gameName == "moonbase" && sessionData.contains("map_data")) {
+						Common::JSONObject mapData = sessionData["map_data"]->asObject();
+						if (mapData.contains("generator") && mapData.contains("seed") &&
+							mapData.contains("size") && mapData.contains("tileset") &&
+							mapData.contains("energy") && mapData.contains("terrain") &&
+							mapData.contains("water")) {
+							session.mapGenerator = mapData["generator"]->asIntegerNumber();
+							session.mapSeed = mapData["seed"]->asIntegerNumber();
+							session.mapSize = mapData["size"]->asIntegerNumber();
+							session.mapTileset = mapData["tileset"]->asIntegerNumber();
+							session.mapEnergy = mapData["energy"]->asIntegerNumber();
+							session.mapTerrain = mapData["terrain"]->asIntegerNumber();
+							session.mapWater = mapData["water"]->asIntegerNumber();
+						}
+					}
 					_sessions.push_back(session);
 				}
 				_gotSessions = true;
@@ -1059,9 +1124,16 @@ void Net::handleBroadcastData(Common::String data, Common::String host, int port
 		if (command == "get_session") {
 			// Session query.
 			if (_sessionHost) {
+				Common::String mapData = "{}";
+				if (_gameName == "moonbase" && _mapGenerator > 0) {
+					// Send over map data
+					mapData = Common::String::format(
+						"{\"generator\":%d,\"seed\":%d,\"size\":%d,\"tileset\":%d,\"energy\":%d,\"terrain\":%d,\"water\":%d}",
+						_mapGenerator, _mapSeed, _mapSize, _mapTileset, _mapEnergy, _mapTerrain, _mapWater);
+				}
 				Common::String resp = Common::String::format(
-					"{\"cmd\":\"session_resp\",\"game\":\"%s\",\"version\":\"%s\",\"id\":%d,\"name\":\"%s\",\"players\":%d}",
-					_gameName.c_str(), _gameVersion.c_str(), _sessionId, _sessionName.c_str(), getTotalPlayers());
+					"{\"cmd\":\"session_resp\",\"game\":\"%s\",\"version\":\"%s\",\"id\":%d,\"name\":\"%s\",\"players\":%d,\"map_data\":%s}",
+					_gameName.c_str(), _gameVersion.c_str(), _sessionId, _sessionName.c_str(), getTotalPlayers(), mapData.c_str());
 
 				// Send this through the session host instead of the broadcast socket
 				// because that will send the correct port to connect to.
@@ -1113,6 +1185,23 @@ void Net::handleBroadcastData(Common::String data, Common::String host, int port
 				session.name = name;
 				session.players = players;
 				session.timestamp = g_system->getMillis();
+
+				if (_gameName == "moonbase" && root.contains("map_data")) {
+					Common::JSONObject mapData = root["map_data"]->asObject();
+					if (mapData.contains("generator") && mapData.contains("seed") &&
+						mapData.contains("size") && mapData.contains("tileset") &&
+						mapData.contains("energy") && mapData.contains("terrain") &&
+						mapData.contains("water")) {
+						session.mapGenerator = mapData["generator"]->asIntegerNumber();
+						session.mapSeed = mapData["seed"]->asIntegerNumber();
+						session.mapSize = mapData["size"]->asIntegerNumber();
+						session.mapTileset = mapData["tileset"]->asIntegerNumber();
+						session.mapEnergy = mapData["energy"]->asIntegerNumber();
+						session.mapTerrain = mapData["terrain"]->asIntegerNumber();
+						session.mapWater = mapData["water"]->asIntegerNumber();
+					}
+				}
+
 				_sessions.push_back(session);
 			}
 		}
diff --git a/engines/scumm/he/net/net_main.h b/engines/scumm/he/net/net_main.h
index 6b4939b187a..aa03d6289f5 100644
--- a/engines/scumm/he/net/net_main.h
+++ b/engines/scumm/he/net/net_main.h
@@ -57,6 +57,15 @@ private:
 		Common::String name;
 		int players = 0;
 		uint32 timestamp = 0;
+
+		// For Moonbase map generation:
+		uint8 mapGenerator = 0;
+		int mapSeed = 0;
+		int mapSize = 0;
+		int mapTileset = 0;
+		int mapEnergy = 0;
+		int mapTerrain = 0;
+		int mapWater = 0;
 	};
 	/**
 	 * Converts a formatted string into an Address object.
@@ -534,6 +543,15 @@ private:
 	Common::String _sessionName;
 	Networking::Host *_sessionHost;
 
+	// For Moonbase map generation:
+	uint8 _mapGenerator;
+	int _mapSeed;
+	int _mapSize;
+	int _mapTileset;
+	int _mapEnergy;
+	int _mapTerrain;
+	int _mapWater;
+
 	bool _isShuttingDown;
 
 	Common::Queue<Common::JSONValue *> _hostDataQueue;
diff --git a/engines/scumm/he/script_v100he.cpp b/engines/scumm/he/script_v100he.cpp
index 113e3c4897c..43ade8ab2a4 100644
--- a/engines/scumm/he/script_v100he.cpp
+++ b/engines/scumm/he/script_v100he.cpp
@@ -2165,11 +2165,9 @@ void ScummEngine_v100he::o100_startScript() {
 	flags = fetchScriptByte();
 
 	if (_game.id == GID_MOONBASE && _roomResource == 5 &&
-		((!strcmp(_game.variant, "1.1") && script == 2178) || script == 2177)) {
-		// TODO: Only run if we're doing a single-player skirmesh or hosting a
-		// multiplayer game.
-		// (gGameMode == GAME-MODE-MULTIPLAYER-HOST || gGameMode == GAME-MODE-TCPIP-HOST ||
-		//  gGameMode == GAME-MODE-SINGLEPLAYER-SKIRMISH)
+		((!strcmp(_game.variant, "1.1") && script == 2178) || script == 2177) &&
+		readVar(253) == 24) {
+		// Only run the generator if we're doing a single-player skirmesh.
 		_moonbase->_map->generateNewMap();
 	} else if (_game.id == GID_MOONBASE && _roomResource == 5 &&
 		((!strcmp(_game.variant, "1.1") && script == 2252) || script == 2251) &&


Commit: 2727e3eaf7788b37f1b0a06c5c3d15e4b925ae3b
    https://github.com/scummvm/scummvm/commit/2727e3eaf7788b37f1b0a06c5c3d15e4b925ae3b
Author: Little Cat (toontownlittlecat at gmail.com)
Date: 2024-05-12T15:08:27+02:00

Commit Message:
SCUMM HE: Only save map config on clicking "Generate".

Changed paths:
    engines/scumm/he/moonbase/dialog-mapgenerator.cpp
    engines/scumm/he/moonbase/dialog-mapgenerator.h


diff --git a/engines/scumm/he/moonbase/dialog-mapgenerator.cpp b/engines/scumm/he/moonbase/dialog-mapgenerator.cpp
index 3d6f7956dae..efd83d37f06 100644
--- a/engines/scumm/he/moonbase/dialog-mapgenerator.cpp
+++ b/engines/scumm/he/moonbase/dialog-mapgenerator.cpp
@@ -235,7 +235,6 @@ void MapGeneratorDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, u
 	switch(cmd) {
 	case kAlgorCmd:
 		ConfMan.setInt("map_algorithm", data);
-		ConfMan.flushToDisk();
 		break;
 	case kAlgorRandCmd:
 		if (data == 1) {
@@ -251,12 +250,10 @@ void MapGeneratorDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, u
 			ConfMan.setInt("map_algorithm", previousValue);
 		}
 
-		ConfMan.flushToDisk();
 		refresh();
 		break;
 	case kSizeCmd:
 		ConfMan.setInt("map_size", data);
-		ConfMan.flushToDisk();
 		break;
 	case kSizeRandCmd:
 		if (data == 1) {
@@ -272,12 +269,10 @@ void MapGeneratorDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, u
 			ConfMan.setInt("map_size", previousValue);
 		}
 
-		ConfMan.flushToDisk();
 		refresh();
 		break;
 	case kTileCmd:
 		ConfMan.setInt("map_tileset", data);
-		ConfMan.flushToDisk();
 		break;
 	case kTileRandCmd:
 		if (data == 1) {
@@ -293,12 +288,10 @@ void MapGeneratorDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, u
 			ConfMan.setInt("map_tileset", previousValue);
 		}
 
-		ConfMan.flushToDisk();
 		refresh();
 		break;
 	case kEnergyCmd:
 		ConfMan.setInt("map_energy", data);
-		ConfMan.flushToDisk();
 		break;
 	case kEnergyRandCmd:
 		if (data == 1) {
@@ -314,12 +307,10 @@ void MapGeneratorDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, u
 			ConfMan.setInt("map_energy", previousValue);
 		}
 
-		ConfMan.flushToDisk();
 		refresh();
 		break;
 	case kTerrainCmd:
 		ConfMan.setInt("map_terrain", data);
-		ConfMan.flushToDisk();
 		break;
 	case kTerrainRandCmd:
 		if (data == 1) {
@@ -335,12 +326,10 @@ void MapGeneratorDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, u
 			ConfMan.setInt("map_terrain", previousValue);
 		}
 
-		ConfMan.flushToDisk();
 		refresh();
 		break;
 	case kWaterCmd:
 		ConfMan.setInt("map_water", data);
-		ConfMan.flushToDisk();
 		break;
 	case kWaterRandCmd:
 		if (data == 1) {
@@ -356,7 +345,6 @@ void MapGeneratorDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, u
 			ConfMan.setInt("map_water", previousValue);
 		}
 
-		ConfMan.flushToDisk();
 		refresh();
 		break;
 	case kCancelCmd:
@@ -364,6 +352,7 @@ void MapGeneratorDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, u
 		close();
 		break;
 	case kGenerateCmd:
+		ConfMan.flushToDisk();
 		setResult(1);
 		close();
 		break;
@@ -372,4 +361,17 @@ void MapGeneratorDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, u
 	}
 }
 
+void MapGeneratorDialog::handleKeyDown(Common::KeyState state) {
+	switch (state.keycode) {
+	case Common::KEYCODE_RETURN:
+	case Common::KEYCODE_KP_ENTER:
+		ConfMan.flushToDisk();
+		setResult(1);
+		close();
+		break;
+	default:
+		Dialog::handleKeyDown(state);
+	}
+}
+
 } // End of namespace Scumm
diff --git a/engines/scumm/he/moonbase/dialog-mapgenerator.h b/engines/scumm/he/moonbase/dialog-mapgenerator.h
index 4d14237b68e..559724a6995 100644
--- a/engines/scumm/he/moonbase/dialog-mapgenerator.h
+++ b/engines/scumm/he/moonbase/dialog-mapgenerator.h
@@ -32,6 +32,7 @@ public:
 	MapGeneratorDialog(bool demo);
 
 	void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data) override;
+	void handleKeyDown(Common::KeyState state) override;
 
 private:
 	void refresh();


Commit: a3eb710f7a29552898a3087e0d43b6fb8ac59592
    https://github.com/scummvm/scummvm/commit/a3eb710f7a29552898a3087e0d43b6fb8ac59592
Author: Little Cat (toontownlittlecat at gmail.com)
Date: 2024-05-12T15:08:27+02:00

Commit Message:
SCUMM HE: Fix map not generating when relaying data.

Changed paths:
    engines/scumm/he/net/net_main.cpp


diff --git a/engines/scumm/he/net/net_main.cpp b/engines/scumm/he/net/net_main.cpp
index 3a124cefd76..d126c606741 100644
--- a/engines/scumm/he/net/net_main.cpp
+++ b/engines/scumm/he/net/net_main.cpp
@@ -406,6 +406,11 @@ int Net::doJoinSession(Session session) {
 		_sessionServerHost = nullptr;
 	}
 
+	if (_gameName == "moonbase" && session.mapGenerator > 0) {
+		// Generate the host's map.
+		_vm->_moonbase->_map->generateMapWithInfo(session.mapGenerator, session.mapSeed, session.mapSize, session.mapTileset, session.mapEnergy, session.mapTerrain, session.mapWater);
+	}
+
 	bool success = connectToSession(session.host, session.port);
 	if (!success) {
 		if (!session.local) {
@@ -438,11 +443,6 @@ int Net::doJoinSession(Session session) {
 		return false;
 	}
 
-	if (_gameName == "moonbase" && session.mapGenerator > 0) {
-		// Generate the host's map.
-		_vm->_moonbase->_map->generateMapWithInfo(session.mapGenerator, session.mapSeed, session.mapSize, session.mapTileset, session.mapEnergy, session.mapTerrain, session.mapWater);
-	}
-
 	return true;
 }
 


Commit: 8f5e44f89c7aafd4dbcae9c6388dc5893e67a621
    https://github.com/scummvm/scummvm/commit/8f5e44f89c7aafd4dbcae9c6388dc5893e67a621
Author: Little Cat (toontownlittlecat at gmail.com)
Date: 2024-05-12T15:08:27+02:00

Commit Message:
SCUMM HE: Compute MD5s for maps and verify over network.

Changed paths:
    engines/scumm/he/moonbase/map_main.cpp
    engines/scumm/he/moonbase/map_main.h
    engines/scumm/he/net/net_main.cpp
    engines/scumm/he/net/net_main.h


diff --git a/engines/scumm/he/moonbase/map_main.cpp b/engines/scumm/he/moonbase/map_main.cpp
index 13c155a6a7c..f22cf7d0c0b 100644
--- a/engines/scumm/he/moonbase/map_main.cpp
+++ b/engines/scumm/he/moonbase/map_main.cpp
@@ -22,6 +22,8 @@
 #include "common/compression/deflate.h"
 #include "common/config-manager.h"
 
+#include "common/md5.h"
+
 #include "common/memstream.h"
 #include "common/bufferedstream.h"
 
@@ -46,6 +48,8 @@ Map::Map(ScummEngine_v100he *vm) : _vm(vm), _rnd("moonbase") {
 	_energy = -1;
 	_terrain = -1;
 	_water = -1;
+
+	_mapHash = Common::String();
 }
 
 Map::~Map() {
@@ -164,6 +168,11 @@ bool Map::generateMapWithInfo(uint8 generator, int seed, int mapSize, int tilese
 		return false;
 	}
 
+	// Compute MD5 hash of the newly generated map file:
+	Common::MemoryReadStream mapStream = Common::MemoryReadStream((byte *)_generatedMap, sizeof(MapFile));
+	_mapHash = Common::computeStreamMD5AsString(mapStream, 0);
+	debug(1, "Map: MD5: %s", _mapHash.c_str());
+
 	_mapGenerated = true;
 	return true;
 }
@@ -182,6 +191,7 @@ void Map::deleteMap() {
 		_energy = 0;
 		_terrain = 0;
 		_water = 0;
+		_mapHash = "";
 		debug(1, "Map: Deleted.");
 	}
 }
diff --git a/engines/scumm/he/moonbase/map_main.h b/engines/scumm/he/moonbase/map_main.h
index 0f26e4a405d..ac1d681672a 100644
--- a/engines/scumm/he/moonbase/map_main.h
+++ b/engines/scumm/he/moonbase/map_main.h
@@ -24,8 +24,8 @@
 
 #ifdef ENABLE_HE
 
-#include "common/stream.h"
 #include "common/random.h"
+#include "common/stream.h"
 
 #include "engines/scumm/he/moonbase/map_mif.h"
 
@@ -77,6 +77,10 @@ public:
 		return _mapGenerated;
 	}
 
+	Common::String getHash() const {
+		return _mapHash;
+	}
+
 private:
 	ScummEngine_v100he *_vm;
 
@@ -95,6 +99,7 @@ private:
 
 	bool _mapGenerated;
 	MapFile *_generatedMap;
+	Common::String _mapHash;
 
 	Common::SeekableReadStream *makeWiz();
 };
diff --git a/engines/scumm/he/net/net_main.cpp b/engines/scumm/he/net/net_main.cpp
index d126c606741..c6589a7e372 100644
--- a/engines/scumm/he/net/net_main.cpp
+++ b/engines/scumm/he/net/net_main.cpp
@@ -81,6 +81,7 @@ Net::Net(ScummEngine_v90he *vm) : _latencyTime(1), _fakeLatency(false), _vm(vm)
 	_mapEnergy = 0;
 	_mapTerrain = 0;
 	_mapWater = 0;
+	_mapHash = Common::String();
 
 	_hostPort = 0;
 
@@ -184,8 +185,7 @@ int Net::joinGame(Common::String IP, char *userName) {
 			address.port = _sessions[0].port;
 
 			if (_gameName == "moonbase" && _sessions[0].mapGenerator > 0) {
-				// Generate the host's map.
-				_vm->_moonbase->_map->generateMapWithInfo(_sessions[0].mapGenerator, _sessions[0].mapSeed, _sessions[0].mapSize, _sessions[0].mapTileset, _sessions[0].mapEnergy, _sessions[0].mapTerrain, _sessions[0].mapWater);
+				generateMoonbaseMap(_sessions[0]);
 			}
 			stopQuerySessions();
 		}
@@ -306,9 +306,10 @@ int Net::createSession(char *name) {
 			_mapEnergy = map->getEnergy();
 			_mapTerrain = map->getTerrain();
 			_mapWater = map->getWater();
+			_mapHash = map->getHash();
 			mapData = Common::String::format(
-				"{\"generator\":%d,\"seed\":%d,\"size\":%d,\"tileset\":%d,\"energy\":%d,\"terrain\":%d,\"water\":%d}",
-				_mapGenerator, _mapSeed, _mapSize, _mapTileset, _mapEnergy, _mapTerrain, _mapWater);
+				"{\"generator\":%d,\"seed\":%d,\"size\":%d,\"tileset\":%d,\"energy\":%d,\"terrain\":%d,\"water\":%d,\"hash\":\"%s\"}",
+				_mapGenerator, _mapSeed, _mapSize, _mapTileset, _mapEnergy, _mapTerrain, _mapWater, _mapHash.c_str());
 		}
 	}
 
@@ -407,8 +408,7 @@ int Net::doJoinSession(Session session) {
 	}
 
 	if (_gameName == "moonbase" && session.mapGenerator > 0) {
-		// Generate the host's map.
-		_vm->_moonbase->_map->generateMapWithInfo(session.mapGenerator, session.mapSeed, session.mapSize, session.mapTileset, session.mapEnergy, session.mapTerrain, session.mapWater);
+		generateMoonbaseMap(session);
 	}
 
 	bool success = connectToSession(session.host, session.port);
@@ -446,6 +446,25 @@ int Net::doJoinSession(Session session) {
 	return true;
 }
 
+void Net::generateMoonbaseMap(Session session) {
+	uint8 mapAttempts = 0;
+	bool mapGenerated = false;
+	// Generate the host's map.
+	while (!mapGenerated) {
+		_vm->_moonbase->_map->generateMapWithInfo(session.mapGenerator, session.mapSeed, session.mapSize, session.mapTileset, session.mapEnergy, session.mapTerrain, session.mapWater);
+		if (_vm->_moonbase->_map->getHash() != _sessions[0].mapHash) {
+			warning("NETWORK: Maps does not match, trying again...");
+			mapAttempts++;
+			if (mapAttempts == 10) {
+				// Maps are not matching... Give up.
+				warning("NETWORK: Unable to generate the host's map exactly. You may need to tell the host to disband and rehost the session. Continuing on, but expect mismatched stuff.");
+				mapGenerated = true;
+			}
+		}
+		mapGenerated = true;
+	}
+}
+
 int Net::joinSession(int sessionIndex) {
 	debugC(DEBUG_NETWORK, "Net::joinSession(%d)", sessionIndex); // PN_JoinSession
 	if (_sessions.empty()) {
@@ -526,6 +545,7 @@ int Net::endSession() {
 	_mapEnergy = 0;
 	_mapTerrain = 0;
 	_mapWater = 0;
+	_mapHash = "";
 
 	return 1;
 }
@@ -1013,7 +1033,7 @@ void Net::handleSessionServerData(Common::String data) {
 						if (mapData.contains("generator") && mapData.contains("seed") &&
 							mapData.contains("size") && mapData.contains("tileset") &&
 							mapData.contains("energy") && mapData.contains("terrain") &&
-							mapData.contains("water")) {
+							mapData.contains("water") && mapData.contains("hash")) {
 							session.mapGenerator = mapData["generator"]->asIntegerNumber();
 							session.mapSeed = mapData["seed"]->asIntegerNumber();
 							session.mapSize = mapData["size"]->asIntegerNumber();
@@ -1021,6 +1041,7 @@ void Net::handleSessionServerData(Common::String data) {
 							session.mapEnergy = mapData["energy"]->asIntegerNumber();
 							session.mapTerrain = mapData["terrain"]->asIntegerNumber();
 							session.mapWater = mapData["water"]->asIntegerNumber();
+							session.mapHash = mapData["hash"]->asString();
 						}
 					}
 					_sessions.push_back(session);
@@ -1128,8 +1149,8 @@ void Net::handleBroadcastData(Common::String data, Common::String host, int port
 				if (_gameName == "moonbase" && _mapGenerator > 0) {
 					// Send over map data
 					mapData = Common::String::format(
-						"{\"generator\":%d,\"seed\":%d,\"size\":%d,\"tileset\":%d,\"energy\":%d,\"terrain\":%d,\"water\":%d}",
-						_mapGenerator, _mapSeed, _mapSize, _mapTileset, _mapEnergy, _mapTerrain, _mapWater);
+						"{\"generator\":%d,\"seed\":%d,\"size\":%d,\"tileset\":%d,\"energy\":%d,\"terrain\":%d,\"water\":%d,\"hash\":\"%s\"}",
+						_mapGenerator, _mapSeed, _mapSize, _mapTileset, _mapEnergy, _mapTerrain, _mapWater, _mapHash.c_str());
 				}
 				Common::String resp = Common::String::format(
 					"{\"cmd\":\"session_resp\",\"game\":\"%s\",\"version\":\"%s\",\"id\":%d,\"name\":\"%s\",\"players\":%d,\"map_data\":%s}",
@@ -1191,7 +1212,7 @@ void Net::handleBroadcastData(Common::String data, Common::String host, int port
 					if (mapData.contains("generator") && mapData.contains("seed") &&
 						mapData.contains("size") && mapData.contains("tileset") &&
 						mapData.contains("energy") && mapData.contains("terrain") &&
-						mapData.contains("water")) {
+						mapData.contains("water") && mapData.contains("hash")) {
 						session.mapGenerator = mapData["generator"]->asIntegerNumber();
 						session.mapSeed = mapData["seed"]->asIntegerNumber();
 						session.mapSize = mapData["size"]->asIntegerNumber();
@@ -1199,6 +1220,7 @@ void Net::handleBroadcastData(Common::String data, Common::String host, int port
 						session.mapEnergy = mapData["energy"]->asIntegerNumber();
 						session.mapTerrain = mapData["terrain"]->asIntegerNumber();
 						session.mapWater = mapData["water"]->asIntegerNumber();
+						session.mapHash = mapData["hash"]->asString();
 					}
 				}
 
diff --git a/engines/scumm/he/net/net_main.h b/engines/scumm/he/net/net_main.h
index aa03d6289f5..af539345aed 100644
--- a/engines/scumm/he/net/net_main.h
+++ b/engines/scumm/he/net/net_main.h
@@ -66,6 +66,7 @@ private:
 		int mapEnergy = 0;
 		int mapTerrain = 0;
 		int mapWater = 0;
+		Common::String mapHash;
 	};
 	/**
 	 * Converts a formatted string into an Address object.
@@ -388,6 +389,14 @@ private:
 	 */
 	int doJoinSession(Session session);
 
+	/**
+	 * Generates a Moonbase Commander map based on the provided
+	 * Session's configurations.
+	 *
+	 * @param session Session structure containing map data.
+	 */
+	void generateMoonbaseMap(Session session);
+
 	/**
 	 * Sends remote data to peer(s).
 	 *
@@ -551,6 +560,7 @@ private:
 	int _mapEnergy;
 	int _mapTerrain;
 	int _mapWater;
+	Common::String _mapHash;
 
 	bool _isShuttingDown;
 


Commit: 6e86d298d597dc996a7eb3c7bae428ba5744c7b2
    https://github.com/scummvm/scummvm/commit/6e86d298d597dc996a7eb3c7bae428ba5744c7b2
Author: Little Cat (toontownlittlecat at gmail.com)
Date: 2024-05-12T15:08:27+02:00

Commit Message:
SCUMM HE: Use own network version number.

Changed paths:
    engines/scumm/dialogs.cpp
    engines/scumm/dialogs.h
    engines/scumm/he/net/net_defines.h
    engines/scumm/he/net/net_lobby.cpp
    engines/scumm/he/net/net_main.cpp


diff --git a/engines/scumm/dialogs.cpp b/engines/scumm/dialogs.cpp
index ae169637f21..4a7e576e247 100644
--- a/engines/scumm/dialogs.cpp
+++ b/engines/scumm/dialogs.cpp
@@ -46,6 +46,10 @@
 #include "scumm/help.h"
 #endif
 
+#ifdef USE_ENET
+#include "scumm/he/net/net_defines.h"
+#endif
+
 using Graphics::kTextAlignCenter;
 using Graphics::kTextAlignLeft;
 using GUI::WIDGET_ENABLED;
@@ -1695,6 +1699,9 @@ HENetworkGameOptionsWidget::HENetworkGameOptionsWidget(GuiObject *boss, const Co
 
 		_serverResetButton = addClearButton(widgetsBoss(), "HENetworkGameOptionsDialog.ServerReset", kResetServersCmd);
 	}
+
+	// Display network version
+	_networkVersion = new GUI::StaticTextWidget(widgetsBoss(), "HENetworkGameOptionsDialog.NetworkVersion", Common::String::format("Multiplayer Version: %s", NETWORK_VERSION));
 }
 
 void HENetworkGameOptionsWidget::load() {
@@ -1773,6 +1780,7 @@ void HENetworkGameOptionsWidget::defineLayout(GUI::ThemeEval &layouts, const Com
 					.addWidget("ServerReset", "", 15, 15)
 				.closeLayout()
 				.addWidget("EnableCompetitiveMods", "Checkbox")
+				.addWidget("NetworkVersion", "")
 			.closeLayout()
 		.closeDialog();
 #endif
@@ -1789,6 +1797,7 @@ void HENetworkGameOptionsWidget::defineLayout(GUI::ThemeEval &layouts, const Com
 					.addWidget("SessionServerAddress", "EditTextWidget")
 					.addWidget("ServerReset", "", 15, 15)
 				.closeLayout()
+				.addWidget("NetworkVersion", "")
 			.closeLayout()
 		.closeDialog();
 	}
diff --git a/engines/scumm/dialogs.h b/engines/scumm/dialogs.h
index 1c795123805..85c06a136ca 100644
--- a/engines/scumm/dialogs.h
+++ b/engines/scumm/dialogs.h
@@ -419,6 +419,8 @@ private:
 	GUI::EditTextWidget *_lobbyServerAddr;
 
 	GUI::CheckboxWidget *_enableCompetitiveMods;
+
+	GUI::StaticTextWidget *_networkVersion;
 };
 #endif
 
diff --git a/engines/scumm/he/net/net_defines.h b/engines/scumm/he/net/net_defines.h
index 6a561899852..11ecff1c3ba 100644
--- a/engines/scumm/he/net/net_defines.h
+++ b/engines/scumm/he/net/net_defines.h
@@ -24,6 +24,13 @@
 
 namespace Scumm {
 
+// The version number of the network protocol.  Users
+// will be matched with the defined when hosting and joining
+// games.  Meaning it will not find users that are using
+// a different version.  This is done to ensure that
+// people are playing with the same netcode as the hosts.
+#define NETWORK_VERSION								"1.1"
+
 // pnetwin.h
 
 #define PN_PRIORITY_HIGH							0x00000001
diff --git a/engines/scumm/he/net/net_lobby.cpp b/engines/scumm/he/net/net_lobby.cpp
index a31b2f3353b..e270c7aa794 100644
--- a/engines/scumm/he/net/net_lobby.cpp
+++ b/engines/scumm/he/net/net_lobby.cpp
@@ -19,11 +19,11 @@
  *
  */
 
-#include "base/version.h"
 #include "common/config-manager.h"
 
 #include "scumm/he/intern_he.h"
 #include "scumm/he/net/net_lobby.h"
+#include "scumm/he/net/net_defines.h"
 
 namespace Scumm {
 
@@ -451,7 +451,7 @@ void Lobby::login(const char *userName, const char *password) {
 	loginRequestParameters.setVal("user", new Common::JSONValue(_userName));
 	loginRequestParameters.setVal("pass", new Common::JSONValue((Common::String)password));
 	loginRequestParameters.setVal("game", new Common::JSONValue((Common::String)_gameName));
-	loginRequestParameters.setVal("version", new Common::JSONValue(gScummVMFullVersion));
+	loginRequestParameters.setVal("version", new Common::JSONValue(NETWORK_VERSION));
 	loginRequestParameters.setVal("competitive_mods", new Common::JSONValue(ConfMan.getBool("enable_competitive_mods")));
 
 	send(loginRequestParameters);
diff --git a/engines/scumm/he/net/net_main.cpp b/engines/scumm/he/net/net_main.cpp
index c6589a7e372..7a20b26daa4 100644
--- a/engines/scumm/he/net/net_main.cpp
+++ b/engines/scumm/he/net/net_main.cpp
@@ -19,7 +19,6 @@
  *
  */
 
-#include "base/version.h"
 #include "common/config-manager.h"
 
 #include "scumm/he/intern_he.h"
@@ -334,8 +333,8 @@ int Net::createSession(char *name) {
 			_sessionServerPeer = 0;
 			// Create session to the session server.
 			Common::String req = Common::String::format(
-				"{\"cmd\":\"host_session\",\"game\":\"%s\",\"version\":\"%s\",\"name\":\"%s\",\"maxplayers\":%d,\"scummvm_version\":\"%s\",\"map_data\":%s}",
-				_gameName.c_str(), _gameVersion.c_str(), name, _maxPlayers, gScummVMFullVersion, mapData.c_str());
+				"{\"cmd\":\"host_session\",\"game\":\"%s\",\"version\":\"%s\",\"name\":\"%s\",\"maxplayers\":%d,\"network_version\":\"%s\",\"map_data\":%s}",
+				_gameName.c_str(), _gameVersion.c_str(), name, _maxPlayers, NETWORK_VERSION, mapData.c_str());
 			debugC(DEBUG_NETWORK, "NETWORK: Sending to session server: %s", req.c_str());
 			_sessionHost->send(req.c_str(), _sessionServerPeer);
 		} else {
@@ -669,8 +668,8 @@ int32 Net::updateQuerySessions() {
 	if (_sessionServerHost) {
 		// Get internet-based sessions from the session server.
 		Common::String getSessions = Common::String::format(
-			"{\"cmd\":\"get_sessions\",\"game\":\"%s\",\"version\":\"%s\",\"scummvm_version\":\"%s\"}",
-			_gameName.c_str(), _gameVersion.c_str(), gScummVMFullVersion);
+			"{\"cmd\":\"get_sessions\",\"game\":\"%s\",\"version\":\"%s\",\"network_version\":\"%s\"}",
+			_gameName.c_str(), _gameVersion.c_str(), NETWORK_VERSION);
 		_sessionServerHost->send(getSessions.c_str(), 0);
 
 		_gotSessions = false;


Commit: 80d8e3efb4a279804859209941a5b0004a967e4d
    https://github.com/scummvm/scummvm/commit/80d8e3efb4a279804859209941a5b0004a967e4d
Author: Little Cat (toontownlittlecat at gmail.com)
Date: 2024-05-12T15:08:27+02:00

Commit Message:
SCUMM HE: Fix network map verification

Changed paths:
    engines/scumm/he/net/net_main.cpp


diff --git a/engines/scumm/he/net/net_main.cpp b/engines/scumm/he/net/net_main.cpp
index 7a20b26daa4..8c53b329a67 100644
--- a/engines/scumm/he/net/net_main.cpp
+++ b/engines/scumm/he/net/net_main.cpp
@@ -451,7 +451,9 @@ void Net::generateMoonbaseMap(Session session) {
 	// Generate the host's map.
 	while (!mapGenerated) {
 		_vm->_moonbase->_map->generateMapWithInfo(session.mapGenerator, session.mapSeed, session.mapSize, session.mapTileset, session.mapEnergy, session.mapTerrain, session.mapWater);
-		if (_vm->_moonbase->_map->getHash() != _sessions[0].mapHash) {
+		if (_vm->_moonbase->_map->getHash() == _sessions[0].mapHash) {
+			mapGenerated = true;
+		} else {
 			warning("NETWORK: Maps does not match, trying again...");
 			mapAttempts++;
 			if (mapAttempts == 10) {
@@ -460,7 +462,6 @@ void Net::generateMoonbaseMap(Session session) {
 				mapGenerated = true;
 			}
 		}
-		mapGenerated = true;
 	}
 }
 


Commit: 6d1d9e8b68cd1bb5f41642e2be9b93f57a5d1b10
    https://github.com/scummvm/scummvm/commit/6d1d9e8b68cd1bb5f41642e2be9b93f57a5d1b10
Author: Michael Barlow (michaelbarlow7 at gmail.com)
Date: 2024-05-12T15:08:27+02:00

Commit Message:
SCUMM HE: Fixed MD5 mismatch bug

The MD5 comparison code was checking the locally generated MD5 of the
Mapfile with the MD5 in the first session (_sessions[0]) instead of
the one passed into the parameter.

Changed paths:
    engines/scumm/he/net/net_main.cpp


diff --git a/engines/scumm/he/net/net_main.cpp b/engines/scumm/he/net/net_main.cpp
index 8c53b329a67..3d93c62905e 100644
--- a/engines/scumm/he/net/net_main.cpp
+++ b/engines/scumm/he/net/net_main.cpp
@@ -451,7 +451,7 @@ void Net::generateMoonbaseMap(Session session) {
 	// Generate the host's map.
 	while (!mapGenerated) {
 		_vm->_moonbase->_map->generateMapWithInfo(session.mapGenerator, session.mapSeed, session.mapSize, session.mapTileset, session.mapEnergy, session.mapTerrain, session.mapWater);
-		if (_vm->_moonbase->_map->getHash() == _sessions[0].mapHash) {
+		if (_vm->_moonbase->_map->getHash() == session.mapHash) {
 			mapGenerated = true;
 		} else {
 			warning("NETWORK: Maps does not match, trying again...");


Commit: fcaa53b253474554e4ee59574d464c895d6b3bbd
    https://github.com/scummvm/scummvm/commit/fcaa53b253474554e4ee59574d464c895d6b3bbd
Author: Michael Barlow (michaelbarlow7 at gmail.com)
Date: 2024-05-12T15:08:27+02:00

Commit Message:
SCUMM HE: Fixed MD5 mismatch issue on Katton maps

The random number generation will generate the same numbers from
a given seed in a particular order. However, when passing
function calls as parameters to another function, the order
in which those parameter calls are made is undefined. If the code is compiled
on different platforms using different compilers (e.g. macOS/clang
vs linux/G++), this order can be different, which results in
different random numbers being assigned to different variables.

The fix is to pull out the parameter function calls as variables
so that the order in which the generated random numbers are assigned
is the same, regardless of compiler/platform.

Changed paths:
    engines/scumm/he/moonbase/map_katton.cpp


diff --git a/engines/scumm/he/moonbase/map_katton.cpp b/engines/scumm/he/moonbase/map_katton.cpp
index efcb327d8b1..3c02e6ed6f3 100644
--- a/engines/scumm/he/moonbase/map_katton.cpp
+++ b/engines/scumm/he/moonbase/map_katton.cpp
@@ -78,6 +78,7 @@ MapFile *KattonGenerator::generateMap(int water, int tileSet, int mapSize, int e
 	short int goodwater[1600][2];
 	// used in making energy
 	int maxnumclose = 0, maxnumfar = 0, maxnumrand = 0, smallmed = 0, goodplaceClose[300][2], goodplaceFar[300][2], numplaceClose, numplaceFar, placeFar[3], placeClose[2], counter, counterpools;
+	int stringiness, randomx, randomy;
 
 	//****************************************Make the basic landmass shapes.
 
@@ -86,23 +87,35 @@ MapFile *KattonGenerator::generateMap(int water, int tileSet, int mapSize, int e
 	for (i = 0; i < numsplotches; i++) {
 		length = (int)(((1 - waterpercent) / 6 * size * size) / numsplotches);
 		length = length + plusminus((int)(length / 2));
-		randomsplotch(length, 1 + plusminus(1), 2, getRandomNumber() % size, getRandomNumber() % size);
+		stringiness = 1 + plusminus(1);
+		randomx = getRandomNumber() % size;
+		randomy = getRandomNumber() % size;
+		randomsplotch(length, 1 + stringiness, 2, randomx, randomy);
 	}
 
 	for (i = 0; i < (int)numsplotches / 4; i++) {
 		length = (int)(((1 - waterpercent) / 3 * size * size) / numsplotches);
 		length = length + plusminus((int)(length / 4));
-		randomsplotch(length, 1 + plusminus(1), 1, getRandomNumber() % size, getRandomNumber() % size);
+		stringiness = 1 + plusminus(1);
+		randomx = getRandomNumber() % size;
+		randomy = getRandomNumber() % size;
+		randomsplotch(length, stringiness, 1, randomx, randomy);
 	}
 
 	for (i = 0; i < (int)numsplotches / 2; i++) {
 		length = (int)(size + plusminus((int)(size / 2)));
-		randomsplotch(length, 1 + plusminus(1), 0, getRandomNumber() % size, getRandomNumber() % size);
+		stringiness = 1 + plusminus(1);
+		randomx = getRandomNumber() % size;
+		randomy = getRandomNumber() % size;
+		randomsplotch(length, stringiness, 0, randomx, randomy);
 	}
 
 	for (i = 0; i < (int)waterpercent * size; i++) {
 		length = (int)(size + plusminus((int)(size / 2)));
-		randomsplotch(length, 1 + plusminus(1), 0, getRandomNumber() % size, getRandomNumber() % size);
+		stringiness = 1 + plusminus(1);
+		randomx = getRandomNumber() % size;
+		randomy = getRandomNumber() % size;
+		randomsplotch(length, stringiness, 0, randomx, randomy);
 	}
 
 	//****************************************Fatten up the landmasses
@@ -154,7 +167,9 @@ MapFile *KattonGenerator::generateMap(int water, int tileSet, int mapSize, int e
 			z = getRandomNumber() % multiplier + i * multiplier;
 			x = goodwater[z][0];
 			y = goodwater[z][1];
-			randomwater(size + plusminus(size / 2), getRandomNumber() % 3, x, y);
+			length = size + plusminus(size / 2);
+			stringiness = getRandomNumber() % 3;
+			randomwater(length, stringiness, x, y);
 		}
 	}
 


Commit: 6b80c4c58128af5eb5471412afcd34fecf851dbf
    https://github.com/scummvm/scummvm/commit/6b80c4c58128af5eb5471412afcd34fecf851dbf
Author: Little Cat (toontownlittlecat at gmail.com)
Date: 2024-05-12T15:08:27+02:00

Commit Message:
COMMON: Add Base64 encoding/decoding

Changed paths:
  A common/base64.cpp
  A common/base64.h
  A test/common/base64.h
    common/module.mk


diff --git a/common/base64.cpp b/common/base64.cpp
new file mode 100644
index 00000000000..e96e7d40d0f
--- /dev/null
+++ b/common/base64.cpp
@@ -0,0 +1,168 @@
+/* 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/base64.h"
+#include "common/array.h"
+#include "common/memstream.h"
+#include "common/str.h"
+#include "common/stream.h"
+#include "common/types.h"
+
+namespace Common {
+
+static const String encodingTable = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+String b64EncodeString(String &string) {
+	String out;
+	int32 val = 0, valb = -6;
+	for (uint8 c : string) {
+		val = (val << 8) + c;
+		valb += 8;
+		while (valb >= 0) {
+			out += (encodingTable[(val >> valb) & 0x3F]);
+			valb -= 6;
+		}
+	}
+	if (valb > -6)
+		out += (encodingTable[((val << 8) >> (valb + 8)) & 0x3F]);
+	while (out.size() % 4)
+		out += "=";
+	return out;
+}
+
+String b64EncodeStream(ReadStream &stream) {
+	String out;
+	int32 val = 0, valb = -6;
+	while (true) {
+		uint8 b = stream.readByte();
+		if (stream.eos())
+			break;
+		val = (val << 8) + b;
+		valb += 8;
+		while (valb >= 0) {
+			out += (encodingTable[(val >> valb) & 0x3F]);
+			valb -= 6;
+		}
+	}
+	if (valb > -6)
+		out += (encodingTable[((val << 8) >> (valb + 8)) & 0x3F]);
+	while (out.size() % 4)
+		out += "=";
+	return out;
+}
+
+String b64EncodeData(void *dataPtr, size_t dataSize) {
+	String out;
+	int32 val = 0, valb = -6;
+	uint8 *p = (uint8 *)dataPtr;
+
+	for (size_t i = 0; i < dataSize; i++) {
+		uint8 b = p[i];
+		val = (val << 8) + b;
+		valb += 8;
+		while (valb >= 0) {
+			out += (encodingTable[(val >> valb) & 0x3F]);
+			valb -= 6;
+		}
+	}
+	if (valb > -6)
+		out += (encodingTable[((val << 8) >> (valb + 8)) & 0x3F]);
+	while (out.size() % 4)
+		out += "=";
+	return out;
+}
+
+String b64DecodeString(String &string) {
+	String out;
+	Common::Array<int> T(256, -1);
+
+	// TODO: Verify if its a proper Base64 encoded string.
+
+	for (int i = 0; i < 64; i++) {
+		T[encodingTable[i]] = i;
+	}
+
+	int val = 0, valb = -8;
+	for (char c : string) {
+		if (T[c] == -1)
+			break;
+		val = (val << 6) + T[c];
+		valb += 6;
+		if (valb >= 0) {
+			out += (char((val >> valb) & 0xFF));
+			valb -= 8;
+		}
+	}
+
+	return out;
+}
+
+MemoryReadStream *b64DecodeStream(String &string, uint32 outputLength) {
+	char *out = (char *)malloc(outputLength);
+	Common::Array<int> T(256, -1);
+
+	// TODO: Verify if its a proper Base64 encoded string.
+
+	for (int i = 0; i < 64; i++) {
+		T[encodingTable[i]] = i;
+	}
+
+	int val = 0, valb = -8, valc = 0;
+	for (char c : string) {
+		if (T[c] == -1)
+			break;
+		val = (val << 6) + T[c];
+		valb += 6;
+		if (valb >= 0) {
+			out[valc++] = (char((val >> valb) & 0xFF));
+			valb -= 8;
+		}
+	}
+
+	return new MemoryReadStream((const byte *)out, outputLength, DisposeAfterUse::YES);
+}
+
+bool b64DecodeData(String &string, void *dataPtr) {
+	uint8 *p = (uint8 *)dataPtr;
+	Common::Array<int> T(256, -1);
+
+	// TODO: Verify if its a proper Base64 encoded string.
+
+	for (int i = 0; i < 64; i++) {
+		T[encodingTable[i]] = i;
+	}
+
+	int val = 0, valb = -8, valc = 0;
+	for (char c : string) {
+		if (T[c] == -1)
+			break;
+		val = (val << 6) + T[c];
+		valb += 6;
+		if (valb >= 0) {
+			p[valc++] = (char((val >> valb) & 0xFF));
+			valb -= 8;
+		}
+	}
+
+	return true;
+}
+
+} // End of namespace Common
diff --git a/common/base64.h b/common/base64.h
new file mode 100644
index 00000000000..6300bf662d9
--- /dev/null
+++ b/common/base64.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 COMMON_BASE64_H
+#define COMMON_BASE64_H
+
+#include "common/scummsys.h"
+
+namespace Common {
+
+/**
+ * @defgroup common_base64 Base64 encoding & decoding.
+ * @ingroup common
+ *
+ * @brief API for encoding and decoing Base64 strings.
+ *
+ * @{
+ */
+
+class MemoryReadStream;
+class ReadStream;
+class String;
+
+/**
+ * Encodes a string into a Base64 encoded string.
+ * @param[in] string	the string to encode
+ * @return String containing the Base64 encoded string.
+ */
+String b64EncodeString(String &string);
+
+/**
+ * Encodes a ReadStream into a Base64 encoded string.
+ * @param[in] stream	the stream to encode
+ * @return String containing the Base64 encoded string.
+ */
+String b64EncodeStream(ReadStream &stream);
+
+/**
+ * Encodes a data pointer into a Base64 encoded string.
+ * @param[in] dataPtr	pointer to data to encode
+ * @return String containing the Base64 encoded string.
+ */
+String b64EncodeData(void *dataPtr, size_t dataSize);
+
+/**
+ * Decodes a Base64 encoded string into a regular string.
+ * @param[in] string	base64 encoded string to decode
+ * @return String containing the decoded result.
+ */
+String b64DecodeString(String &string);
+
+/**
+ * Decodes a Base64 encoded string into a MemoryReadStream, its contents
+ * will be disposed when deleting the stream.
+ * @param[in] string	base64 encoded string to decode
+ * @return MemoryReadStream pointer containing the decoded result.
+ */
+MemoryReadStream *b64DecodeStream(String &string, uint32 outputLength);
+
+/**
+ * Decodes a Base64 encoded string into the set data pointer
+ * @param[in] string	base64 encoded string to decode
+ * @return true on success, false if an error occurred
+ */
+bool b64DecodeData(String &string, void *dataPtr);
+
+/** @} */
+
+} // End of namespace Common
+
+#endif
diff --git a/common/module.mk b/common/module.mk
index 860b853cffe..3450853a87d 100644
--- a/common/module.mk
+++ b/common/module.mk
@@ -2,6 +2,7 @@ MODULE := common
 
 MODULE_OBJS := \
 	archive.o \
+	base64.o \
 	btea.o \
 	concatstream.o \
 	config-manager.o \
diff --git a/test/common/base64.h b/test/common/base64.h
new file mode 100644
index 00000000000..5d59af741d9
--- /dev/null
+++ b/test/common/base64.h
@@ -0,0 +1,108 @@
+#include <cxxtest/TestSuite.h>
+
+#include "common/base64.h"
+#include "common/memstream.h"
+
+static const char *base64_test_string[] = {
+	"",
+	"a",
+	"abc",
+	"abcdefghijklmnopqrstuvwxyz",
+	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+	("12345678901234567890123456789012345678901234567890123456789012"
+		"345678901234567890")
+};
+
+static const char *base64_test_encoded[] = {
+	"",
+	"YQ==",
+	"YWJj",
+	"YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo=",
+	("QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdH"
+		"V2d3h5ejAxMjM0NTY3ODk="),
+	("MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Nj"
+		"c4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTA=")
+};
+
+#include <common/pack-start.h>	// START STRUCT PACKING
+
+struct Base64TestStruct {
+	uint32 x;
+	byte y;
+	uint16 z;
+	uint32 a;
+	byte b;
+} PACKED_STRUCT;
+
+#include <common/pack-end.h>	// END STRUCT PACKING
+
+class Base64TestSuite : public CxxTest::TestSuite {
+	public:
+	void test_b64EncodeString() {
+		for (int i = 0; i < 6; i++) {
+			Common::String string = base64_test_string[i];
+			Common::String encoded = Common::b64EncodeString(string);
+			TS_ASSERT_EQUALS(encoded, base64_test_encoded[i])
+		}
+	}
+
+	void test_b64EncodeStream() {
+		for (int i = 0; i < 6; i++) {
+			Common::MemoryReadStream stream((const byte *)base64_test_string[i], strlen(base64_test_string[i]));
+			Common::String encoded = Common::b64EncodeStream(stream);
+			TS_ASSERT_EQUALS(encoded, base64_test_encoded[i])
+		}
+	}
+
+	void test_b64EncodeData() {
+		Base64TestStruct *test = new Base64TestStruct();
+		test->x = 1;
+		test->y = 2;
+		test->z = 3;
+		test->a = 4;
+		test->b = 5;
+
+		Common::String encoded = Common::b64EncodeData(test, sizeof(Base64TestStruct));
+		TS_ASSERT_EQUALS(encoded, "AQAAAAIDAAQAAAAF");
+		delete test;
+	}
+
+	void test_b64DecodeString() {
+		for (int i = 0; i < 6; i++) {
+			Common::String encoded = base64_test_encoded[i];
+			Common::String string = Common::b64DecodeString(encoded);
+			TS_ASSERT_EQUALS(string, base64_test_string[i]);
+		}
+	}
+
+	void test_b64DecodeStream() {
+		for (int i = 0; i < 6; i++) {
+			Common::String encoded = base64_test_encoded[i];
+			Common::MemoryReadStream *stream = Common::b64DecodeStream(encoded, strlen(base64_test_string[i]));
+			TS_ASSERT_EQUALS(stream->size(), strlen(base64_test_string[i]));
+
+			char *data = (char *)malloc(stream->size());
+			stream->read(data, stream->size());
+			delete stream;
+
+			Common::String string(data, strlen(base64_test_string[i]));
+			TS_ASSERT_EQUALS(string, base64_test_string[i]);
+			delete data;
+		}
+	}
+
+	void test_b64DecodeData() {
+		Base64TestStruct *test = new Base64TestStruct();
+
+		Common::String encoded = "AQAAAAIDAAQAAAAF";
+		bool success = Common::b64DecodeData(encoded, test);
+		TS_ASSERT_EQUALS(success, true);
+
+		TS_ASSERT_EQUALS(test->x, 1);
+		TS_ASSERT_EQUALS(test->y, 2);
+		TS_ASSERT_EQUALS(test->z, 3);
+		TS_ASSERT_EQUALS(test->a, 4);
+		TS_ASSERT_EQUALS(test->b, 5);
+		delete test;
+	}
+};


Commit: c5c09eece8f985835717904fff7c5b6b0c8b85d3
    https://github.com/scummvm/scummvm/commit/c5c09eece8f985835717904fff7c5b6b0c8b85d3
Author: Little Cat (toontownlittlecat at gmail.com)
Date: 2024-05-12T15:08:27+02:00

Commit Message:
SCUMM HE: Use Base64 to transfer map data

Hopefully this is more stable in keeping maps in sync between players
instead of relaying in an MD5 hash.

Changed paths:
    engines/scumm/he/moonbase/map_main.cpp
    engines/scumm/he/moonbase/map_main.h
    engines/scumm/he/net/net_main.cpp
    engines/scumm/he/net/net_main.h


diff --git a/engines/scumm/he/moonbase/map_main.cpp b/engines/scumm/he/moonbase/map_main.cpp
index f22cf7d0c0b..bf03537b502 100644
--- a/engines/scumm/he/moonbase/map_main.cpp
+++ b/engines/scumm/he/moonbase/map_main.cpp
@@ -22,7 +22,7 @@
 #include "common/compression/deflate.h"
 #include "common/config-manager.h"
 
-#include "common/md5.h"
+#include "common/base64.h"
 
 #include "common/memstream.h"
 #include "common/bufferedstream.h"
@@ -49,7 +49,7 @@ Map::Map(ScummEngine_v100he *vm) : _vm(vm), _rnd("moonbase") {
 	_terrain = -1;
 	_water = -1;
 
-	_mapHash = Common::String();
+	_encodedMap = Common::String();
 }
 
 Map::~Map() {
@@ -72,108 +72,112 @@ bool Map::generateNewMap() {
 	// map (or to debug with a prefixed seed).
 	_rnd.generateNewSeed();
 
-	int mapSize = 0;
 	if (ConfMan.hasKey("map_size"))
-		mapSize = ConfMan.getInt("map_size");
-	if (mapSize < 4 || mapSize > 10)
+		_size = ConfMan.getInt("map_size");
+	if (_size < 4 || _size > 10)
 		// Don't randomly pick nonstandard map sizes.
-		mapSize = _rnd.getRandomNumberRngSigned(4, 8);
+		_size = _rnd.getRandomNumberRngSigned(4, 8);
 
-	mapSize *= 8;
+	_size *= 8;
 
-	uint8 generator = 0;
 	if (ConfMan.hasKey("map_algorithm"))
-		generator = ConfMan.getInt("map_algorithm");
-	if (generator < SPIFF_GEN || generator > KATTON_GEN)
-		generator = _rnd.getRandomNumberRng(1, 2);
+		_generator = ConfMan.getInt("map_algorithm");
+	if (_generator < SPIFF_GEN || _generator > KATTON_GEN)
+		_generator = _rnd.getRandomNumberRng(1, 2);
 
-	int tileSet = 0;
 	if (ConfMan.hasKey("map_tileset"))
-		tileSet = ConfMan.getInt("map_tileset");
-	if (tileSet < 1 || tileSet > 6)
-		tileSet = _rnd.getRandomNumberRngSigned(1, 6);
+		_tileset = ConfMan.getInt("map_tileset");
+	if (_tileset < 1 || _tileset > 6)
+		_tileset = _rnd.getRandomNumberRngSigned(1, 6);
 
-	if (!strcmp(_vm->_game.variant, "Demo") && (tileSet == 1 ||
-		tileSet == 3 || tileSet == 5)) {
+	if (!strcmp(_vm->_game.variant, "Demo") && (_tileset == 1 ||
+		_tileset == 3 || _tileset == 5)) {
 		// Demo version only has tilesets 1, 2, 4 and 6.
 		switch (_rnd.getRandomNumber(3)) {
 		case 0:
-			tileSet = 1;
+			_tileset = 1;
 			break;
 		case 1:
-			tileSet = 2;
+			_tileset = 2;
 			break;
 		case 2:
-			tileSet = 4;
+			_tileset = 4;
 			break;
 		default:
-			tileSet = 6;
+			_tileset = 6;
 		}
 	}
 
-	int energy = -1;
 	if (ConfMan.hasKey("map_energy"))
-		energy = ConfMan.getInt("map_energy");
-	if (energy < 0 || energy > 6)
+		_energy = ConfMan.getInt("map_energy");
+	if (_energy < 0 || _energy > 6)
 		// Only use [2, 3, 4] of the legal [0, 1, 2, 3, 4, 5, 6]
-		energy = _rnd.getRandomNumberRngSigned(2, 4);
+		_energy = _rnd.getRandomNumberRngSigned(2, 4);
 
-	int terrain = -1;
 	if (ConfMan.hasKey("map_terrain"))
-		terrain = ConfMan.getInt("map_terrain");
-	if (terrain < 0 || terrain > 6)
+		_terrain = ConfMan.getInt("map_terrain");
+	if (_terrain < 0 || _terrain > 6)
 		// Only use [2, 3, 4] of the legal [0, 1, 2, 3, 4, 5, 6]
-		terrain = _rnd.getRandomNumberRngSigned(2, 4);
+		_terrain = _rnd.getRandomNumberRngSigned(2, 4);
 
-	int water = -1;
 	if (ConfMan.hasKey("map_water"))
-		water = ConfMan.getInt("map_water");
-	if (water < 0 || water > 6)
+		_water = ConfMan.getInt("map_water");
+	if (_water < 0 || _water > 6)
 		// Only use [2, 3, 4] of the legal [0, 1, 2, 3, 4, 5, 6]
-		water = _rnd.getRandomNumberRngSigned(2, 4);
+		_water = _rnd.getRandomNumberRngSigned(2, 4);
 
 	// 32767 is RAND_MAX on Windows
 	int seed = _rnd.getRandomNumber(32767);
 
-	return generateMapWithInfo(generator, seed, mapSize, tileSet, energy, terrain, water);
-}
-
-bool Map::generateMapWithInfo(uint8 generator, int seed, int mapSize, int tileset, int energy, int terrain, int water) {
-	deleteMap();
-
-	_generator = generator;
-	_seed = seed;
-	_size = mapSize;
-	_tileset = tileset;
-	_energy = energy;
-	_terrain = terrain;
-	_water = water;
-
-	debug(1, "Map: Generating new map with info: generator = %d, seed = %d, mapSize = %d, tileset = %d , energy = %d, terrain = %d, water = %d.", generator, getSeed(), mapSize, tileset, energy, terrain, water);
-	switch (generator) {
+	debug(1, "Map: Generating new map with info: generator = %d, seed = %d, size = %d, tileset = %d , energy = %d, terrain = %d, water = %d.", _generator, getSeed(), _size, _tileset, _energy, _terrain, _water);
+	switch (_generator) {
 	case SPIFF_GEN:
 	{
 		SpiffGenerator spiff = SpiffGenerator(seed);
-		_generatedMap = spiff.generateMap(water, tileset, mapSize, energy, terrain);
+		_generatedMap = spiff.generateMap(_water, _tileset, _size, _energy, _terrain);
 		break;
 	}
 	case KATTON_GEN:
 	{
 		KattonGenerator katton = KattonGenerator(seed);
-		_generatedMap = katton.generateMap(water, tileset, mapSize, energy, terrain);
+		_generatedMap = katton.generateMap(_water, _tileset, _size, _energy, _terrain);
 		break;
 	}
 	default:
-		error("Map: Got unknown generator: %d", generator);
+		error("Map: Got unknown generator: %d", _generator);
 		return false;
 	}
 
-	// Compute MD5 hash of the newly generated map file:
-	Common::MemoryReadStream mapStream = Common::MemoryReadStream((byte *)_generatedMap, sizeof(MapFile));
-	_mapHash = Common::computeStreamMD5AsString(mapStream, 0);
-	debug(1, "Map: MD5: %s", _mapHash.c_str());
+	// Encode the newly generated map file into base64 to transmit over the wire:
+	_encodedMap = Common::b64EncodeData(_generatedMap, sizeof(MapFile));
+	debug(2, "Map: Base64: %s", _encodedMap.c_str());
+
+	_mapGenerated = true;
+	return true;
+}
+
+bool Map::generateMapWithInfo(Common::String encodedMap, uint8 generator, int seed, int mapSize, int tileset, int energy, int terrain, int water) {
+	deleteMap();
 
+	_generator = generator;
+	_seed = seed;
+	_size = mapSize;
+	_tileset = tileset;
+	_energy = energy;
+	_terrain = terrain;
+	_water = water;
+	_encodedMap = encodedMap;
+
+	// Decode base64 encoded map file
+	debug(1, "Map: Generating map with base64: encodedMap: %s, generator = %d, seed = %d, mapSize = %d, tileset = %d , energy = %d, terrain = %d, water = %d.", encodedMap.c_str(), generator, getSeed(), mapSize, tileset, energy, terrain, water);
+	_generatedMap = new MapFile();
+	bool success = Common::b64DecodeData(encodedMap, _generatedMap);
+	if (!success) {
+		warning("Map: Error has occured when decoding map data from base64");
+		return false;
+	}
 	_mapGenerated = true;
+
 	return true;
 }
 
@@ -188,10 +192,10 @@ void Map::deleteMap() {
 		_size = 0;
 		_seed = 0;
 		_tileset = 0;
-		_energy = 0;
-		_terrain = 0;
-		_water = 0;
-		_mapHash = "";
+		_energy = -1;
+		_terrain = -1;
+		_water = -1;
+		_encodedMap = "";
 		debug(1, "Map: Deleted.");
 	}
 }
diff --git a/engines/scumm/he/moonbase/map_main.h b/engines/scumm/he/moonbase/map_main.h
index ac1d681672a..8d0c555a623 100644
--- a/engines/scumm/he/moonbase/map_main.h
+++ b/engines/scumm/he/moonbase/map_main.h
@@ -40,7 +40,7 @@ public:
 	~Map();
 
 	bool generateNewMap();
-	bool generateMapWithInfo(uint8 generator, int seed, int mapSize, int tileset, int energy, int terrain, int water);
+	bool generateMapWithInfo(Common::String encodedMap, uint8 generator, int seed, int mapSize, int tileset, int energy, int terrain, int water);
 	Common::SeekableReadStream *substituteFile(const byte *fileName);
 
 	void deleteMap();
@@ -77,8 +77,8 @@ public:
 		return _mapGenerated;
 	}
 
-	Common::String getHash() const {
-		return _mapHash;
+	Common::String getEncodedMap() const {
+		return _encodedMap;
 	}
 
 private:
@@ -99,7 +99,7 @@ private:
 
 	bool _mapGenerated;
 	MapFile *_generatedMap;
-	Common::String _mapHash;
+	Common::String _encodedMap;
 
 	Common::SeekableReadStream *makeWiz();
 };
diff --git a/engines/scumm/he/net/net_main.cpp b/engines/scumm/he/net/net_main.cpp
index 3d93c62905e..785efba95bc 100644
--- a/engines/scumm/he/net/net_main.cpp
+++ b/engines/scumm/he/net/net_main.cpp
@@ -80,7 +80,7 @@ Net::Net(ScummEngine_v90he *vm) : _latencyTime(1), _fakeLatency(false), _vm(vm)
 	_mapEnergy = 0;
 	_mapTerrain = 0;
 	_mapWater = 0;
-	_mapHash = Common::String();
+	_encodedMap = Common::String();
 
 	_hostPort = 0;
 
@@ -147,6 +147,7 @@ int Net::hostGame(char *sessionName, char *userName) {
 int Net::joinGame(Common::String IP, char *userName) {
 	debugC(DEBUG_NETWORK, "Net::joinGame(\"%s\", \"%s\")", IP.c_str(), userName); // PN_JoinTCPIPGame
 	Address address = getAddressFromString(IP);
+	bool getGeneratedMap = false;
 
 	bool isLocal = false;
 	// TODO: 20-bit block address (172.16.0.0 – 172.31.255.255)
@@ -182,14 +183,12 @@ int Net::joinGame(Common::String IP, char *userName) {
 			if (address.host == "255.255.255.255")
 				address.host = _sessions[0].host;
 			address.port = _sessions[0].port;
+			getGeneratedMap = _sessions[0].getGeneratedMap;
 
-			if (_gameName == "moonbase" && _sessions[0].mapGenerator > 0) {
-				generateMoonbaseMap(_sessions[0]);
-			}
 			stopQuerySessions();
 		}
 		// We got our address and port, attempt connection:
-		if (connectToSession(address.host, address.port)) {
+		if (connectToSession(address.host, address.port, getGeneratedMap)) {
 			// Connected, add our user.
 			return addUser(userName, userName);
 		} else {
@@ -202,7 +201,7 @@ int Net::joinGame(Common::String IP, char *userName) {
 	return 0;
 }
 
-bool Net::connectToSession(Common::String address, int port) {
+bool Net::connectToSession(Common::String address, int port, bool queryGeneratedMap) {
 	if (_hostPort)
 		_sessionHost = _enet->connectToHost("0.0.0.0", _hostPort, address, port);
 	else
@@ -210,6 +209,22 @@ bool Net::connectToSession(Common::String address, int port) {
 	if (!_sessionHost)
 		return false;
 
+	if (_gameName == "moonbase" && queryGeneratedMap) {
+		Common::String queryMap = Common::String("{\"cmd\":\"query_map\"}");
+
+		_sessionHost->send(queryMap.c_str(), 0, 0, true);
+
+		uint tickCount = 0;
+		while (_vm->_moonbase->_map->getGenerator() > 0) {
+			remoteReceiveData();
+			// Wait for five seconds for map data before giving up
+			tickCount += 5;
+			g_system->delayMillis(5);
+			if (tickCount >= 5000)
+				break;
+		}
+	}
+
 	return true;
 }
 
@@ -305,10 +320,10 @@ int Net::createSession(char *name) {
 			_mapEnergy = map->getEnergy();
 			_mapTerrain = map->getTerrain();
 			_mapWater = map->getWater();
-			_mapHash = map->getHash();
+			_encodedMap = map->getEncodedMap();
 			mapData = Common::String::format(
-				"{\"generator\":%d,\"seed\":%d,\"size\":%d,\"tileset\":%d,\"energy\":%d,\"terrain\":%d,\"water\":%d,\"hash\":\"%s\"}",
-				_mapGenerator, _mapSeed, _mapSize, _mapTileset, _mapEnergy, _mapTerrain, _mapWater, _mapHash.c_str());
+				"{\"generator\":%d,\"seed\":%d,\"size\":%d,\"tileset\":%d,\"energy\":%d,\"terrain\":%d,\"water\":%d,\"data\":\"%s\"}",
+				_mapGenerator, _mapSeed, _mapSize, _mapTileset, _mapEnergy, _mapTerrain, _mapWater, _encodedMap.c_str());
 		}
 	}
 
@@ -410,7 +425,7 @@ int Net::doJoinSession(Session session) {
 		generateMoonbaseMap(session);
 	}
 
-	bool success = connectToSession(session.host, session.port);
+	bool success = connectToSession(session.host, session.port, session.getGeneratedMap);
 	if (!success) {
 		if (!session.local) {
 			// Start up a relay session with the host.
@@ -446,23 +461,7 @@ int Net::doJoinSession(Session session) {
 }
 
 void Net::generateMoonbaseMap(Session session) {
-	uint8 mapAttempts = 0;
-	bool mapGenerated = false;
-	// Generate the host's map.
-	while (!mapGenerated) {
-		_vm->_moonbase->_map->generateMapWithInfo(session.mapGenerator, session.mapSeed, session.mapSize, session.mapTileset, session.mapEnergy, session.mapTerrain, session.mapWater);
-		if (_vm->_moonbase->_map->getHash() == session.mapHash) {
-			mapGenerated = true;
-		} else {
-			warning("NETWORK: Maps does not match, trying again...");
-			mapAttempts++;
-			if (mapAttempts == 10) {
-				// Maps are not matching... Give up.
-				warning("NETWORK: Unable to generate the host's map exactly. You may need to tell the host to disband and rehost the session. Continuing on, but expect mismatched stuff.");
-				mapGenerated = true;
-			}
-		}
-	}
+	_vm->_moonbase->_map->generateMapWithInfo(session.encodedMap, session.mapGenerator, session.mapSeed, session.mapSize, session.mapTileset, session.mapEnergy, session.mapTerrain, session.mapWater);
 }
 
 int Net::joinSession(int sessionIndex) {
@@ -545,7 +544,7 @@ int Net::endSession() {
 	_mapEnergy = 0;
 	_mapTerrain = 0;
 	_mapWater = 0;
-	_mapHash = "";
+	_encodedMap = "";
 
 	return 1;
 }
@@ -1033,7 +1032,7 @@ void Net::handleSessionServerData(Common::String data) {
 						if (mapData.contains("generator") && mapData.contains("seed") &&
 							mapData.contains("size") && mapData.contains("tileset") &&
 							mapData.contains("energy") && mapData.contains("terrain") &&
-							mapData.contains("water") && mapData.contains("hash")) {
+							mapData.contains("water") && mapData.contains("data")) {
 							session.mapGenerator = mapData["generator"]->asIntegerNumber();
 							session.mapSeed = mapData["seed"]->asIntegerNumber();
 							session.mapSize = mapData["size"]->asIntegerNumber();
@@ -1041,7 +1040,7 @@ void Net::handleSessionServerData(Common::String data) {
 							session.mapEnergy = mapData["energy"]->asIntegerNumber();
 							session.mapTerrain = mapData["terrain"]->asIntegerNumber();
 							session.mapWater = mapData["water"]->asIntegerNumber();
-							session.mapHash = mapData["hash"]->asString();
+							session.encodedMap = mapData["data"]->asString();
 						}
 					}
 					_sessions.push_back(session);
@@ -1145,16 +1144,9 @@ void Net::handleBroadcastData(Common::String data, Common::String host, int port
 		if (command == "get_session") {
 			// Session query.
 			if (_sessionHost) {
-				Common::String mapData = "{}";
-				if (_gameName == "moonbase" && _mapGenerator > 0) {
-					// Send over map data
-					mapData = Common::String::format(
-						"{\"generator\":%d,\"seed\":%d,\"size\":%d,\"tileset\":%d,\"energy\":%d,\"terrain\":%d,\"water\":%d,\"hash\":\"%s\"}",
-						_mapGenerator, _mapSeed, _mapSize, _mapTileset, _mapEnergy, _mapTerrain, _mapWater, _mapHash.c_str());
-				}
 				Common::String resp = Common::String::format(
-					"{\"cmd\":\"session_resp\",\"game\":\"%s\",\"version\":\"%s\",\"id\":%d,\"name\":\"%s\",\"players\":%d,\"map_data\":%s}",
-					_gameName.c_str(), _gameVersion.c_str(), _sessionId, _sessionName.c_str(), getTotalPlayers(), mapData.c_str());
+					"{\"cmd\":\"session_resp\",\"game\":\"%s\",\"version\":\"%s\",\"id\":%d,\"name\":\"%s\",\"players\":%d,\"generated_map\":%s}",
+					_gameName.c_str(), _gameVersion.c_str(), _sessionId, _sessionName.c_str(), getTotalPlayers(), _mapGenerator > 0 ? "true" : "false");
 
 				// Send this through the session host instead of the broadcast socket
 				// because that will send the correct port to connect to.
@@ -1207,21 +1199,8 @@ void Net::handleBroadcastData(Common::String data, Common::String host, int port
 				session.players = players;
 				session.timestamp = g_system->getMillis();
 
-				if (_gameName == "moonbase" && root.contains("map_data")) {
-					Common::JSONObject mapData = root["map_data"]->asObject();
-					if (mapData.contains("generator") && mapData.contains("seed") &&
-						mapData.contains("size") && mapData.contains("tileset") &&
-						mapData.contains("energy") && mapData.contains("terrain") &&
-						mapData.contains("water") && mapData.contains("hash")) {
-						session.mapGenerator = mapData["generator"]->asIntegerNumber();
-						session.mapSeed = mapData["seed"]->asIntegerNumber();
-						session.mapSize = mapData["size"]->asIntegerNumber();
-						session.mapTileset = mapData["tileset"]->asIntegerNumber();
-						session.mapEnergy = mapData["energy"]->asIntegerNumber();
-						session.mapTerrain = mapData["terrain"]->asIntegerNumber();
-						session.mapWater = mapData["water"]->asIntegerNumber();
-						session.mapHash = mapData["hash"]->asString();
-					}
+				if (_gameName == "moonbase" && root.contains("generated_map")) {
+					session.getGeneratedMap = root["generated_map"]->asBool();
 				}
 
 				_sessions.push_back(session);
@@ -1353,6 +1332,28 @@ void Net::remoteReceiveData() {
 						handleGameDataHost(json, peerIndex);
 					else
 						handleGameData(json, peerIndex);
+				} else if (_isHost && command == "query_map" && _gameName == "moonbase" && _mapGenerator > 0) {
+					// LAN connection wants generated map data
+					Common::String resp = Common::String::format(
+						"{\"cmd\":\"map_data\",\"generator\":%d,\"seed\":%d,\"size\":%d,\"tileset\":%d,\"energy\":%d,\"terrain\":%d,\"water\":%d,\"data\":\"%s\"}",
+						_mapGenerator, _mapSeed, _mapSize, _mapTileset, _mapEnergy, _mapTerrain, _mapWater, _encodedMap.c_str());
+					_sessionHost->send(resp.c_str(), peerIndex);
+				} else if (!_isHost && command == "map_data" && _gameName == "moonbase") {
+					if (root.contains("generator") && root.contains("seed") &&
+						root.contains("size") && root.contains("tileset") &&
+						root.contains("energy") && root.contains("terrain") &&
+						root.contains("water") && root.contains("data")) {
+						uint8 mapGenerator = root["generator"]->asIntegerNumber();
+						int mapSeed = root["seed"]->asIntegerNumber();
+						int mapSize = root["size"]->asIntegerNumber();
+						int mapTileset = root["tileset"]->asIntegerNumber();
+						int mapEnergy = root["energy"]->asIntegerNumber();
+						int mapTerrain = root["terrain"]->asIntegerNumber();
+						int mapWater = root["water"]->asIntegerNumber();
+						Common::String encodedMap = root["data"]->asString();
+
+						_vm->_moonbase->_map->generateMapWithInfo(encodedMap, mapGenerator, mapSeed, mapSize, mapTileset, mapEnergy, mapTerrain, mapWater);
+					}
 				}
 			}
 			if (_sessionHost)
diff --git a/engines/scumm/he/net/net_main.h b/engines/scumm/he/net/net_main.h
index af539345aed..a3fb800bb36 100644
--- a/engines/scumm/he/net/net_main.h
+++ b/engines/scumm/he/net/net_main.h
@@ -66,7 +66,9 @@ private:
 		int mapEnergy = 0;
 		int mapTerrain = 0;
 		int mapWater = 0;
-		Common::String mapHash;
+		Common::String encodedMap;
+		// Used to query map data over LAN.
+		bool getGeneratedMap = false;
 	};
 	/**
 	 * Converts a formatted string into an Address object.
@@ -369,13 +371,14 @@ private:
 	 *
 	 * @param address Address of a session to connect to.
 	 * @param port Port number of a session to connect to.
+	 * @param queryGeneratedMap Querys generated map data for Moonbase Commander (currently only used for LAN connections).
 	 * @retval true on success
 	 * @retval false on failure.
 	 *
 	 * @see joinGame
 	 * @see doJoinSession
 	 */
-	bool connectToSession(Common::String address, int port);
+	bool connectToSession(Common::String address, int port, bool queryGeneratedMap);
 
 	/**
 	 * Method that actually attemps to join a session.
@@ -560,7 +563,7 @@ private:
 	int _mapEnergy;
 	int _mapTerrain;
 	int _mapWater;
-	Common::String _mapHash;
+	Common::String _encodedMap;
 
 	bool _isShuttingDown;
 


Commit: 267bfc9d031e3635e8d5c75fdaa00ddefa87de8a
    https://github.com/scummvm/scummvm/commit/267bfc9d031e3635e8d5c75fdaa00ddefa87de8a
Author: Little Cat (toontownlittlecat at gmail.com)
Date: 2024-05-12T15:08:27+02:00

Commit Message:
COMMON: Base64 string validation.

Changed paths:
    common/base64.cpp
    common/base64.h
    test/common/base64.h


diff --git a/common/base64.cpp b/common/base64.cpp
index e96e7d40d0f..0175e076431 100644
--- a/common/base64.cpp
+++ b/common/base64.cpp
@@ -30,6 +30,35 @@ namespace Common {
 
 static const String encodingTable = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 
+bool b64Validate(String &string) {
+	bool paddingStarted = false;
+	// Base64 encoded strings uses 4 characters to encode 3 bytes.
+	// and thus, a fully encoded string are always divisable by 4.
+	// A padding character (=) may be used to ensure divisibility.
+	if ((strlen(string.c_str()) % 4) > 0)
+		return false;
+
+	// It must also use characters defined in the encoding table,
+	for (char c : string) {
+		if (!encodingTable.contains(c)) {
+			// or the padding character (=).
+			if (c != '=')
+				return false;
+		}
+
+		if (paddingStarted && c != '=') {
+			// Excess data after padding are not allowed.
+			return false;
+		}
+
+		if (c == '=' && !paddingStarted) {
+			paddingStarted = true;
+		}
+	}
+
+	return true;
+}
+
 String b64EncodeString(String &string) {
 	String out;
 	int32 val = 0, valb = -6;
@@ -94,7 +123,9 @@ String b64DecodeString(String &string) {
 	String out;
 	Common::Array<int> T(256, -1);
 
-	// TODO: Verify if its a proper Base64 encoded string.
+	if (!b64Validate(string))
+		// Return empty string.
+		return out;
 
 	for (int i = 0; i < 64; i++) {
 		T[encodingTable[i]] = i;
@@ -119,7 +150,11 @@ MemoryReadStream *b64DecodeStream(String &string, uint32 outputLength) {
 	char *out = (char *)malloc(outputLength);
 	Common::Array<int> T(256, -1);
 
-	// TODO: Verify if its a proper Base64 encoded string.
+	if (!b64Validate(string)) {
+		// Return nothing.
+		free(out);
+		return nullptr;
+	}
 
 	for (int i = 0; i < 64; i++) {
 		T[encodingTable[i]] = i;
@@ -144,7 +179,8 @@ bool b64DecodeData(String &string, void *dataPtr) {
 	uint8 *p = (uint8 *)dataPtr;
 	Common::Array<int> T(256, -1);
 
-	// TODO: Verify if its a proper Base64 encoded string.
+	if (!b64Validate(string))
+		return false;
 
 	for (int i = 0; i < 64; i++) {
 		T[encodingTable[i]] = i;
diff --git a/common/base64.h b/common/base64.h
index 6300bf662d9..8b49e4c0004 100644
--- a/common/base64.h
+++ b/common/base64.h
@@ -30,7 +30,7 @@ namespace Common {
  * @defgroup common_base64 Base64 encoding & decoding.
  * @ingroup common
  *
- * @brief API for encoding and decoing Base64 strings.
+ * @brief API for encoding and decoding Base64 strings.
  *
  * @{
  */
@@ -39,6 +39,14 @@ class MemoryReadStream;
 class ReadStream;
 class String;
 
+/**
+ * Validates a string to see if its a properly Base64 encoded string.
+ * This gets called when using the decode functions.
+ * @param[in] string	the string to validate
+ * @return true on success, false if an error occured.
+ */
+bool b64Validate(String &string);
+
 /**
  * Encodes a string into a Base64 encoded string.
  * @param[in] string	the string to encode
@@ -63,7 +71,7 @@ String b64EncodeData(void *dataPtr, size_t dataSize);
 /**
  * Decodes a Base64 encoded string into a regular string.
  * @param[in] string	base64 encoded string to decode
- * @return String containing the decoded result.
+ * @return String containing the decoded result, empty string if an error occured.
  */
 String b64DecodeString(String &string);
 
@@ -71,7 +79,7 @@ String b64DecodeString(String &string);
  * Decodes a Base64 encoded string into a MemoryReadStream, its contents
  * will be disposed when deleting the stream.
  * @param[in] string	base64 encoded string to decode
- * @return MemoryReadStream pointer containing the decoded result.
+ * @return MemoryReadStream pointer containing the decoded result, nullptr if an error occured
  */
 MemoryReadStream *b64DecodeStream(String &string, uint32 outputLength);
 
diff --git a/test/common/base64.h b/test/common/base64.h
index 5d59af741d9..bb4a5ce9ec8 100644
--- a/test/common/base64.h
+++ b/test/common/base64.h
@@ -24,6 +24,12 @@ static const char *base64_test_encoded[] = {
 		"c4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTA=")
 };
 
+static const char *base64_validate_tests[] = {
+	"YQ", // missing padding
+	"!@#$" // characters not in encoding table
+	"YQ==YWJj", // data after padding
+};
+
 #include <common/pack-start.h>	// START STRUCT PACKING
 
 struct Base64TestStruct {
@@ -38,11 +44,25 @@ struct Base64TestStruct {
 
 class Base64TestSuite : public CxxTest::TestSuite {
 	public:
+	void test_b64Validate() {
+		for (int i = 0; i < 6; i++) {
+			Common::String encoded = base64_test_encoded[i];
+			// All of these should return true.
+			TS_ASSERT_EQUALS(Common::b64Validate(encoded), true);
+		}
+		for (int i = 0; i < 3; i++) {
+			Common::String encoded = base64_validate_tests[i];
+			// All of these should return false.
+			TS_ASSERT_EQUALS(Common::b64Validate(encoded), false);
+		}
+
+	}
+
 	void test_b64EncodeString() {
 		for (int i = 0; i < 6; i++) {
 			Common::String string = base64_test_string[i];
 			Common::String encoded = Common::b64EncodeString(string);
-			TS_ASSERT_EQUALS(encoded, base64_test_encoded[i])
+			TS_ASSERT_EQUALS(encoded, base64_test_encoded[i]);
 		}
 	}
 
@@ -50,7 +70,7 @@ class Base64TestSuite : public CxxTest::TestSuite {
 		for (int i = 0; i < 6; i++) {
 			Common::MemoryReadStream stream((const byte *)base64_test_string[i], strlen(base64_test_string[i]));
 			Common::String encoded = Common::b64EncodeStream(stream);
-			TS_ASSERT_EQUALS(encoded, base64_test_encoded[i])
+			TS_ASSERT_EQUALS(encoded, base64_test_encoded[i]);
 		}
 	}
 


Commit: 4d3f6b7064b5fde460aab069ba8797a26aa9a3a3
    https://github.com/scummvm/scummvm/commit/4d3f6b7064b5fde460aab069ba8797a26aa9a3a3
Author: Little Cat (toontownlittlecat at gmail.com)
Date: 2024-05-12T15:08:27+02:00

Commit Message:
SCUMM HE: Fix compiling with HE v71+ disabled.

Changed paths:
    engines/scumm/he/intern_he.h
    engines/scumm/he/script_v60he.cpp
    engines/scumm/scumm.cpp


diff --git a/engines/scumm/he/intern_he.h b/engines/scumm/he/intern_he.h
index b3dbd56e873..b8e076ed075 100644
--- a/engines/scumm/he/intern_he.h
+++ b/engines/scumm/he/intern_he.h
@@ -47,7 +47,9 @@ class Moonbase;
 #endif
 
 class ScummEngine_v60he : public ScummEngine_v6 {
+#ifdef ENABLE_HE
 	friend class Moonbase;
+#endif
 protected:
 	enum SubOpType {
 		SO_ACTOR_DEFAULT_CLIPPED = 30,
@@ -77,8 +79,10 @@ public:
 	void setHETimer(int timer);
 	void pauseHETimers(bool pause);
 
+#ifdef ENABLE_HE
 public:
 	Moonbase *_moonbase;
+#endif
 
 public:
 	ScummEngine_v60he(OSystem *syst, const DetectorResult &dr);
diff --git a/engines/scumm/he/script_v60he.cpp b/engines/scumm/he/script_v60he.cpp
index 9e43bfc82ea..4be4d141c2b 100644
--- a/engines/scumm/he/script_v60he.cpp
+++ b/engines/scumm/he/script_v60he.cpp
@@ -188,11 +188,13 @@ Common::String ScummEngine_v60he::convertSavePathOld(const byte *src) {
 }
 
 Common::SeekableReadStream *ScummEngine_v60he::openFileForReading(const byte *fileName) {
+#ifdef ENABLE_HE
 	if (_moonbase) {
 		Common::SeekableReadStream *substitutedFile = _moonbase->_map->substituteFile(fileName);
 		if (substitutedFile)
 			return substitutedFile;
 	}
+#endif
 	Common::SeekableReadStream *saveFile = openSaveFileForReading(fileName);
 
 	if (saveFile)
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index 61b5b018ab8..a0d379bbffe 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -649,7 +649,9 @@ ScummEngine_v6::ScummEngine_v6(OSystem *syst, const DetectorResult &dr)
 
 ScummEngine_v60he::ScummEngine_v60he(OSystem *syst, const DetectorResult &dr)
 	: ScummEngine_v6(syst, dr) {
+#ifdef ENABLE_HE
 	_moonbase = 0;
+#endif
 
 	memset(_hInFileTable, 0, sizeof(_hInFileTable));
 	memset(_hOutFileTable, 0, sizeof(_hOutFileTable));


Commit: 5d462c5b9c3732171e2c2984daebd57c27300c5b
    https://github.com/scummvm/scummvm/commit/5d462c5b9c3732171e2c2984daebd57c27300c5b
Author: Little Cat (toontownlittlecat at gmail.com)
Date: 2024-05-12T15:08:27+02:00

Commit Message:
SCUMM HE: Set debug level for printing Base64 output to 2.

Changed paths:
    engines/scumm/he/moonbase/map_main.cpp


diff --git a/engines/scumm/he/moonbase/map_main.cpp b/engines/scumm/he/moonbase/map_main.cpp
index bf03537b502..19b91881b99 100644
--- a/engines/scumm/he/moonbase/map_main.cpp
+++ b/engines/scumm/he/moonbase/map_main.cpp
@@ -169,7 +169,7 @@ bool Map::generateMapWithInfo(Common::String encodedMap, uint8 generator, int se
 	_encodedMap = encodedMap;
 
 	// Decode base64 encoded map file
-	debug(1, "Map: Generating map with base64: encodedMap: %s, generator = %d, seed = %d, mapSize = %d, tileset = %d , energy = %d, terrain = %d, water = %d.", encodedMap.c_str(), generator, getSeed(), mapSize, tileset, energy, terrain, water);
+	debug(2, "Map: Generating map with base64: encodedMap: %s, generator = %d, seed = %d, mapSize = %d, tileset = %d , energy = %d, terrain = %d, water = %d.", encodedMap.c_str(), generator, getSeed(), mapSize, tileset, energy, terrain, water);
 	_generatedMap = new MapFile();
 	bool success = Common::b64DecodeData(encodedMap, _generatedMap);
 	if (!success) {


Commit: 814dc28d355309fbca8430d198360c6668e33c7f
    https://github.com/scummvm/scummvm/commit/814dc28d355309fbca8430d198360c6668e33c7f
Author: Michael Barlow (michaelbarlow7 at gmail.com)
Date: 2024-05-12T15:08:27+02:00

Commit Message:
SCUMM HE: Fix crash with no-water Katton maps

When generating a Katton map with no water, the code tries to modulo
a number by 0, which causes a crash. This fixes this.

Crash also occurs in original Moonbase Console.

Changed paths:
    engines/scumm/he/moonbase/map_katton.cpp


diff --git a/engines/scumm/he/moonbase/map_katton.cpp b/engines/scumm/he/moonbase/map_katton.cpp
index 3c02e6ed6f3..ae7ec5d09de 100644
--- a/engines/scumm/he/moonbase/map_katton.cpp
+++ b/engines/scumm/he/moonbase/map_katton.cpp
@@ -760,7 +760,12 @@ int KattonGenerator::randomflip(int numberofplaces, int inWater) {
 		x = getRandomNumber() % size;
 		y = getRandomNumber() % size;
 		if (board[x][y] == 0) {
-			temp = getRandomNumber() % inWater;
+			if (inWater == 0) {
+				temp = 0;
+			} else {
+				temp = getRandomNumber() % inWater;
+			}
+
 			if (temp <= 50) {
 				board[x][y] = 1;
 			}


Commit: 58f6e5ebe4aa789388f2c6a66daf779c088f734d
    https://github.com/scummvm/scummvm/commit/58f6e5ebe4aa789388f2c6a66daf779c088f734d
Author: Little Cat (toontownlittlecat at gmail.com)
Date: 2024-05-12T15:08:27+02:00

Commit Message:
SCUMM HE: Fix header defines.

Changed paths:
    engines/scumm/he/moonbase/map_data.h
    engines/scumm/he/moonbase/map_katton.h
    engines/scumm/he/moonbase/map_main.h
    engines/scumm/he/moonbase/map_mif.h
    engines/scumm/he/moonbase/map_spiff.h


diff --git a/engines/scumm/he/moonbase/map_data.h b/engines/scumm/he/moonbase/map_data.h
index 7d3f2f1ad7d..0edb52bd9ca 100644
--- a/engines/scumm/he/moonbase/map_data.h
+++ b/engines/scumm/he/moonbase/map_data.h
@@ -19,8 +19,8 @@
  *
  */
 
-#ifndef SCUMM_HE_MOONBASE_MAP_DATA
-#define SCUMM_HE_MOONBASE_MAP_DATA
+#ifndef SCUMM_HE_MOONBASE_MAP_DATA_H
+#define SCUMM_HE_MOONBASE_MAP_DATA_H
 
 // This header contains file data used by the map generator, mostly
 // the Template.thm and Template.wiz data taken from the Moonbase Console
@@ -390,4 +390,4 @@ const byte Template_wiz[] = {
   0xd1, 0xe8, 0xeb, 0x3a, 0x9b, 0x00, 0x00
 };
 
-#endif // SCUMM_HE_MOONBASE_MAP_DATA
+#endif // SCUMM_HE_MOONBASE_MAP_DATA_H
diff --git a/engines/scumm/he/moonbase/map_katton.h b/engines/scumm/he/moonbase/map_katton.h
index ba92db33d7b..94d8ff60390 100644
--- a/engines/scumm/he/moonbase/map_katton.h
+++ b/engines/scumm/he/moonbase/map_katton.h
@@ -19,8 +19,8 @@
  *
  */
 
-#ifndef SCUMM_HE_MOONBASE_MAP_KATTON
-#define SCUMM_HE_MOONBASE_MAP_KATTON
+#ifndef SCUMM_HE_MOONBASE_MAP_KATTON_H
+#define SCUMM_HE_MOONBASE_MAP_KATTON_H
 
 #ifdef ENABLE_HE
 
@@ -74,4 +74,4 @@ private:
 
 #endif // ENABLE_HE
 
-#endif // SCUMM_HE_MOONBASE_MAP_KATTON
+#endif // SCUMM_HE_MOONBASE_MAP_KATTON_H
diff --git a/engines/scumm/he/moonbase/map_main.h b/engines/scumm/he/moonbase/map_main.h
index 8d0c555a623..c717332c901 100644
--- a/engines/scumm/he/moonbase/map_main.h
+++ b/engines/scumm/he/moonbase/map_main.h
@@ -19,8 +19,8 @@
  *
  */
 
-#ifndef SCUMM_HE_MOONBASE_MAP_MAIN
-#define SCUMM_HE_MOONBASE_MAP_MAIN
+#ifndef SCUMM_HE_MOONBASE_MAP_MAIN_H
+#define SCUMM_HE_MOONBASE_MAP_MAIN_H
 
 #ifdef ENABLE_HE
 
@@ -109,4 +109,4 @@ private:
 
 #endif // ENABLE_HE
 
-#endif // SCUMM_HE_MOONBASE_MAP_MAIN
+#endif // SCUMM_HE_MOONBASE_MAP_MAIN_H
diff --git a/engines/scumm/he/moonbase/map_mif.h b/engines/scumm/he/moonbase/map_mif.h
index c28aa5f6910..4db2e06f8af 100644
--- a/engines/scumm/he/moonbase/map_mif.h
+++ b/engines/scumm/he/moonbase/map_mif.h
@@ -19,8 +19,8 @@
  *
  */
 
-#ifndef SCUMM_HE_MOONBASE_MAP_MIF
-#define SCUMM_HE_MOONBASE_MAP_MIF
+#ifndef SCUMM_HE_MOONBASE_MAP_MIF_H
+#define SCUMM_HE_MOONBASE_MAP_MIF_H
 
 #ifdef ENABLE_HE
 
@@ -30,7 +30,7 @@ namespace Scumm {
 
 #define MAX_TILE_COUNT 80
 
-#include <common/pack-start.h>	// START STRUCT PACKING
+#include "common/pack-start.h"	// START STRUCT PACKING
 
 typedef struct PixelLoc {
 	uint16 x;
@@ -73,7 +73,7 @@ struct MapFile {
 	}
 } PACKED_STRUCT;
 
-#include <common/pack-end.h>	// END STRUCT PACKING
+#include "common/pack-end.h"	// END STRUCT PACKING
 
 class MIF {
 public:
@@ -195,4 +195,4 @@ private:
 
 #endif // ENABLE_HE
 
-#endif // SCUMM_HE_MOONBASE_MAP_MIF
+#endif // SCUMM_HE_MOONBASE_MAP_MIF_H
diff --git a/engines/scumm/he/moonbase/map_spiff.h b/engines/scumm/he/moonbase/map_spiff.h
index 5be4c4821b3..7ded12bfee3 100644
--- a/engines/scumm/he/moonbase/map_spiff.h
+++ b/engines/scumm/he/moonbase/map_spiff.h
@@ -19,8 +19,8 @@
  *
  */
 
-#ifndef SCUMM_HE_MOONBASE_MAP_SPIFF
-#define SCUMM_HE_MOONBASE_MAP_SPIFF
+#ifndef SCUMM_HE_MOONBASE_MAP_SPIFF_H
+#define SCUMM_HE_MOONBASE_MAP_SPIFF_H
 
 #ifdef ENABLE_HE
 
@@ -92,4 +92,4 @@ private:
 
 #endif // ENABLE_HE
 
-#endif // SCUMM_HE_MOONBASE_MAP_SPIFF
+#endif // SCUMM_HE_MOONBASE_MAP_SPIFF_H


Commit: ebebbb2b740b44a5604de71ba88f61c7323967be
    https://github.com/scummvm/scummvm/commit/ebebbb2b740b44a5604de71ba88f61c7323967be
Author: Little Cat (toontownlittlecat at gmail.com)
Date: 2024-05-12T15:08:27+02:00

Commit Message:
SCUMM HE: Rename "cornerSum"

Changed paths:
    engines/scumm/he/moonbase/map_mif.cpp


diff --git a/engines/scumm/he/moonbase/map_mif.cpp b/engines/scumm/he/moonbase/map_mif.cpp
index fe2f6bb924c..127e801aeac 100644
--- a/engines/scumm/he/moonbase/map_mif.cpp
+++ b/engines/scumm/he/moonbase/map_mif.cpp
@@ -327,9 +327,9 @@ uint16 MIF::findTileFor(int x, int y) {
 		if (0 == tlCorner(x, y) || 0 == trCorner(x, y) || 0 == blCorner(x, y) || 0 == brCorner(x, y)) {
 			// Corner cases
 
-			int CornerSum = tlCorner(x, y) + trCorner(x, y) + blCorner(x, y) + brCorner(x, y);
+			int cornerSum = tlCorner(x, y) + trCorner(x, y) + blCorner(x, y) + brCorner(x, y);
 
-			if (1 == CornerSum) {
+			if (1 == cornerSum) {
 				if (tlCorner(x, y)) {
 					if (tllCorner(x, y) > 0 && ttlCorner(x, y) > 0)
 						return 0x03;
@@ -531,9 +531,9 @@ uint16 MIF::findTileFor(int x, int y) {
 		if (1 == tlCorner(x, y) || 1 == trCorner(x, y) || 1 == blCorner(x, y) || 1 == brCorner(x, y)) {
 			// Corner cases
 
-			int CornerSum = (tlCorner(x, y) == 2) + (trCorner(x, y) == 2) + (blCorner(x, y) == 2) + (brCorner(x, y) == 2);
+			int cornerSum = (tlCorner(x, y) == 2) + (trCorner(x, y) == 2) + (blCorner(x, y) == 2) + (brCorner(x, y) == 2);
 
-			if (1 == CornerSum) {
+			if (1 == cornerSum) {
 				if (tlCorner(x, y) == 2) {
 					if (tllCorner(x, y) == 2 && ttlCorner(x, y) == 2)
 						return 0x10;


Commit: 2d5eb18c5703120cbb37cde9d0af6a189cdd1902
    https://github.com/scummvm/scummvm/commit/2d5eb18c5703120cbb37cde9d0af6a189cdd1902
Author: Little Cat (toontownlittlecat at gmail.com)
Date: 2024-05-12T15:08:27+02:00

Commit Message:
 SCUMM HE: Add an underscroll to all class variables.

Changed paths:
    engines/scumm/he/moonbase/map_katton.cpp
    engines/scumm/he/moonbase/map_katton.h
    engines/scumm/he/moonbase/map_mif.cpp
    engines/scumm/he/moonbase/map_mif.h
    engines/scumm/he/moonbase/map_spiff.cpp
    engines/scumm/he/moonbase/map_spiff.h


diff --git a/engines/scumm/he/moonbase/map_katton.cpp b/engines/scumm/he/moonbase/map_katton.cpp
index ae7ec5d09de..07dcf170ca6 100644
--- a/engines/scumm/he/moonbase/map_katton.cpp
+++ b/engines/scumm/he/moonbase/map_katton.cpp
@@ -44,8 +44,8 @@ int KattonGenerator::getRandomNumber() {
 }
 
 MapFile *KattonGenerator::generateMap(int water, int tileSet, int mapSize, int energy, int terrain) {
-	size = mapSize;
-	tileset = tileSet;
+	_size = mapSize;
+	_tileset = tileSet;
 	int inEnergy = energy;
 	int inTerrain = terrain;
 	int inWater = water;
@@ -82,39 +82,39 @@ MapFile *KattonGenerator::generateMap(int water, int tileSet, int mapSize, int e
 
 	//****************************************Make the basic landmass shapes.
 
-	numsplotches = (int)(size / 4) + (int)((terrainpercent - 0.5) * size / 2);
+	numsplotches = (int)(_size / 4) + (int)((terrainpercent - 0.5) * _size / 2);
 
 	for (i = 0; i < numsplotches; i++) {
-		length = (int)(((1 - waterpercent) / 6 * size * size) / numsplotches);
+		length = (int)(((1 - waterpercent) / 6 * _size * _size) / numsplotches);
 		length = length + plusminus((int)(length / 2));
 		stringiness = 1 + plusminus(1);
-		randomx = getRandomNumber() % size;
-		randomy = getRandomNumber() % size;
+		randomx = getRandomNumber() % _size;
+		randomy = getRandomNumber() % _size;
 		randomsplotch(length, 1 + stringiness, 2, randomx, randomy);
 	}
 
 	for (i = 0; i < (int)numsplotches / 4; i++) {
-		length = (int)(((1 - waterpercent) / 3 * size * size) / numsplotches);
+		length = (int)(((1 - waterpercent) / 3 * _size * _size) / numsplotches);
 		length = length + plusminus((int)(length / 4));
 		stringiness = 1 + plusminus(1);
-		randomx = getRandomNumber() % size;
-		randomy = getRandomNumber() % size;
+		randomx = getRandomNumber() % _size;
+		randomy = getRandomNumber() % _size;
 		randomsplotch(length, stringiness, 1, randomx, randomy);
 	}
 
 	for (i = 0; i < (int)numsplotches / 2; i++) {
-		length = (int)(size + plusminus((int)(size / 2)));
+		length = (int)(_size + plusminus((int)(_size / 2)));
 		stringiness = 1 + plusminus(1);
-		randomx = getRandomNumber() % size;
-		randomy = getRandomNumber() % size;
+		randomx = getRandomNumber() % _size;
+		randomy = getRandomNumber() % _size;
 		randomsplotch(length, stringiness, 0, randomx, randomy);
 	}
 
-	for (i = 0; i < (int)waterpercent * size; i++) {
-		length = (int)(size + plusminus((int)(size / 2)));
+	for (i = 0; i < (int)waterpercent * _size; i++) {
+		length = (int)(_size + plusminus((int)(_size / 2)));
 		stringiness = 1 + plusminus(1);
-		randomx = getRandomNumber() % size;
-		randomy = getRandomNumber() % size;
+		randomx = getRandomNumber() % _size;
+		randomy = getRandomNumber() % _size;
 		randomsplotch(length, stringiness, 0, randomx, randomy);
 	}
 
@@ -137,7 +137,7 @@ MapFile *KattonGenerator::generateMap(int water, int tileSet, int mapSize, int e
 
 	//****************************************Smooth out/rough up the landmasses
 
-	randomflip((int)(terrainpercent * terrainpercent * size * size / 4 + size / 4), inWater);
+	randomflip((int)(terrainpercent * terrainpercent * _size * _size / 4 + _size / 4), inWater);
 
 	//****************************************Make the start locations
 
@@ -145,8 +145,8 @@ MapFile *KattonGenerator::generateMap(int water, int tileSet, int mapSize, int e
 
 	//****************************************Put down some water
 
-	for (i = 0; i < size; i += 2) {
-		for (j = 0; j < size; j += 2) {
+	for (i = 0; i < _size; i += 2) {
+		for (j = 0; j < _size; j += 2) {
 			if (goodforwater(i, j)) {
 				goodwater[numwaterplaces][0] = i;
 				goodwater[numwaterplaces][1] = j;
@@ -155,7 +155,7 @@ MapFile *KattonGenerator::generateMap(int water, int tileSet, int mapSize, int e
 		}
 	}
 
-	numwatersplotches = (int)(size * waterpercent * waterpercent * 5);
+	numwatersplotches = (int)(_size * waterpercent * waterpercent * 5);
 
 	if (numwaterplaces <= numwatersplotches) {
 		numwatersplotches = numwaterplaces;
@@ -167,7 +167,7 @@ MapFile *KattonGenerator::generateMap(int water, int tileSet, int mapSize, int e
 			z = getRandomNumber() % multiplier + i * multiplier;
 			x = goodwater[z][0];
 			y = goodwater[z][1];
-			length = size + plusminus(size / 2);
+			length = _size + plusminus(_size / 2);
 			stringiness = getRandomNumber() % 3;
 			randomwater(length, stringiness, x, y);
 		}
@@ -177,32 +177,32 @@ MapFile *KattonGenerator::generateMap(int water, int tileSet, int mapSize, int e
 	if (inEnergy >= 90) {
 		maxnumclose = 2;
 		maxnumfar = 3;
-		maxnumrand = (int)(size * size / 150);
+		maxnumrand = (int)(_size * _size / 150);
 		smallmed = 2;
 	} else if (inEnergy >= 75) {
 		maxnumclose = 2;
 		maxnumfar = 1;
-		maxnumrand = (int)(size * size / 250) + 4;
+		maxnumrand = (int)(_size * _size / 250) + 4;
 		smallmed = 3;
 	} else if (inEnergy >= 60) {
 		maxnumclose = 1;
 		maxnumfar = 2;
-		maxnumrand = (int)(size * size / 250);
+		maxnumrand = (int)(_size * _size / 250);
 		smallmed = 4;
 	} else if (inEnergy >= 45) {
 		maxnumclose = 1;
 		maxnumfar = 1;
-		maxnumrand = (int)(size * size / 250);
+		maxnumrand = (int)(_size * _size / 250);
 		smallmed = 6;
 	} else if (inEnergy >= 30) {
 		maxnumclose = 1;
 		maxnumfar = 0;
-		maxnumrand = (int)(size * size / 350) + 2;
+		maxnumrand = (int)(_size * _size / 350) + 2;
 		smallmed = 8;
 	} else if (inEnergy >= 15) {
 		maxnumclose = 0;
 		maxnumfar = 1;
-		maxnumrand = (int)(size * size / 450);
+		maxnumrand = (int)(_size * _size / 450);
 		smallmed = 10;
 	} else if (inEnergy >= 0) {
 		maxnumclose = 0;
@@ -214,13 +214,13 @@ MapFile *KattonGenerator::generateMap(int water, int tileSet, int mapSize, int e
 	for (i = 0; i < 4; i++) {
 		numplaceClose = 0;
 		numplaceFar = 0;
-		for (j = 0; j < size; j++) {
-			for (k = 0; k < size; k++) {
-				if ((goodforenergy(j, k, 0)) && (distance(startloc[i][0], startloc[i][1], j, k) >= (int)(size / 10)) && (distance(startloc[i][0], startloc[i][1], j, k) <= (int)(size / 8))) {
+		for (j = 0; j < _size; j++) {
+			for (k = 0; k < _size; k++) {
+				if ((goodforenergy(j, k, 0)) && (distance(_startloc[i][0], _startloc[i][1], j, k) >= (int)(_size / 10)) && (distance(_startloc[i][0], _startloc[i][1], j, k) <= (int)(_size / 8))) {
 					goodplaceClose[numplaceClose][0] = j;
 					goodplaceClose[numplaceClose][1] = k;
 					numplaceClose++;
-				} else if ((goodforenergy(j, k, 0)) && (distance(startloc[i][0], startloc[i][1], j, k) >= (int)(size / 7)) && (distance(startloc[i][0], startloc[i][1], j, k) <= (int)(size / 5))) {
+				} else if ((goodforenergy(j, k, 0)) && (distance(_startloc[i][0], _startloc[i][1], j, k) >= (int)(_size / 7)) && (distance(_startloc[i][0], _startloc[i][1], j, k) <= (int)(_size / 5))) {
 					goodplaceFar[numplaceFar][0] = j;
 					goodplaceFar[numplaceFar][1] = k;
 					numplaceFar++;
@@ -236,11 +236,11 @@ MapFile *KattonGenerator::generateMap(int water, int tileSet, int mapSize, int e
 
 		if (numplaceClose >= maxnumclose) {
 			for (l = 0; l < maxnumclose; l++) {
-				special[goodplaceClose[placeClose[l]][0]][goodplaceClose[placeClose[l]][1]] = 100;
+				_special[goodplaceClose[placeClose[l]][0]][goodplaceClose[placeClose[l]][1]] = 100;
 			}
 		} else {
 			for (l = 0; l < numplaceClose; l++) {
-				special[goodplaceClose[placeClose[l]][0]][goodplaceClose[placeClose[l]][1]] = 100;
+				_special[goodplaceClose[placeClose[l]][0]][goodplaceClose[placeClose[l]][1]] = 100;
 			}
 		}
 
@@ -256,11 +256,11 @@ MapFile *KattonGenerator::generateMap(int water, int tileSet, int mapSize, int e
 
 		if (numplaceFar >= maxnumfar) {
 			for (l = 0; l < maxnumfar; l++) {
-				special[goodplaceFar[placeFar[l]][0]][goodplaceFar[placeFar[l]][1]] = 100;
+				_special[goodplaceFar[placeFar[l]][0]][goodplaceFar[placeFar[l]][1]] = 100;
 			}
 		} else {
 			for (l = 0; l < numplaceFar; l++) {
-				special[goodplaceFar[placeFar[l]][0]][goodplaceFar[placeFar[l]][1]] = 100;
+				_special[goodplaceFar[placeFar[l]][0]][goodplaceFar[placeFar[l]][1]] = 100;
 			}
 		}
 	}
@@ -269,40 +269,40 @@ MapFile *KattonGenerator::generateMap(int water, int tileSet, int mapSize, int e
 	counterpools = 4 * (maxnumfar + maxnumclose);
 	for (k = 0; k < maxnumrand && counterpools < 50; k++) {
 		do {
-			i = getRandomNumber() % size;
-			j = getRandomNumber() % size;
+			i = getRandomNumber() % _size;
+			j = getRandomNumber() % _size;
 			counter++;
-		} while (!((distance(i, j, startloc[0][0], startloc[0][1]) >= 10) && (distance(i, j, startloc[1][0], startloc[1][1]) >= 10) && (distance(i, j, startloc[2][0], startloc[2][1]) >= 10) && (distance(i, j, startloc[3][0], startloc[3][1]) >= 10) && (goodforenergy(i, j, 1)) && (counter < 5000)));
+		} while (!((distance(i, j, _startloc[0][0], _startloc[0][1]) >= 10) && (distance(i, j, _startloc[1][0], _startloc[1][1]) >= 10) && (distance(i, j, _startloc[2][0], _startloc[2][1]) >= 10) && (distance(i, j, _startloc[3][0], _startloc[3][1]) >= 10) && (goodforenergy(i, j, 1)) && (counter < 5000)));
 		if (getRandomNumber() % smallmed == 0) {
-			special[i][j] = 200;
+			_special[i][j] = 200;
 			counterpools++;
 		} else {
-			special[i][j] = 100;
+			_special[i][j] = 100;
 			counterpools++;
 		}
 	}
 
 	//****************************************Do that saving thing that you do, BABY!
 	MIF mif = MIF();
-	Common::sprintf_s(mif.name, "Katton %04X", (uint16)_seed);
-	mif.dimension = size;
-	mif.mapType = tileset;
-	for (j = 0; j < size; j++) {
-		for (i = 0; i < size; i++)
-			mif.cornerMap[i][j] = board[i][j];
-		for (i = 0; i < size; i++)
-			if (special[i][j] == 0)
-				mif.centerMap[i][j] = '.';
-			else if (special[i][j] == -1)
-				mif.centerMap[i][j] = 'W';
-			else if (special[i][j] == 100)
-				mif.centerMap[i][j] = 'S';
-			else if (special[i][j] == 200)
-				mif.centerMap[i][j] = 'M';
-			else if (special[i][j] == 300)
-				mif.centerMap[i][j] = 'L';
+	Common::sprintf_s(mif._name, "Katton %04X", (uint16)_seed);
+	mif._dimension = _size;
+	mif._mapType = _tileset;
+	for (j = 0; j < _size; j++) {
+		for (i = 0; i < _size; i++)
+			mif._cornerMap[i][j] = _board[i][j];
+		for (i = 0; i < _size; i++)
+			if (_special[i][j] == 0)
+				mif._centerMap[i][j] = '.';
+			else if (_special[i][j] == -1)
+				mif._centerMap[i][j] = 'W';
+			else if (_special[i][j] == 100)
+				mif._centerMap[i][j] = 'S';
+			else if (_special[i][j] == 200)
+				mif._centerMap[i][j] = 'M';
+			else if (_special[i][j] == 300)
+				mif._centerMap[i][j] = 'L';
 			else
-				mif.centerMap[i][j] = -special[i][j];
+				mif._centerMap[i][j] = -_special[i][j];
 	}
 
 	// Generate new map:
@@ -314,8 +314,8 @@ MapFile *KattonGenerator::generateMap(int water, int tileSet, int mapSize, int e
 
 int KattonGenerator::distance(int x1, int y1, int x2, int y2) {
 	int dx, dy, disp;
-	dx = min((abs(x1 - x2)), (abs(x1 + size - x2)), (abs(x2 + size - x1)));
-	dy = min((abs(y1 - y2)), (abs(y1 + size - y2)), (abs(y2 + size - y1)));
+	dx = min((abs(x1 - x2)), (abs(x1 + _size - x2)), (abs(x2 + _size - x1)));
+	dy = min((abs(y1 - y2)), (abs(y1 + _size - y2)), (abs(y2 + _size - y1)));
 	disp = (int)sqrt((double)(dx * dx + dy * dy));
 	return disp;
 }
@@ -335,9 +335,9 @@ int KattonGenerator::min(int a, int b, int c) {
 int KattonGenerator::goodforenergy(int x, int y, int poolsize) {
 	switch (poolsize) {
 	case 0:
-		if ((board[x][y] == board[findcoord(x, +1)][y]) && (board[findcoord(x, +1)][y] == board[x][findcoord(y, +1)]) && (board[x][findcoord(y, +1)] == board[findcoord(x, +1)][findcoord(y, +1)])) {
+		if ((_board[x][y] == _board[findcoord(x, +1)][y]) && (_board[findcoord(x, +1)][y] == _board[x][findcoord(y, +1)]) && (_board[x][findcoord(y, +1)] == _board[findcoord(x, +1)][findcoord(y, +1)])) {
 			//check main map
-			if (special[x][y] == 0) { //specials are clear
+			if (_special[x][y] == 0) { //specials are clear
 				return 1;
 			} else {
 				return 0;
@@ -346,8 +346,8 @@ int KattonGenerator::goodforenergy(int x, int y, int poolsize) {
 			return 0;
 		}
 	case 1:
-		if ((board[x][y] == board[findcoord(x, +1)][y]) && (board[findcoord(x, +1)][y] == board[x][findcoord(y, +1)]) && (board[x][findcoord(y, +1)] == board[findcoord(x, +1)][findcoord(y, +1)])) { //check main map
-			if ((special[x][y] == 0) && (special[findcoord(x, +1)][y] == 0) && (special[x][findcoord(y, +1)] == 0) && (special[findcoord(x, +1)][findcoord(y, +1)] == 0)) {                           //specials are clear
+		if ((_board[x][y] == _board[findcoord(x, +1)][y]) && (_board[findcoord(x, +1)][y] == _board[x][findcoord(y, +1)]) && (_board[x][findcoord(y, +1)] == _board[findcoord(x, +1)][findcoord(y, +1)])) { //check main map
+			if ((_special[x][y] == 0) && (_special[findcoord(x, +1)][y] == 0) && (_special[x][findcoord(y, +1)] == 0) && (_special[findcoord(x, +1)][findcoord(y, +1)] == 0)) {                           //specials are clear
 				return 1;
 			} else {
 				return 0;
@@ -370,10 +370,10 @@ int KattonGenerator::plusminus(int max) {
 
 int KattonGenerator::fillboards(int num) {
 	int i, j;
-	for (i = 0; i < size; i++) {
-		for (j = 0; j < size; j++) {
-			board[i][j] = num;
-			special[i][j] = num;
+	for (i = 0; i < _size; i++) {
+		for (j = 0; j < _size; j++) {
+			_board[i][j] = num;
+			_special[i][j] = num;
 		}
 	}
 	return 0;
@@ -382,9 +382,9 @@ int KattonGenerator::fillboards(int num) {
 int KattonGenerator::randomplace(int numberofplaces, int placer) {
 	int i, randx, randy;
 	for (i = 0; i < numberofplaces; i++) {
-		randx = (getRandomNumber() % size);
-		randy = (getRandomNumber() % size);
-		board[randx][randy] = placer;
+		randx = (getRandomNumber() % _size);
+		randy = (getRandomNumber() % _size);
+		_board[randx][randy] = placer;
 	}
 	return 0;
 }
@@ -394,7 +394,7 @@ int KattonGenerator::randomsplotch(int length, int stringiness, int placer, int
 	currx = x;
 	curry = y;
 	while (i <= length) {
-		board[currx][curry] = placer;
+		_board[currx][curry] = placer;
 		prevdirection = direction;
 		direction = (getRandomNumber() % 4);
 		if ((((direction + 2) == prevdirection) || ((direction - 2) == prevdirection)) && (stringiness == 2)) {
@@ -428,23 +428,23 @@ int KattonGenerator::randomsplotch(int length, int stringiness, int placer, int
 }
 
 int KattonGenerator::findcoord(int value, int move) {
-	move = move % size;
+	move = move % _size;
 	int final = value + move;
 	if (final < 0) {
-		final = size + final;
+		final = _size + final;
 	}
-	if (final >= size) {
-		final = final % size;
+	if (final >= _size) {
+		final = final % _size;
 	}
 	return final;
 }
 
 int KattonGenerator::replacenum(int replacee, int replacer) {
 	int i, j;
-	for (j = 0; j < size; j++) {
-		for (i = 0; i < size; i++) {
-			if (board[i][j] == replacee) {
-				board[i][j] = replacer;
+	for (j = 0; j < _size; j++) {
+		for (i = 0; i < _size; i++) {
+			if (_board[i][j] == replacee) {
+				_board[i][j] = replacer;
 			}
 		}
 	}
@@ -453,9 +453,9 @@ int KattonGenerator::replacenum(int replacee, int replacer) {
 
 int KattonGenerator::fattenall(int howfat, int middle, int ignorer, int replacer) {
 	int i, j, temp;
-	for (j = 0; j < size; j++) {
-		for (i = 0; i < size; i++) {
-			if (board[i][j] == middle) {
+	for (j = 0; j < _size; j++) {
+		for (i = 0; i < _size; i++) {
+			if (_board[i][j] == middle) {
 				if (howfat <= 0) {
 					temp = (int)(abs(howfat) + plusminus(2));
 					if (temp <= 1) {
@@ -474,50 +474,50 @@ int KattonGenerator::fattenall(int howfat, int middle, int ignorer, int replacer
 }
 int KattonGenerator::fattenone(int x, int y, int howfat, int middle, int ignorer, int replacer) {
 	if (howfat == -100) {
-		board[x][y] = replacer;
-		board[findcoord(x, +1)][y] = replacer;
-		board[x][findcoord(y, +1)] = replacer;
-		board[findcoord(x, +1)][findcoord(y, +1)] = replacer;
+		_board[x][y] = replacer;
+		_board[findcoord(x, +1)][y] = replacer;
+		_board[x][findcoord(y, +1)] = replacer;
+		_board[findcoord(x, +1)][findcoord(y, +1)] = replacer;
 	}
 	if (howfat >= 1) {
-		board[x][findcoord(y, -1)] = ((board[x][findcoord(y, -1)] == middle) || (board[x][findcoord(y, -1)] == ignorer)) ? board[x][findcoord(y, -1)] : replacer;
-		board[x][findcoord(y, +1)] = ((board[x][findcoord(y, +1)] == middle) || (board[x][findcoord(y, +1)] == ignorer)) ? board[x][findcoord(y, +1)] : replacer;
-		board[findcoord(x, -1)][y] = ((board[findcoord(x, -1)][y] == middle) || (board[findcoord(x, -1)][y] == ignorer)) ? board[findcoord(x, -1)][y] : replacer;
-		board[findcoord(x, +1)][y] = ((board[findcoord(x, +1)][y] == middle) || (board[findcoord(x, +1)][y] == ignorer)) ? board[findcoord(x, +1)][y] : replacer;
+		_board[x][findcoord(y, -1)] = ((_board[x][findcoord(y, -1)] == middle) || (_board[x][findcoord(y, -1)] == ignorer)) ? _board[x][findcoord(y, -1)] : replacer;
+		_board[x][findcoord(y, +1)] = ((_board[x][findcoord(y, +1)] == middle) || (_board[x][findcoord(y, +1)] == ignorer)) ? _board[x][findcoord(y, +1)] : replacer;
+		_board[findcoord(x, -1)][y] = ((_board[findcoord(x, -1)][y] == middle) || (_board[findcoord(x, -1)][y] == ignorer)) ? _board[findcoord(x, -1)][y] : replacer;
+		_board[findcoord(x, +1)][y] = ((_board[findcoord(x, +1)][y] == middle) || (_board[findcoord(x, +1)][y] == ignorer)) ? _board[findcoord(x, +1)][y] : replacer;
 	}
 	if (howfat >= 2) {
-		board[findcoord(x, -1)][findcoord(y, -1)] = ((board[findcoord(x, -1)][findcoord(y, -1)] == middle) || (board[findcoord(x, -1)][findcoord(y, -1)] == ignorer)) ? board[findcoord(x, -1)][findcoord(y, -1)] : replacer;
-		board[findcoord(x, -1)][findcoord(y, +1)] = ((board[findcoord(x, -1)][findcoord(y, +1)] == middle) || (board[findcoord(x, -1)][findcoord(y, +1)] == ignorer)) ? board[findcoord(x, -1)][findcoord(y, +1)] : replacer;
-		board[findcoord(x, +1)][findcoord(y, -1)] = ((board[findcoord(x, +1)][findcoord(y, -1)] == middle) || (board[findcoord(x, +1)][findcoord(y, -1)] == ignorer)) ? board[findcoord(x, +1)][findcoord(y, -1)] : replacer;
-		board[findcoord(x, +1)][findcoord(y, +1)] = ((board[findcoord(x, +1)][findcoord(y, +1)] == middle) || (board[findcoord(x, +1)][findcoord(y, +1)] == ignorer)) ? board[findcoord(x, +1)][findcoord(y, +1)] : replacer;
+		_board[findcoord(x, -1)][findcoord(y, -1)] = ((_board[findcoord(x, -1)][findcoord(y, -1)] == middle) || (_board[findcoord(x, -1)][findcoord(y, -1)] == ignorer)) ? _board[findcoord(x, -1)][findcoord(y, -1)] : replacer;
+		_board[findcoord(x, -1)][findcoord(y, +1)] = ((_board[findcoord(x, -1)][findcoord(y, +1)] == middle) || (_board[findcoord(x, -1)][findcoord(y, +1)] == ignorer)) ? _board[findcoord(x, -1)][findcoord(y, +1)] : replacer;
+		_board[findcoord(x, +1)][findcoord(y, -1)] = ((_board[findcoord(x, +1)][findcoord(y, -1)] == middle) || (_board[findcoord(x, +1)][findcoord(y, -1)] == ignorer)) ? _board[findcoord(x, +1)][findcoord(y, -1)] : replacer;
+		_board[findcoord(x, +1)][findcoord(y, +1)] = ((_board[findcoord(x, +1)][findcoord(y, +1)] == middle) || (_board[findcoord(x, +1)][findcoord(y, +1)] == ignorer)) ? _board[findcoord(x, +1)][findcoord(y, +1)] : replacer;
 	}
 	if (howfat >= 3) {
-		board[x][findcoord(y, -2)] = ((board[x][findcoord(y, -2)] == middle) || (board[x][findcoord(y, -2)] == ignorer)) ? board[x][findcoord(y, -2)] : replacer;
-		board[x][findcoord(y, +2)] = ((board[x][findcoord(y, +2)] == middle) || (board[x][findcoord(y, +2)] == ignorer)) ? board[x][findcoord(y, +2)] : replacer;
-		board[findcoord(x, -2)][y] = ((board[findcoord(x, -2)][y] == middle) || (board[findcoord(x, -2)][y] == ignorer)) ? board[findcoord(x, -2)][y] : replacer;
-		board[findcoord(x, +2)][y] = ((board[findcoord(x, +2)][y] == middle) || (board[findcoord(x, +2)][y] == ignorer)) ? board[findcoord(x, +2)][y] : replacer;
+		_board[x][findcoord(y, -2)] = ((_board[x][findcoord(y, -2)] == middle) || (_board[x][findcoord(y, -2)] == ignorer)) ? _board[x][findcoord(y, -2)] : replacer;
+		_board[x][findcoord(y, +2)] = ((_board[x][findcoord(y, +2)] == middle) || (_board[x][findcoord(y, +2)] == ignorer)) ? _board[x][findcoord(y, +2)] : replacer;
+		_board[findcoord(x, -2)][y] = ((_board[findcoord(x, -2)][y] == middle) || (_board[findcoord(x, -2)][y] == ignorer)) ? _board[findcoord(x, -2)][y] : replacer;
+		_board[findcoord(x, +2)][y] = ((_board[findcoord(x, +2)][y] == middle) || (_board[findcoord(x, +2)][y] == ignorer)) ? _board[findcoord(x, +2)][y] : replacer;
 	}
 	if (howfat >= 4) {
-		board[findcoord(x, -1)][findcoord(y, -2)] = ((board[findcoord(x, -1)][findcoord(y, -2)] == middle) || (board[findcoord(x, -1)][findcoord(y, -2)] == ignorer)) ? board[findcoord(x, -1)][findcoord(y, -2)] : replacer;
-		board[findcoord(x, -1)][findcoord(y, +2)] = ((board[findcoord(x, -1)][findcoord(y, +2)] == middle) || (board[findcoord(x, -1)][findcoord(y, +2)] == ignorer)) ? board[findcoord(x, -1)][findcoord(y, +2)] : replacer;
-		board[findcoord(x, +1)][findcoord(y, -2)] = ((board[findcoord(x, +1)][findcoord(y, -2)] == middle) || (board[findcoord(x, +1)][findcoord(y, -2)] == ignorer)) ? board[findcoord(x, +1)][findcoord(y, -2)] : replacer;
-		board[findcoord(x, +1)][findcoord(y, +2)] = ((board[findcoord(x, +1)][findcoord(y, +2)] == middle) || (board[findcoord(x, +1)][findcoord(y, +2)] == ignorer)) ? board[findcoord(x, +1)][findcoord(y, +2)] : replacer;
+		_board[findcoord(x, -1)][findcoord(y, -2)] = ((_board[findcoord(x, -1)][findcoord(y, -2)] == middle) || (_board[findcoord(x, -1)][findcoord(y, -2)] == ignorer)) ? _board[findcoord(x, -1)][findcoord(y, -2)] : replacer;
+		_board[findcoord(x, -1)][findcoord(y, +2)] = ((_board[findcoord(x, -1)][findcoord(y, +2)] == middle) || (_board[findcoord(x, -1)][findcoord(y, +2)] == ignorer)) ? _board[findcoord(x, -1)][findcoord(y, +2)] : replacer;
+		_board[findcoord(x, +1)][findcoord(y, -2)] = ((_board[findcoord(x, +1)][findcoord(y, -2)] == middle) || (_board[findcoord(x, +1)][findcoord(y, -2)] == ignorer)) ? _board[findcoord(x, +1)][findcoord(y, -2)] : replacer;
+		_board[findcoord(x, +1)][findcoord(y, +2)] = ((_board[findcoord(x, +1)][findcoord(y, +2)] == middle) || (_board[findcoord(x, +1)][findcoord(y, +2)] == ignorer)) ? _board[findcoord(x, +1)][findcoord(y, +2)] : replacer;
 
-		board[findcoord(x, -2)][findcoord(y, -1)] = ((board[findcoord(x, -2)][findcoord(y, -1)] == middle) || (board[findcoord(x, -2)][findcoord(y, -1)] == ignorer)) ? board[findcoord(x, -2)][findcoord(y, -1)] : replacer;
-		board[findcoord(x, -2)][findcoord(y, +1)] = ((board[findcoord(x, -2)][findcoord(y, +1)] == middle) || (board[findcoord(x, -2)][findcoord(y, +1)] == ignorer)) ? board[findcoord(x, -2)][findcoord(y, +1)] : replacer;
-		board[findcoord(x, +2)][findcoord(y, -1)] = ((board[findcoord(x, +2)][findcoord(y, -1)] == middle) || (board[findcoord(x, +2)][findcoord(y, -1)] == ignorer)) ? board[findcoord(x, +2)][findcoord(y, -1)] : replacer;
-		board[findcoord(x, +2)][findcoord(y, +1)] = ((board[findcoord(x, +2)][findcoord(y, +1)] == middle) || (board[findcoord(x, +2)][findcoord(y, +1)] == ignorer)) ? board[findcoord(x, +2)][findcoord(y, +1)] : replacer;
+		_board[findcoord(x, -2)][findcoord(y, -1)] = ((_board[findcoord(x, -2)][findcoord(y, -1)] == middle) || (_board[findcoord(x, -2)][findcoord(y, -1)] == ignorer)) ? _board[findcoord(x, -2)][findcoord(y, -1)] : replacer;
+		_board[findcoord(x, -2)][findcoord(y, +1)] = ((_board[findcoord(x, -2)][findcoord(y, +1)] == middle) || (_board[findcoord(x, -2)][findcoord(y, +1)] == ignorer)) ? _board[findcoord(x, -2)][findcoord(y, +1)] : replacer;
+		_board[findcoord(x, +2)][findcoord(y, -1)] = ((_board[findcoord(x, +2)][findcoord(y, -1)] == middle) || (_board[findcoord(x, +2)][findcoord(y, -1)] == ignorer)) ? _board[findcoord(x, +2)][findcoord(y, -1)] : replacer;
+		_board[findcoord(x, +2)][findcoord(y, +1)] = ((_board[findcoord(x, +2)][findcoord(y, +1)] == middle) || (_board[findcoord(x, +2)][findcoord(y, +1)] == ignorer)) ? _board[findcoord(x, +2)][findcoord(y, +1)] : replacer;
 	}
 	if (howfat >= 5) {
-		board[findcoord(x, -2)][findcoord(y, -2)] = ((board[findcoord(x, -2)][findcoord(y, -2)] == middle) || (board[findcoord(x, -2)][findcoord(y, -2)] == ignorer)) ? board[findcoord(x, -2)][findcoord(y, -2)] : replacer;
-		board[findcoord(x, -2)][findcoord(y, +2)] = ((board[findcoord(x, -2)][findcoord(y, +2)] == middle) || (board[findcoord(x, -2)][findcoord(y, +2)] == ignorer)) ? board[findcoord(x, -2)][findcoord(y, +2)] : replacer;
-		board[findcoord(x, +2)][findcoord(y, -2)] = ((board[findcoord(x, +2)][findcoord(y, -2)] == middle) || (board[findcoord(x, +2)][findcoord(y, -2)] == ignorer)) ? board[findcoord(x, +2)][findcoord(y, -2)] : replacer;
-		board[findcoord(x, +2)][findcoord(y, +2)] = ((board[findcoord(x, +2)][findcoord(y, +2)] == middle) || (board[findcoord(x, +2)][findcoord(y, +2)] == ignorer)) ? board[findcoord(x, +2)][findcoord(y, +2)] : replacer;
+		_board[findcoord(x, -2)][findcoord(y, -2)] = ((_board[findcoord(x, -2)][findcoord(y, -2)] == middle) || (_board[findcoord(x, -2)][findcoord(y, -2)] == ignorer)) ? _board[findcoord(x, -2)][findcoord(y, -2)] : replacer;
+		_board[findcoord(x, -2)][findcoord(y, +2)] = ((_board[findcoord(x, -2)][findcoord(y, +2)] == middle) || (_board[findcoord(x, -2)][findcoord(y, +2)] == ignorer)) ? _board[findcoord(x, -2)][findcoord(y, +2)] : replacer;
+		_board[findcoord(x, +2)][findcoord(y, -2)] = ((_board[findcoord(x, +2)][findcoord(y, -2)] == middle) || (_board[findcoord(x, +2)][findcoord(y, -2)] == ignorer)) ? _board[findcoord(x, +2)][findcoord(y, -2)] : replacer;
+		_board[findcoord(x, +2)][findcoord(y, +2)] = ((_board[findcoord(x, +2)][findcoord(y, +2)] == middle) || (_board[findcoord(x, +2)][findcoord(y, +2)] == ignorer)) ? _board[findcoord(x, +2)][findcoord(y, +2)] : replacer;
 
-		board[x][findcoord(y, -3)] = ((board[x][findcoord(y, -3)] == middle) || (board[x][findcoord(y, -3)] == ignorer)) ? board[x][findcoord(y, -3)] : replacer;
-		board[x][findcoord(y, +3)] = ((board[x][findcoord(y, +3)] == middle) || (board[x][findcoord(y, +3)] == ignorer)) ? board[x][findcoord(y, +3)] : replacer;
-		board[findcoord(x, -3)][y] = ((board[findcoord(x, -3)][y] == middle) || (board[findcoord(x, -3)][y] == ignorer)) ? board[findcoord(x, -3)][y] : replacer;
-		board[findcoord(x, +3)][y] = ((board[findcoord(x, +3)][y] == middle) || (board[findcoord(x, +3)][y] == ignorer)) ? board[findcoord(x, +3)][y] : replacer;
+		_board[x][findcoord(y, -3)] = ((_board[x][findcoord(y, -3)] == middle) || (_board[x][findcoord(y, -3)] == ignorer)) ? _board[x][findcoord(y, -3)] : replacer;
+		_board[x][findcoord(y, +3)] = ((_board[x][findcoord(y, +3)] == middle) || (_board[x][findcoord(y, +3)] == ignorer)) ? _board[x][findcoord(y, +3)] : replacer;
+		_board[findcoord(x, -3)][y] = ((_board[findcoord(x, -3)][y] == middle) || (_board[findcoord(x, -3)][y] == ignorer)) ? _board[findcoord(x, -3)][y] : replacer;
+		_board[findcoord(x, +3)][y] = ((_board[findcoord(x, +3)][y] == middle) || (_board[findcoord(x, +3)][y] == ignorer)) ? _board[findcoord(x, +3)][y] : replacer;
 	}
 	return 0;
 }
@@ -525,19 +525,19 @@ int KattonGenerator::fattenone(int x, int y, int howfat, int middle, int ignorer
 int KattonGenerator::findstartloc() {
 	int temp, i, j, shiftx, shifty, secondshift;
 	int start[4][2];
-	shiftx = getRandomNumber() % size;
-	shifty = getRandomNumber() % size;
-	start[0][0] = findcoord((int)size / 4, (plusminus(3) + shiftx));
-	start[0][1] = findcoord((int)size / 4, (plusminus(3) + shifty));
-	start[1][0] = findcoord((int)3 * size / 4, (plusminus(3) + shiftx));
-	start[1][1] = findcoord((int)size / 4, (plusminus(3) + shifty));
-	start[2][0] = findcoord((int)size / 4, (plusminus(3) + shiftx));
-	start[2][1] = findcoord((int)3 * size / 4, (plusminus(3) + shifty));
-	start[3][0] = findcoord((int)3 * size / 4, (plusminus(3) + shiftx));
-	start[3][1] = findcoord((int)3 * size / 4, (plusminus(3) + shifty));
+	shiftx = getRandomNumber() % _size;
+	shifty = getRandomNumber() % _size;
+	start[0][0] = findcoord((int)_size / 4, (plusminus(3) + shiftx));
+	start[0][1] = findcoord((int)_size / 4, (plusminus(3) + shifty));
+	start[1][0] = findcoord((int)3 * _size / 4, (plusminus(3) + shiftx));
+	start[1][1] = findcoord((int)_size / 4, (plusminus(3) + shifty));
+	start[2][0] = findcoord((int)_size / 4, (plusminus(3) + shiftx));
+	start[2][1] = findcoord((int)3 * _size / 4, (plusminus(3) + shifty));
+	start[3][0] = findcoord((int)3 * _size / 4, (plusminus(3) + shiftx));
+	start[3][1] = findcoord((int)3 * _size / 4, (plusminus(3) + shifty));
 
 	temp = getRandomNumber() % 2;
-	secondshift = getRandomNumber() % size;
+	secondshift = getRandomNumber() % _size;
 
 	if (temp == 0) {
 		start[0][0] = findcoord(start[0][0], secondshift);
@@ -563,7 +563,7 @@ int KattonGenerator::findstartloc() {
 
 	for (j = 0; j < 4; j++) {
 		for (i = 0; i < 2; i++) {
-			startloc[j][i] = start[j][i];
+			_startloc[j][i] = start[j][i];
 		}
 	}
 
@@ -572,53 +572,53 @@ int KattonGenerator::findstartloc() {
 	for (i = 0; i < 4; i++) {
 		if (temp == i) {
 		} else {
-			startloc[j][0] = start[i][0];
-			startloc[j][1] = start[i][1];
+			_startloc[j][0] = start[i][0];
+			_startloc[j][1] = start[i][1];
 			j++;
 		}
 	}
 
-	startloc[7][0] = startloc[4][0];
-	startloc[7][1] = startloc[4][1];
-	startloc[8][0] = startloc[6][0];
-	startloc[8][1] = startloc[6][1];
+	_startloc[7][0] = _startloc[4][0];
+	_startloc[7][1] = _startloc[4][1];
+	_startloc[8][0] = _startloc[6][0];
+	_startloc[8][1] = _startloc[6][1];
 
 	for (j = 9; j < 13; j++) {
 		for (i = 0; i < 2; i++) {
-			startloc[j][i] = start[j - 9][i];
+			_startloc[j][i] = start[j - 9][i];
 		}
 	}
 
 	for (j = 13; j < 17; j++) {
 		for (i = 0; i < 2; i++) {
-			startloc[j][i] = start[j - 13][i];
+			_startloc[j][i] = start[j - 13][i];
 		}
 	}
 
 	for (j = 17; j < 20; j++) {
 		for (i = 0; i < 2; i++) {
-			startloc[j][i] = startloc[j - 13][i];
+			_startloc[j][i] = _startloc[j - 13][i];
 		}
 	}
 
 	// place on special map
 	for (i = 0; i < 4; i++) {
-		special[startloc[i][0]][startloc[i][1]] += 1;
+		_special[_startloc[i][0]][_startloc[i][1]] += 1;
 	}
 	for (i = 4; i < 7; i++) {
-		special[startloc[i][0]][startloc[i][1]] += 2;
+		_special[_startloc[i][0]][_startloc[i][1]] += 2;
 	}
 	for (i = 7; i < 9; i++) {
-		special[startloc[i][0]][startloc[i][1]] += 4;
+		_special[_startloc[i][0]][_startloc[i][1]] += 4;
 	}
 	for (i = 9; i < 13; i++) {
-		special[startloc[i][0]][startloc[i][1]] += 8;
+		_special[_startloc[i][0]][_startloc[i][1]] += 8;
 	}
 	for (i = 13; i < 17; i++) {
-		special[startloc[i][0]][startloc[i][1]] += 16;
+		_special[_startloc[i][0]][_startloc[i][1]] += 16;
 	}
 	for (i = 17; i < 20; i++) {
-		special[startloc[i][0]][startloc[i][1]] += 32;
+		_special[_startloc[i][0]][_startloc[i][1]] += 32;
 	}
 	return 0;
 }
@@ -626,25 +626,25 @@ int KattonGenerator::findstartloc() {
 int KattonGenerator::whatheightstartloc(int x, int y) {
 	int heightfield[3] = {0, 0, 0};
 
-	heightfield[board[findcoord(x, +2)][findcoord(y, -1)]]++;
-	heightfield[board[findcoord(x, +2)][y]]++;
-	heightfield[board[findcoord(x, +2)][findcoord(y, +1)]]++;
-	heightfield[board[findcoord(x, +2)][findcoord(y, +2)]]++;
+	heightfield[_board[findcoord(x, +2)][findcoord(y, -1)]]++;
+	heightfield[_board[findcoord(x, +2)][y]]++;
+	heightfield[_board[findcoord(x, +2)][findcoord(y, +1)]]++;
+	heightfield[_board[findcoord(x, +2)][findcoord(y, +2)]]++;
 
-	heightfield[board[findcoord(x, -1)][findcoord(y, -1)]]++;
-	heightfield[board[findcoord(x, -1)][y]]++;
-	heightfield[board[findcoord(x, -1)][findcoord(y, +1)]]++;
-	heightfield[board[findcoord(x, -1)][findcoord(y, +2)]]++;
+	heightfield[_board[findcoord(x, -1)][findcoord(y, -1)]]++;
+	heightfield[_board[findcoord(x, -1)][y]]++;
+	heightfield[_board[findcoord(x, -1)][findcoord(y, +1)]]++;
+	heightfield[_board[findcoord(x, -1)][findcoord(y, +2)]]++;
 
-	heightfield[board[x][findcoord(y, -1)]]++;
-	heightfield[board[x][y]]++;
-	heightfield[board[x][findcoord(y, +1)]]++;
-	heightfield[board[x][findcoord(y, +2)]]++;
+	heightfield[_board[x][findcoord(y, -1)]]++;
+	heightfield[_board[x][y]]++;
+	heightfield[_board[x][findcoord(y, +1)]]++;
+	heightfield[_board[x][findcoord(y, +2)]]++;
 
-	heightfield[board[findcoord(x, +1)][findcoord(y, -1)]]++;
-	heightfield[board[findcoord(x, +1)][y]]++;
-	heightfield[board[findcoord(x, +1)][findcoord(y, +1)]]++;
-	heightfield[board[findcoord(x, +1)][findcoord(y, +2)]]++;
+	heightfield[_board[findcoord(x, +1)][findcoord(y, -1)]]++;
+	heightfield[_board[findcoord(x, +1)][y]]++;
+	heightfield[_board[findcoord(x, +1)][findcoord(y, +1)]]++;
+	heightfield[_board[findcoord(x, +1)][findcoord(y, +2)]]++;
 
 	if (heightfield[0] == 0) {
 		if (heightfield[1] >= heightfield[2]) {
@@ -670,8 +670,8 @@ int KattonGenerator::whatheightstartloc(int x, int y) {
 }
 
 int KattonGenerator::goodforwater(int x, int y) {
-	if ((board[x][y] == 0) && (board[findcoord(x, +1)][y] == 0) && (board[x][findcoord(y, +1)] == 0) && (board[findcoord(x, +1)][findcoord(y, +1)] == 0)) {                                                                                                                                                                                                                                                       //check main map
-		if ((special[x][y] <= 0) && (special[x][findcoord(y, 1)] <= 0) && (special[findcoord(x, 1)][findcoord(y, 1)] <= 0) && (special[findcoord(x, 1)][y] <= 0) && (special[findcoord(x, 1)][findcoord(y, -1)] <= 0) && (special[x][findcoord(y, -1)] <= 0) && (special[findcoord(x, -1)][findcoord(y, -1)] <= 0) && (special[findcoord(x, -1)][y] <= 0) && (special[findcoord(x, -1)][findcoord(y, 1)] <= 0)) { //specials are clear
+	if ((_board[x][y] == 0) && (_board[findcoord(x, +1)][y] == 0) && (_board[x][findcoord(y, +1)] == 0) && (_board[findcoord(x, +1)][findcoord(y, +1)] == 0)) {                                                                                                                                                                                                                                                       //check main map
+		if ((_special[x][y] <= 0) && (_special[x][findcoord(y, 1)] <= 0) && (_special[findcoord(x, 1)][findcoord(y, 1)] <= 0) && (_special[findcoord(x, 1)][y] <= 0) && (_special[findcoord(x, 1)][findcoord(y, -1)] <= 0) && (_special[x][findcoord(y, -1)] <= 0) && (_special[findcoord(x, -1)][findcoord(y, -1)] <= 0) && (_special[findcoord(x, -1)][y] <= 0) && (_special[findcoord(x, -1)][findcoord(y, 1)] <= 0)) { //specials are clear
 			return 1;
 		} else {
 			return 0;
@@ -686,7 +686,7 @@ int KattonGenerator::randomwater(int length, int stringiness, int x, int y) {
 	currx = x;
 	curry = y;
 	while (i <= length) {
-		special[currx][curry] = -1;
+		_special[currx][curry] = -1;
 		prevdirection = direction;
 		direction = (getRandomNumber() % 4);
 		if ((((direction + 2) == prevdirection) || ((direction - 2) == prevdirection)) && (stringiness == 2)) {
@@ -728,26 +728,26 @@ int KattonGenerator::randomwater(int length, int stringiness, int x, int y) {
 int KattonGenerator::tileaverage(int x, int y, int threshold) {
 	int heightfield[3] = {0, 0, 0};
 
-	heightfield[board[findcoord(x, -1)][findcoord(y, -1)]]++;
-	heightfield[board[findcoord(x, -1)][y]]++;
-	heightfield[board[findcoord(x, -1)][findcoord(y, +1)]]++;
+	heightfield[_board[findcoord(x, -1)][findcoord(y, -1)]]++;
+	heightfield[_board[findcoord(x, -1)][y]]++;
+	heightfield[_board[findcoord(x, -1)][findcoord(y, +1)]]++;
 
-	heightfield[board[x][findcoord(y, -1)]]++;
-	heightfield[board[x][y]]++;
-	heightfield[board[x][findcoord(y, +1)]]++;
+	heightfield[_board[x][findcoord(y, -1)]]++;
+	heightfield[_board[x][y]]++;
+	heightfield[_board[x][findcoord(y, +1)]]++;
 
-	heightfield[board[findcoord(x, +1)][findcoord(y, -1)]]++;
-	heightfield[board[findcoord(x, +1)][y]]++;
-	heightfield[board[findcoord(x, +1)][findcoord(y, +1)]]++;
+	heightfield[_board[findcoord(x, +1)][findcoord(y, -1)]]++;
+	heightfield[_board[findcoord(x, +1)][y]]++;
+	heightfield[_board[findcoord(x, +1)][findcoord(y, +1)]]++;
 
 	if ((heightfield[2] == 0) && (heightfield[1] < heightfield[0]) && (heightfield[0] >= threshold)) {
-		board[x][y] = 0;
+		_board[x][y] = 0;
 		return 0;
 	} else if ((heightfield[0] == 0) && (heightfield[1] < heightfield[2]) && (heightfield[2] >= threshold)) {
-		board[x][y] = 2;
+		_board[x][y] = 2;
 		return 2;
 	} else if (heightfield[1] >= threshold) {
-		board[x][y] = 1;
+		_board[x][y] = 1;
 		return 1;
 	} else {
 		return 0;
@@ -757,9 +757,9 @@ int KattonGenerator::tileaverage(int x, int y, int threshold) {
 int KattonGenerator::randomflip(int numberofplaces, int inWater) {
 	int i, x, y, temp;
 	for (i = 0; i < numberofplaces; i++) {
-		x = getRandomNumber() % size;
-		y = getRandomNumber() % size;
-		if (board[x][y] == 0) {
+		x = getRandomNumber() % _size;
+		y = getRandomNumber() % _size;
+		if (_board[x][y] == 0) {
 			if (inWater == 0) {
 				temp = 0;
 			} else {
@@ -767,30 +767,30 @@ int KattonGenerator::randomflip(int numberofplaces, int inWater) {
 			}
 
 			if (temp <= 50) {
-				board[x][y] = 1;
+				_board[x][y] = 1;
 			}
-		} else if (board[x][y] == 2) {
-			board[x][y] = 1;
-		} else if (board[x][y] == 1) {
+		} else if (_board[x][y] == 2) {
+			_board[x][y] = 1;
+		} else if (_board[x][y] == 1) {
 
 			temp = getRandomNumber() % 2;
 			int heightfield[3] = {0, 0, 0};
 
-			heightfield[board[findcoord(x, -1)][findcoord(y, -1)]]++;
-			heightfield[board[findcoord(x, -1)][y]]++;
-			heightfield[board[findcoord(x, -1)][findcoord(y, +1)]]++;
+			heightfield[_board[findcoord(x, -1)][findcoord(y, -1)]]++;
+			heightfield[_board[findcoord(x, -1)][y]]++;
+			heightfield[_board[findcoord(x, -1)][findcoord(y, +1)]]++;
 
-			heightfield[board[x][findcoord(y, -1)]]++;
-			heightfield[board[x][findcoord(y, +1)]]++;
+			heightfield[_board[x][findcoord(y, -1)]]++;
+			heightfield[_board[x][findcoord(y, +1)]]++;
 
-			heightfield[board[findcoord(x, +1)][findcoord(y, -1)]]++;
-			heightfield[board[findcoord(x, +1)][y]]++;
-			heightfield[board[findcoord(x, +1)][findcoord(y, +1)]]++;
+			heightfield[_board[findcoord(x, +1)][findcoord(y, -1)]]++;
+			heightfield[_board[findcoord(x, +1)][y]]++;
+			heightfield[_board[findcoord(x, +1)][findcoord(y, +1)]]++;
 			temp = getRandomNumber() % 2;
 			if (heightfield[0] == 0) {
-				board[x][y] = 2;
+				_board[x][y] = 2;
 			} else if (heightfield[2] == 0) {
-				board[x][y] = 0;
+				_board[x][y] = 0;
 			}
 		}
 	}
diff --git a/engines/scumm/he/moonbase/map_katton.h b/engines/scumm/he/moonbase/map_katton.h
index 94d8ff60390..213ab191144 100644
--- a/engines/scumm/he/moonbase/map_katton.h
+++ b/engines/scumm/he/moonbase/map_katton.h
@@ -41,11 +41,11 @@ public:
 private:
 	int _seed;
 
-	int size; // 32, 40, 48, or 56
-	int tileset;
-	int startloc[20][2];
-	int board[MAX_TILE_COUNT][MAX_TILE_COUNT];
-	int special[MAX_TILE_COUNT][MAX_TILE_COUNT];
+	int _size; // 32, 40, 48, or 56
+	int _tileset;
+	int _startloc[20][2];
+	int _board[MAX_TILE_COUNT][MAX_TILE_COUNT];
+	int _special[MAX_TILE_COUNT][MAX_TILE_COUNT];
 
 	int getRandomNumber();
 
diff --git a/engines/scumm/he/moonbase/map_mif.cpp b/engines/scumm/he/moonbase/map_mif.cpp
index 127e801aeac..e604c0b3c15 100644
--- a/engines/scumm/he/moonbase/map_mif.cpp
+++ b/engines/scumm/he/moonbase/map_mif.cpp
@@ -80,14 +80,14 @@ MIF::MIF() {
 }
 
 void MIF::generateMap(MapFile *map) {
-	map->terrainDimX = dimension;
-	map->terrainDimY = dimension;
-	map->mapType = mapType;
-	Common::strlcpy(map->name, name, 17);
+	map->terrainDimX = _dimension;
+	map->terrainDimY = _dimension;
+	map->mapType = _mapType;
+	Common::strlcpy(map->name, _name, 17);
 
 	int x, y;
-	for (y = 0; y < dimension; ++y) {
-		for (x = 0; x < dimension; ++x) {
+	for (y = 0; y < _dimension; ++y) {
+		for (x = 0; x < _dimension; ++x) {
 			map->terrainStates[x][y] = findTileFor(x, y);
 		}
 	}
@@ -100,9 +100,9 @@ void MIF::generateMap(MapFile *map) {
 void MIF::defineStartLocations(MapFile *map) {
 	int x, y;
 
-	for (y = 0; y < dimension; ++y) {
-		for (x = 0; x < dimension; ++x) {
-			char ch = centerMap[x][y];
+	for (y = 0; y < _dimension; ++y) {
+		for (x = 0; x < _dimension; ++x) {
+			char ch = _centerMap[x][y];
 
 			if (ch < 0) {
 				int i;
@@ -193,9 +193,9 @@ void MIF::defineStartLocations(MapFile *map) {
 void MIF::defineEnergyPools(MapFile *map) {
 	int x, y;
 
-	for (y = 0; y < dimension; ++y) {
-		for (x = 0; x < dimension; ++x) {
-			char ch = centerMap[x][y];
+	for (y = 0; y < _dimension; ++y) {
+		for (x = 0; x < _dimension; ++x) {
+			char ch = _centerMap[x][y];
 
 			if ('S' == ch || 'M' == ch || 'L' == ch) {
 				// Verify legal position
@@ -272,8 +272,8 @@ void MIF::makeCraters(MapFile *map) {
 		{2, 3, 4, 5, 6, 7, 0, 1, 2, 3}
 	};
 
-	for (int i = 0; i < dimension / 8; i++) {
-		for (int j = 0; j < dimension / 8; j++) {
+	for (int i = 0; i < _dimension / 8; i++) {
+		for (int j = 0; j < _dimension / 8; j++) {
 			for (int nCrater = 0; nCrater < 3; nCrater++) {
 				if (9 == locations[largegrid[j][i]][nCrater][0]) {
 					continue;
@@ -284,9 +284,9 @@ void MIF::makeCraters(MapFile *map) {
 
 				byte nLevel = tlCorner(x, y);
 				if ((tlCorner(x, y) == nLevel) && (trCorner(x, y) == nLevel) && (trrCorner(x, y) == nLevel) &&
-					(centerMap[x][y] != 'W') && (centerMap[x + 1][y] != 'W') &&
+					(_centerMap[x][y] != 'W') && (_centerMap[x + 1][y] != 'W') &&
 					(blCorner(x, y) == nLevel) && (brCorner(x, y) == nLevel) && (brrCorner(x, y) == nLevel) &&
-					(centerMap[x][y + 1] != 'W') && (centerMap[x + 1][y + 1] != 'W') &&
+					(_centerMap[x][y + 1] != 'W') && (_centerMap[x + 1][y + 1] != 'W') &&
 					(bblCorner(x, y) == nLevel) && (bbrCorner(x, y) == nLevel) && (bbrrCorner(x, y) == nLevel)) {
 					// The tile values follow a predictable pattern, level one craters in order, etc.
 					int16 nBase = 0xA6 + (tlCorner(x, y) * 12) + (nCrater * 4);
@@ -308,7 +308,7 @@ uint16 MIF::findTileFor(int x, int y) {
 	byte aLowBlanks[] = {0x93, 0x94, 0x00, 0x96};
 	byte aMedBlanks[] = {0x97, 0x99, 0x0D, 0x9A};
 	byte aHiBlanks[] = {0x9B, 0x9C, 0x1A, 0x9D};
-	ch = centerMap[x][y];
+	ch = _centerMap[x][y];
 
 	debug(5, "MIF: Tile for %d, %d is %c", x, y, ch);
 
diff --git a/engines/scumm/he/moonbase/map_mif.h b/engines/scumm/he/moonbase/map_mif.h
index 4db2e06f8af..c9ece821fc1 100644
--- a/engines/scumm/he/moonbase/map_mif.h
+++ b/engines/scumm/he/moonbase/map_mif.h
@@ -81,11 +81,11 @@ public:
 
 	void generateMap(MapFile *map);
 
-	int dimension; // 32 (small), 40 (medium), 48 (large), 56 (huge), 64 (SAI)
-	int mapType;
-	char name[17];
-	byte cornerMap[MAX_TILE_COUNT][MAX_TILE_COUNT];
-	char centerMap[MAX_TILE_COUNT][MAX_TILE_COUNT];
+	int _dimension; // 32 (small), 40 (medium), 48 (large), 56 (huge), 64 (SAI)
+	int _mapType;
+	char _name[17];
+	byte _cornerMap[MAX_TILE_COUNT][MAX_TILE_COUNT];
+	char _centerMap[MAX_TILE_COUNT][MAX_TILE_COUNT];
 private:
 
 	void defineStartLocations(MapFile *map);
@@ -94,99 +94,99 @@ private:
 	uint16 findTileFor(int x, int y);
 
 	inline char tlCenter(int x, int y) const {
-		return centerMap[(0 == x) ? dimension - 1 : x - 1][(0 == y) ? dimension - 1 : y - 1];
+		return _centerMap[(0 == x) ? _dimension - 1 : x - 1][(0 == y) ? _dimension - 1 : y - 1];
 	}
 
 	inline char tCenter(int x, int y) const {
-		return centerMap[x][(0 == y) ? dimension - 1 : y - 1];
+		return _centerMap[x][(0 == y) ? _dimension - 1 : y - 1];
 	}
 
 	inline char trCenter(int x, int y) const {
-		return centerMap[(x + 1) % dimension][(0 == y) ? dimension - 1 : y - 1];
+		return _centerMap[(x + 1) % _dimension][(0 == y) ? _dimension - 1 : y - 1];
 	}
 
 	inline char lCenter(int x, int y) const {
-		return centerMap[(0 == x) ? dimension - 1 : x - 1][y];
+		return _centerMap[(0 == x) ? _dimension - 1 : x - 1][y];
 	}
 
 	inline char rCenter(int x, int y) const {
-		return centerMap[(x + 1) % dimension][y];
+		return _centerMap[(x + 1) % _dimension][y];
 	}
 
 	inline char blCenter(int x, int y) const {
-		return centerMap[(0 == x) ? dimension - 1 : x - 1][(y + 1) % dimension];
+		return _centerMap[(0 == x) ? _dimension - 1 : x - 1][(y + 1) % _dimension];
 	}
 
 	inline char bCenter(int x, int y) const {
-		return centerMap[x][(y + 1) % dimension];
+		return _centerMap[x][(y + 1) % _dimension];
 	}
 
 	inline char brCenter(int x, int y) const {
-		return centerMap[(x + 1) % dimension][(y + 1) % dimension];
+		return _centerMap[(x + 1) % _dimension][(y + 1) % _dimension];
 	}
 
 	inline byte tlCorner(int x, int y) const {
-		return cornerMap[x][y];
+		return _cornerMap[x][y];
 	}
 
 	inline byte trCorner(int x, int y) const {
-		return cornerMap[(x + 1) % dimension][y];
+		return _cornerMap[(x + 1) % _dimension][y];
 	}
 
 	inline byte blCorner(int x, int y) const {
-		return cornerMap[x][(y + 1) % dimension];
+		return _cornerMap[x][(y + 1) % _dimension];
 	}
 
 	inline byte brCorner(int x, int y) const {
-		return cornerMap[(x + 1) % dimension][(y + 1) % dimension];
+		return _cornerMap[(x + 1) % _dimension][(y + 1) % _dimension];
 	}
 
 	inline byte ttllCorner(int x, int y) const {
-		return tlCorner((x == 0) ? dimension - 1 : x - 1, (y == 0) ? dimension - 1: y - 1);
+		return tlCorner((x == 0) ? _dimension - 1 : x - 1, (y == 0) ? _dimension - 1: y - 1);
 	}
 
 	inline byte ttlCorner(int x, int y) const {
-		return trCorner((x == 0) ? dimension - 1 : x - 1, (y == 0) ? dimension - 1: y - 1);
+		return trCorner((x == 0) ? _dimension - 1 : x - 1, (y == 0) ? _dimension - 1: y - 1);
 	}
 
 	inline byte ttrCorner(int x, int y) const {
-		return tlCorner((x + 1) % dimension, (y == 0) ? dimension - 1: y - 1);
+		return tlCorner((x + 1) % _dimension, (y == 0) ? _dimension - 1: y - 1);
 	}
 
 	inline byte ttrrCorner(int x, int y) const {
-		return trCorner((x + 1) % dimension, (y == 0) ? dimension - 1: y - 1);
+		return trCorner((x + 1) % _dimension, (y == 0) ? _dimension - 1: y - 1);
 	}
 
 	inline byte tllCorner(int x, int y) const {
-		return tlCorner((x == 0) ? dimension - 1 : x - 1, y);
+		return tlCorner((x == 0) ? _dimension - 1 : x - 1, y);
 	}
 
 	inline byte trrCorner(int x, int y) const {
-		return trCorner((x + 1) % dimension, y);
+		return trCorner((x + 1) % _dimension, y);
 	}
 
 	inline byte bllCorner(int x, int y) const {
-		return blCorner((x == 0) ? dimension - 1 : x - 1, y);
+		return blCorner((x == 0) ? _dimension - 1 : x - 1, y);
 	}
 
 	inline byte brrCorner(int x, int y) const {
-		return brCorner((x + 1) % dimension, y);
+		return brCorner((x + 1) % _dimension, y);
 	}
 
 	inline byte bbllCorner(int x, int y) const {
-		return blCorner((x == 0) ? dimension - 1 : x - 1, (y + 1) % dimension);
+		return blCorner((x == 0) ? _dimension - 1 : x - 1, (y + 1) % _dimension);
 	}
 
 	inline byte bblCorner(int x, int y) const {
-		return brCorner((x == 0) ? dimension - 1 : x - 1, (y + 1) % dimension);
+		return brCorner((x == 0) ? _dimension - 1 : x - 1, (y + 1) % _dimension);
 	}
 
 	inline byte bbrCorner(int x, int y) const {
-		return blCorner((x + 1) % dimension, (y + 1) % dimension);
+		return blCorner((x + 1) % _dimension, (y + 1) % _dimension);
 	}
 
 	inline byte bbrrCorner(int x, int y) const {
-		return brCorner((x + 1) % dimension, (y + 1) % dimension);
+		return brCorner((x + 1) % _dimension, (y + 1) % _dimension);
 	}
 
 };
diff --git a/engines/scumm/he/moonbase/map_spiff.cpp b/engines/scumm/he/moonbase/map_spiff.cpp
index c73ac2b45ec..650db5595b3 100644
--- a/engines/scumm/he/moonbase/map_spiff.cpp
+++ b/engines/scumm/he/moonbase/map_spiff.cpp
@@ -33,30 +33,30 @@ SpiffGenerator::~SpiffGenerator() {
 }
 
 MapFile *SpiffGenerator::generateMap(int water, int tileset, int mapSize, int energy, int terrain) {
-	totalMapSizeG = mapSize;
-	energyAmountG = (2 + energy) * totalMapSizeG * totalMapSizeG;
+	_totalMapSizeG = mapSize;
+	_energyAmountG = (2 + energy) * _totalMapSizeG * _totalMapSizeG;
 
-	islandsFlagG = pickFrom2(0, 1, water - 4, (water >= 5)); // 1 is large islands, 2 is small
-	if (islandsFlagG) {
+	_islandsFlagG = pickFrom2(0, 1, water - 4, (water >= 5)); // 1 is large islands, 2 is small
+	if (_islandsFlagG) {
 		water -= 3;
-		energyAmountG = (int)(energyAmountG * (5 - islandsFlagG) / 6); // *2/3 or *1/2
+		_energyAmountG = (int)(_energyAmountG * (5 - _islandsFlagG) / 6); // *2/3 or *1/2
 	}
 
-	waterAmountG = 4 * water;
-	cliffAmountG = 1 << terrain;
-	advancedMirrorOK_G = ((terrain > 1) && (water < 6)) || islandsFlagG;
-	terrainSeedFlagG = 2 * water - terrain;
+	_waterAmountG = 4 * water;
+	_cliffAmountG = 1 << terrain;
+	_advancedMirrorOK_G = ((terrain > 1) && (water < 6)) || _islandsFlagG;
+	_terrainSeedFlagG = 2 * water - terrain;
 
-	int n = (int)(energyAmountG / 2700);
+	int n = (int)(_energyAmountG / 2700);
 	if (n > 12) {
 		n = 12;
 	}
 	if (n < 1) {
 		n = 1;
 	}
-	numPoolsG = spiffRand((int)(energyAmountG / 4000) + 1, n);
-	if (numPoolsG > 12) {
-		numPoolsG = 12;
+	_numPoolsG = spiffRand((int)(_energyAmountG / 4000) + 1, n);
+	if (_numPoolsG > 12) {
+		_numPoolsG = 12;
 	}
 
 	generate();
@@ -69,29 +69,29 @@ MapFile *SpiffGenerator::generateMap(int water, int tileset, int mapSize, int en
 	levelMap[MEDIUM] = 1;
 	levelMap[LOW] = 0;
 
-	mif.mapType = tileset;
-	Common::sprintf_s(mif.name, "Spiff %04X", (uint16)_seed);
+	mif._mapType = tileset;
+	Common::sprintf_s(mif._name, "Spiff %04X", (uint16)_seed);
 
-	mif.dimension = totalMapSizeG;
+	mif._dimension = _totalMapSizeG;
 
 	int y;
 	int x;
 	char t;
-	int XOffset = spiffRand(0, totalMapSizeG-1);
-	int YOffset = spiffRand(0, totalMapSizeG-1);
+	int XOffset = spiffRand(0, _totalMapSizeG-1);
+	int YOffset = spiffRand(0, _totalMapSizeG-1);
 	int newX;
 	int newY;
 
-	for (y = 0, newY = YOffset; y < totalMapSizeG; ++y, ++newY) {
-		for (x = 0, newX = XOffset; x < totalMapSizeG; ++x, ++newX) {
-			if (newX == totalMapSizeG)
+	for (y = 0, newY = YOffset; y < _totalMapSizeG; ++y, ++newY) {
+		for (x = 0, newX = XOffset; x < _totalMapSizeG; ++x, ++newX) {
+			if (newX == _totalMapSizeG)
 				newX = 0;
-			if (newY == totalMapSizeG)
+			if (newY == _totalMapSizeG)
 				newY = 0;
-			mif.cornerMap[newX][newY] = levelMap[mapCorner[x][y]];
-			switch (mapMiddle[x][y]) {
+			mif._cornerMap[newX][newY] = levelMap[_mapCorner[x][y]];
+			switch (_mapMiddle[x][y]) {
 			case HUB:
-				t = -1;
+				t = '\xFF';
 				break;
 			case SMALLPOOL:
 				t = 'S';
@@ -112,7 +112,7 @@ MapFile *SpiffGenerator::generateMap(int water, int tileset, int mapSize, int en
 			default:
 				t = '?';
 			}
-			mif.centerMap[newX][newY] = t;
+			mif._centerMap[newX][newY] = t;
 		}
 	}
 
@@ -180,32 +180,32 @@ int SpiffGenerator::pickFrom4(int a, int probA, int b, int probB, int c, int pro
 void SpiffGenerator::getSpecials() {
 	// choose where the starting points and pools are
 	int x, y, p, t;
-	int edgeWaterA = (int)(islandsFlagG * totalMapSizeG / 16 + 0.5);
-	int edgeWaterB = (int)(islandsFlagG * totalMapSizeG / 16); // don't put pools between islands
+	int edgeWaterA = (int)(_islandsFlagG * _totalMapSizeG / 16 + 0.5);
+	int edgeWaterB = (int)(_islandsFlagG * _totalMapSizeG / 16); // don't put pools between islands
 
 	// No matter what, they get a start hub spot.
-	if (mirrorTypeG == MAXDISTMIRROR)
-		x = (int)((totalMapSizeG * 3 + 8) / 16);
+	if (_mirrorTypeG == MAXDISTMIRROR)
+		x = (int)((_totalMapSizeG * 3 + 8) / 16);
 	else
-		x = (int)(mapMiddleMaxG / 2);
+		x = (int)(_mapMiddleMaxG / 2);
 	y = x;
 
-	mapMiddle[x][y] = HUB; // hub start position
+	_mapMiddle[x][y] = HUB; // hub start position
 
-	for (p = 1; p <= numPoolsG; ++p) {
-		x = spiffRand(edgeWaterA, mapMiddleMaxG - edgeWaterB);
-		y = spiffRand(edgeWaterA, mapMiddleMaxG - edgeWaterB);
-		if (mapMiddle[x][y] != UNASSIGNED)
+	for (p = 1; p <= _numPoolsG; ++p) {
+		x = spiffRand(edgeWaterA, _mapMiddleMaxG - edgeWaterB);
+		y = spiffRand(edgeWaterA, _mapMiddleMaxG - edgeWaterB);
+		if (_mapMiddle[x][y] != UNASSIGNED)
 			--p; // repick this pool
 		else {
-			t = pickFrom3(SMALLPOOL, 40000 * numPoolsG, MEDIUMPOOL, 20000 * numPoolsG + energyAmountG, LARGEPOOLTOP, 2 * energyAmountG);
+			t = pickFrom3(SMALLPOOL, 40000 * _numPoolsG, MEDIUMPOOL, 20000 * _numPoolsG + _energyAmountG, LARGEPOOLTOP, 2 * _energyAmountG);
 			if (t == LARGEPOOLTOP) {
-				if ((y == mapMiddleMaxG - edgeWaterB) || (mapMiddle[x][y + 1] != UNASSIGNED))
+				if ((y == _mapMiddleMaxG - edgeWaterB) || (_mapMiddle[x][y + 1] != UNASSIGNED))
 					t = SMALLPOOL; // keep large pool from being too high or overlapping another pool or start
 				else
-					mapMiddle[x][y + 1] = LARGEPOOLBOTTOM;
+					_mapMiddle[x][y + 1] = LARGEPOOLBOTTOM;
 			}
-			mapMiddle[x][y] = t;
+			_mapMiddle[x][y] = t;
 		}
 	}
 }
@@ -219,33 +219,33 @@ void SpiffGenerator::copyMap(int XOffset, int YOffset, int XDirection, int YDire
 	int newMX, newMY;
 
 	if (YDirection < 0)
-		newCY += mapCornerMaxG;
+		newCY += _mapCornerMaxG;
 
-	for (y = 0; y <= mapCornerMaxG; ++y) {
+	for (y = 0; y <= _mapCornerMaxG; ++y) {
 		if (newCY < 0)
-			newCY += totalMapSizeG;
-		else if (newCY >= totalMapSizeG)
-			newCY -= totalMapSizeG;
+			newCY += _totalMapSizeG;
+		else if (newCY >= _totalMapSizeG)
+			newCY -= _totalMapSizeG;
 
 		newCX = XOffset;
 		if (XDirection < 0)
-			newCX += mapCornerMaxG;
+			newCX += _mapCornerMaxG;
 
-		for (x = 0; x <= mapCornerMaxG; ++x) {
+		for (x = 0; x <= _mapCornerMaxG; ++x) {
 			if (newCX < 0)
-				newCX += totalMapSizeG;
-			else if (newCX >= totalMapSizeG)
-				newCX -= totalMapSizeG;
+				newCX += _totalMapSizeG;
+			else if (newCX >= _totalMapSizeG)
+				newCX -= _totalMapSizeG;
 
-			mapCorner[newCX][newCY] = mapCorner[x][y];
-			if ((x != mapCornerMaxG) && (y != mapCornerMaxG)) {
-				tempMiddle = mapMiddle[x][y];
+			_mapCorner[newCX][newCY] = _mapCorner[x][y];
+			if ((x != _mapCornerMaxG) && (y != _mapCornerMaxG)) {
+				tempMiddle = _mapMiddle[x][y];
 				newMX = newCX;
 				newMY = newCY;
 				if (YDirection < 0) {
 					newMY--;
 					if (newMY == -1)
-						newMY = totalMapSizeG - 1;
+						newMY = _totalMapSizeG - 1;
 					if (tempMiddle == LARGEPOOLTOP)
 						tempMiddle = LARGEPOOLBOTTOM;
 					else if (tempMiddle == LARGEPOOLBOTTOM)
@@ -254,9 +254,9 @@ void SpiffGenerator::copyMap(int XOffset, int YOffset, int XDirection, int YDire
 				if (XDirection < 0) {
 					newMX--;
 					if (newMX == -1)
-						newMX = totalMapSizeG - 1;
+						newMX = _totalMapSizeG - 1;
 				}
-				mapMiddle[newMX][newMY] = tempMiddle;
+				_mapMiddle[newMX][newMY] = tempMiddle;
 			}
 
 			newCX += XDirection;
@@ -271,21 +271,21 @@ void SpiffGenerator::mirrorMap() {
 	//  mirror map
 	// --------------------------------------------------------------
 
-	int swapXa = pickFrom2(-1, 1, 1, advancedMirrorOK_G);
-	int swapYa = pickFrom2(-1, advancedMirrorOK_G, 1, 1);
-	int swapXb = pickFrom2(-1, advancedMirrorOK_G, 1, 1);
-	int swapYb = pickFrom2(-1, 1, 1, advancedMirrorOK_G);
+	int swapXa = pickFrom2(-1, 1, 1, _advancedMirrorOK_G);
+	int swapYa = pickFrom2(-1, _advancedMirrorOK_G, 1, 1);
+	int swapXb = pickFrom2(-1, _advancedMirrorOK_G, 1, 1);
+	int swapYb = pickFrom2(-1, 1, 1, _advancedMirrorOK_G);
 
-	switch (mirrorTypeG) {
+	switch (_mirrorTypeG) {
 	case NORMALMIRROR: // four quadrants
 		// ABCBA
 		// DEFED
 		// GHIHG
 		// DEFED
 		// ABCBA
-		copyMap(mapCornerMaxG, 0, swapXa, swapYa);
-		copyMap(0, mapCornerMaxG, swapXb, swapYb);
-		copyMap(mapCornerMaxG, mapCornerMaxG, swapXa * swapXb, swapYa * swapYb);
+		copyMap(_mapCornerMaxG, 0, swapXa, swapYa);
+		copyMap(0, _mapCornerMaxG, swapXb, swapYb);
+		copyMap(_mapCornerMaxG, _mapCornerMaxG, swapXa * swapXb, swapYa * swapYb);
 		break;
 	case XOFFSETMIRROR: // Like normal, but one half is moved horizontally by 1/4 totalmapsize
 		// ABABABABA
@@ -295,16 +295,16 @@ void SpiffGenerator::mirrorMap() {
 		// ABABABABA
 		if (swapYa == -1) // ensures fairness
 			swapXb = -1;
-		copyMap(mapCornerMaxG, 0, 1, swapYa);
-		copyMap(mapCornerMaxG / 2, mapCornerMaxG, swapXb, swapYb);
-		copyMap(mapCornerMaxG * 3 / 2, mapCornerMaxG, swapXb, swapYa * swapYb);
+		copyMap(_mapCornerMaxG, 0, 1, swapYa);
+		copyMap(_mapCornerMaxG / 2, _mapCornerMaxG, swapXb, swapYb);
+		copyMap(_mapCornerMaxG * 3 / 2, _mapCornerMaxG, swapXb, swapYa * swapYb);
 		break;
 	case YOFFSETMIRROR:   // Like normal, but one half is moved vertically by 1/4 totalmapsize
 		if (swapXb == -1) // ensures fairness
 			swapYa = -1;
-		copyMap(mapCornerMaxG, mapCornerMaxG / 2, swapXa, swapYa);
-		copyMap(0, mapCornerMaxG, swapXb, 1);
-		copyMap(mapCornerMaxG, mapCornerMaxG * 3 / 2, swapXa * swapXb, swapYa);
+		copyMap(_mapCornerMaxG, _mapCornerMaxG / 2, swapXa, swapYa);
+		copyMap(0, _mapCornerMaxG, swapXb, 1);
+		copyMap(_mapCornerMaxG, _mapCornerMaxG * 3 / 2, swapXa * swapXb, swapYa);
 		break;
 	case MAXDISTMIRROR: // Allows maximum distance between starting points
 	default:
@@ -316,15 +316,15 @@ void SpiffGenerator::mirrorMap() {
 		// EJIHG*E
 		// ABCDCBA
 
-		copyMap(mapCornerMaxG, 0, 1, -1);
-		copyMap(0, mapCornerMaxG, -1, 1);
-		copyMap(mapCornerMaxG, mapCornerMaxG, -1, -1);
+		copyMap(_mapCornerMaxG, 0, 1, -1);
+		copyMap(0, _mapCornerMaxG, -1, 1);
+		copyMap(_mapCornerMaxG, _mapCornerMaxG, -1, -1);
 	}
 }
 
 void SpiffGenerator::errorCorrection() {
 	// corrects errors caused by pool placement and mirroring
-	// doesn't correct mapCorner[x][totalMapSizeG+1] or mapCorner[totalMapSizeG+1][y], since it isn't used
+	// doesn't correct _mapCorner[x][_totalMapSizeG+1] or _mapCorner[_totalMapSizeG+1][y], since it isn't used
 
 	// for any HIGH to LOW transitions, makes the HIGH MEDIUM
 	// for pools on nonflat terrain, makes the terrain MEDIUM
@@ -339,60 +339,60 @@ void SpiffGenerator::errorCorrection() {
 	int redo;
 	int elev;
 
-	for (y = 0; y < totalMapSizeG; ++y) {
-		for (x = 0; x < totalMapSizeG; ++x) {
-			if (mapCorner[x][y] == HIGH) {
+	for (y = 0; y < _totalMapSizeG; ++y) {
+		for (x = 0; x < _totalMapSizeG; ++x) {
+			if (_mapCorner[x][y] == HIGH) {
 				for (dy = -1; dy <= 1; ++dy) {
 					tempY = y + dy;
-					if (tempY == totalMapSizeG) {
+					if (tempY == _totalMapSizeG) {
 						tempY = 0;
 					} else if (tempY == -1) {
-						tempY = totalMapSizeG - 1;
+						tempY = _totalMapSizeG - 1;
 					}
 
 					for (dx = -1; dx <= 1; ++dx) {
 						tempX = x + dx;
-						if (tempX == totalMapSizeG) {
+						if (tempX == _totalMapSizeG) {
 							tempX = 0;
 						} else if (tempX == -1) {
-							tempX = totalMapSizeG - 1;
+							tempX = _totalMapSizeG - 1;
 						}
 
-						if (mapCorner[tempX][tempY] == LOW) {
-							mapCorner[x][y] = MEDIUM;
+						if (_mapCorner[tempX][tempY] == LOW) {
+							_mapCorner[x][y] = MEDIUM;
 						}
 					}
 				}
-			} else if ((mapCorner[x][y] != LOW) && (mapCorner[x][y] != MEDIUM)) {
-				mapCorner[x][y] = MEDIUM; // should not happen anymore
+			} else if ((_mapCorner[x][y] != LOW) && (_mapCorner[x][y] != MEDIUM)) {
+				_mapCorner[x][y] = MEDIUM; // should not happen anymore
 			}
 		}
 	}
 
 	do {
 		redo = 0;
-		for (y = 0; y < totalMapSizeG; ++y) {
-			for (x = 0; x < totalMapSizeG; ++x) {
-				if (mapMiddle[x][y] != UNASSIGNED) {
+		for (y = 0; y < _totalMapSizeG; ++y) {
+			for (x = 0; x < _totalMapSizeG; ++x) {
+				if (_mapMiddle[x][y] != UNASSIGNED) {
 					tempY = y + 1;
-					if (tempY == totalMapSizeG)
+					if (tempY == _totalMapSizeG)
 						tempY = 0;
 
 					tempX = x + 1;
-					if (tempX == totalMapSizeG)
+					if (tempX == _totalMapSizeG)
 						tempX = 0;
 
-					elev = mapCorner[x][y];
-					if ((mapMiddle[x][y] == WATER) && (elev != LOW))
-						mapMiddle[x][y] = UNASSIGNED;
-					else if ((elev != mapCorner[x][tempY]) || (elev != mapCorner[tempX][y]) || (elev != mapCorner[tempX][tempY])) {
-						if (mapMiddle[x][y] == WATER)
-							mapMiddle[x][y] = UNASSIGNED;
+					elev = _mapCorner[x][y];
+					if ((_mapMiddle[x][y] == WATER) && (elev != LOW))
+						_mapMiddle[x][y] = UNASSIGNED;
+					else if ((elev != _mapCorner[x][tempY]) || (elev != _mapCorner[tempX][y]) || (elev != _mapCorner[tempX][tempY])) {
+						if (_mapMiddle[x][y] == WATER)
+							_mapMiddle[x][y] = UNASSIGNED;
 						else {
-							mapCorner[x][y] = MEDIUM;
-							mapCorner[x][tempY] = MEDIUM;
-							mapCorner[tempX][y] = MEDIUM;
-							mapCorner[tempX][tempY] = MEDIUM;
+							_mapCorner[x][y] = MEDIUM;
+							_mapCorner[x][tempY] = MEDIUM;
+							_mapCorner[tempX][y] = MEDIUM;
+							_mapCorner[tempX][tempY] = MEDIUM;
 							redo = 1;
 						}
 					}
@@ -415,36 +415,36 @@ void SpiffGenerator::generate() {
 	int nextElevation;
 	int special;
 
-	mapCornerMaxG = totalMapSizeG / 2;
-	mapMiddleMaxG = mapCornerMaxG - 1;
+	_mapCornerMaxG = _totalMapSizeG / 2;
+	_mapMiddleMaxG = _mapCornerMaxG - 1;
 
-	for (y = 0; y <= mapCornerMaxG; ++y) {
+	for (y = 0; y <= _mapCornerMaxG; ++y) {
 		// initialise map to UNASSIGNED tiles
-		for (x = 0; x <= mapCornerMaxG; ++x) {
-			mapCorner[x][y] = UNASSIGNED;
-			mapMiddle[x][y] = UNASSIGNED;
+		for (x = 0; x <= _mapCornerMaxG; ++x) {
+			_mapCorner[x][y] = UNASSIGNED;
+			_mapMiddle[x][y] = UNASSIGNED;
 		}
 	}
-	if (advancedMirrorOK_G)
-		mirrorTypeG = pickFrom4(NORMALMIRROR, 1, XOFFSETMIRROR, 2, YOFFSETMIRROR, 2, MAXDISTMIRROR, 4);
+	if (_advancedMirrorOK_G)
+		_mirrorTypeG = pickFrom4(NORMALMIRROR, 1, XOFFSETMIRROR, 2, YOFFSETMIRROR, 2, MAXDISTMIRROR, 4);
 	else
-		mirrorTypeG = NORMALMIRROR;
+		_mirrorTypeG = NORMALMIRROR;
 	getSpecials(); // get start and pools
 
 	// --------------------------------------------------------------
 	//  loop through each square
 	// --------------------------------------------------------------
-	mapCorner[0][0] = pickFrom3(LOW, 1, MEDIUM, (terrainSeedFlagG < 9), HIGH, (terrainSeedFlagG < 8)); // seed
+	_mapCorner[0][0] = pickFrom3(LOW, 1, MEDIUM, (_terrainSeedFlagG < 9), HIGH, (_terrainSeedFlagG < 8)); // seed
 	// fill in the rest of the random map
-	for (y = 0; y <= mapCornerMaxG; ++y) {
-		for (x = 0; x <= mapCornerMaxG; ++x) {
-			special = mapMiddle[x][y]; // water wouldn't have been assigned yet, so must be pool, start, or UNASSIGNED
+	for (y = 0; y <= _mapCornerMaxG; ++y) {
+		for (x = 0; x <= _mapCornerMaxG; ++x) {
+			special = _mapMiddle[x][y]; // water wouldn't have been assigned yet, so must be pool, start, or UNASSIGNED
 
 			// --------------------------------------------------------------
 			//  check neighbors
 			// --------------------------------------------------------------
-			if ((mapCorner[x][y] != UNASSIGNED) && (mapCorner[x][y] != LOW_OR_WATER))
-				nextElevation = mapCorner[x][y]; // already defined because of a special or (0,0), so no change
+			if ((_mapCorner[x][y] != UNASSIGNED) && (_mapCorner[x][y] != LOW_OR_WATER))
+				nextElevation = _mapCorner[x][y]; // already defined because of a special or (0,0), so no change
 			else {
 				neighbors[HIGH] = 0;
 				neighbors[MEDIUM] = 0;
@@ -452,28 +452,28 @@ void SpiffGenerator::generate() {
 				neighbors[WATER] = 0;
 
 				if (x > 0) {
-					a = mapCorner[x - 1][y];
-					if ((y > 1) && (mapMiddle[x - 1][y - 2] == WATER))
+					a = _mapCorner[x - 1][y];
+					if ((y > 1) && (_mapMiddle[x - 1][y - 2] == WATER))
 						++neighbors[WATER];
 					if (y > 0)
-						neighbors[mapCorner[x - 1][y - 1]] += 3;
+						neighbors[_mapCorner[x - 1][y - 1]] += 3;
 				} else {
-					a = mapCorner[x][y - 1];
+					a = _mapCorner[x][y - 1];
 				}
 
 				neighbors[a] += 3;
 				if (y > 0) {
-					b = mapCorner[x][y - 1];
+					b = _mapCorner[x][y - 1];
 					neighbors[b] += 3;
-					if (x < mapCornerMaxG) {
-						++neighbors[mapCorner[x + 1][y - 1]]; // so this value can be ignored when choosing water
-						if ((special != UNASSIGNED) && (x < mapCornerMaxG - 1))
-							++neighbors[mapCorner[x + 2][y - 1]];
+					if (x < _mapCornerMaxG) {
+						++neighbors[_mapCorner[x + 1][y - 1]]; // so this value can be ignored when choosing water
+						if ((special != UNASSIGNED) && (x < _mapCornerMaxG - 1))
+							++neighbors[_mapCorner[x + 2][y - 1]];
 					}
-					if ((x > 1) && (mapMiddle[x - 2][y - 1] == WATER))
+					if ((x > 1) && (_mapMiddle[x - 2][y - 1] == WATER))
 						++neighbors[WATER];
 				} else {
-					b = mapCorner[x - 1][y]; // for probability equations for edges
+					b = _mapCorner[x - 1][y]; // for probability equations for edges
 				}
 
 				// --------------------------------------------------------------
@@ -487,9 +487,9 @@ void SpiffGenerator::generate() {
 				// HIGH with LOW or WATER     MEDIUM
 
 				static int highAmt = 105;
-				static int mediumAmt = 100 + waterAmountG;
-				static int lowAmt = 105 + 3 * waterAmountG;
-				static int waterAmt = 15 * waterAmountG;
+				static int mediumAmt = 100 + _waterAmountG;
+				static int lowAmt = 105 + 3 * _waterAmountG;
+				static int waterAmt = 15 * _waterAmountG;
 
 
 
@@ -500,17 +500,17 @@ void SpiffGenerator::generate() {
 						if (a != b) {
 							nextElevation = pickFrom2(LOW, lowAmt, MEDIUM, mediumAmt);
 						} else if (a == LOW) {
-							nextElevation = pickFrom2(LOW, 100 * lowAmt, MEDIUM, mediumAmt * cliffAmountG);
+							nextElevation = pickFrom2(LOW, 100 * lowAmt, MEDIUM, mediumAmt * _cliffAmountG);
 						} else {
-							nextElevation = pickFrom2(LOW, lowAmt * cliffAmountG, MEDIUM, 100 * mediumAmt);
+							nextElevation = pickFrom2(LOW, lowAmt * _cliffAmountG, MEDIUM, 100 * mediumAmt);
 						}
 					} else { // LOW or WATER only, possibly MEDIUM down-right
 						if (neighbors[WATER] == 1) {
-							nextElevation = pickFrom3(WATER, 100 * waterAmt, LOW, 100 * lowAmt, MEDIUM, mediumAmt * cliffAmountG);
+							nextElevation = pickFrom3(WATER, 100 * waterAmt, LOW, 100 * lowAmt, MEDIUM, mediumAmt * _cliffAmountG);
 						} else if (neighbors[WATER] == 0) {
-							nextElevation = pickFrom3(WATER, waterAmt * cliffAmountG, LOW, 100 * lowAmt, MEDIUM, mediumAmt * cliffAmountG);
+							nextElevation = pickFrom3(WATER, waterAmt * _cliffAmountG, LOW, 100 * lowAmt, MEDIUM, mediumAmt * _cliffAmountG);
 						} else {
-							nextElevation = pickFrom3(WATER, 10000 * waterAmt, LOW, lowAmt * 100 * cliffAmountG, MEDIUM, mediumAmt * cliffAmountG * cliffAmountG);
+							nextElevation = pickFrom3(WATER, 10000 * waterAmt, LOW, lowAmt * 100 * _cliffAmountG, MEDIUM, mediumAmt * _cliffAmountG * _cliffAmountG);
 						}
 					}
 				} else {
@@ -518,98 +518,98 @@ void SpiffGenerator::generate() {
 						if (a != b) {
 							nextElevation = pickFrom2(MEDIUM, mediumAmt, HIGH, highAmt);
 						} else if (a == HIGH) {
-							nextElevation = pickFrom2(MEDIUM, mediumAmt * cliffAmountG, HIGH, 100 * highAmt);
+							nextElevation = pickFrom2(MEDIUM, mediumAmt * _cliffAmountG, HIGH, 100 * highAmt);
 						} else {
-							nextElevation = pickFrom2(MEDIUM, 100 * mediumAmt, HIGH, highAmt * cliffAmountG);
+							nextElevation = pickFrom2(MEDIUM, 100 * mediumAmt, HIGH, highAmt * _cliffAmountG);
 						}
 					} else {
-						nextElevation = pickFrom3(LOW, lowAmt * cliffAmountG, MEDIUM, 200 * mediumAmt, HIGH, highAmt * cliffAmountG);
+						nextElevation = pickFrom3(LOW, lowAmt * _cliffAmountG, MEDIUM, 200 * mediumAmt, HIGH, highAmt * _cliffAmountG);
 					}
 				}
 
 				// --------------------------------------------------------------
 				//  set elevation
 				// --------------------------------------------------------------
-				if ((mapCorner[x][y] == LOW_OR_WATER) && (nextElevation != WATER)) {
+				if ((_mapCorner[x][y] == LOW_OR_WATER) && (nextElevation != WATER)) {
 					// bottom and left edges of a special on LOW ground there may only be LOW or WATER
 					nextElevation = LOW;
 				}
 
 				if (nextElevation == WATER) {
-					if ((x != 0) && (y != 0) && (mapMiddle[x - 1][y - 1] == UNASSIGNED)) {
-						mapMiddle[x - 1][y - 1] = WATER; // set WATER
+					if ((x != 0) && (y != 0) && (_mapMiddle[x - 1][y - 1] == UNASSIGNED)) {
+						_mapMiddle[x - 1][y - 1] = WATER; // set WATER
 					}
 					nextElevation = LOW;
 				}
 
-				mapCorner[x][y] = nextElevation; // set elevation
+				_mapCorner[x][y] = nextElevation; // set elevation
 
 				if (special != UNASSIGNED) { // if special, make flat spot (don't worry about going over map edge, will go into mirrored part)
 					tempElevation = nextElevation;
 					if (tempElevation == LOW)
 						tempElevation = LOW_OR_WATER; // allow for water on left and bottom edges
-					mapCorner[x + 1][y + 1] = nextElevation;
-					mapCorner[x + 1][y] = tempElevation;
-					mapCorner[x][y + 1] = tempElevation;
+					_mapCorner[x + 1][y + 1] = nextElevation;
+					_mapCorner[x + 1][y] = tempElevation;
+					_mapCorner[x][y + 1] = tempElevation;
 				}
 			}
 		}
 	}
 
-	if (islandsFlagG) { // replace borders with water, errorCorrection() finishes it.
-		int edgeWaterA = (int)(islandsFlagG * totalMapSizeG / 16 + 0.5);
-		int edgeWaterB = mapMiddleMaxG - (int)(islandsFlagG * totalMapSizeG / 16);
-		for (y = 0; y <= mapCornerMaxG; ++y) {
+	if (_islandsFlagG) { // replace borders with water, errorCorrection() finishes it.
+		int edgeWaterA = (int)(_islandsFlagG * _totalMapSizeG / 16 + 0.5);
+		int edgeWaterB = _mapMiddleMaxG - (int)(_islandsFlagG * _totalMapSizeG / 16);
+		for (y = 0; y <= _mapCornerMaxG; ++y) {
 			for (x = 0; x < edgeWaterA; ++x) {
-				mapCorner[x][y] = LOW;
-				mapMiddle[x][y] = WATER;
+				_mapCorner[x][y] = LOW;
+				_mapMiddle[x][y] = WATER;
 			}
-			if (mapCorner[edgeWaterA + 1][y] == HIGH)
-				mapCorner[edgeWaterA][y] = MEDIUM;
+			if (_mapCorner[edgeWaterA + 1][y] == HIGH)
+				_mapCorner[edgeWaterA][y] = MEDIUM;
 
-			for (x = mapMiddleMaxG; x > edgeWaterB; --x) {
-				mapCorner[x + 1][y] = LOW;
-				mapMiddle[x][y] = WATER;
+			for (x = _mapMiddleMaxG; x > edgeWaterB; --x) {
+				_mapCorner[x + 1][y] = LOW;
+				_mapMiddle[x][y] = WATER;
 			}
-			if (mapCorner[edgeWaterB][y] == HIGH) {
-				mapCorner[edgeWaterB + 1][y] = MEDIUM;
+			if (_mapCorner[edgeWaterB][y] == HIGH) {
+				_mapCorner[edgeWaterB + 1][y] = MEDIUM;
 			}
 		}
 
 		for (x = edgeWaterA; x <= edgeWaterB + 1; ++x) {
 			for (y = 0; y < edgeWaterA; ++y) {
-				mapCorner[x][y] = LOW;
-				mapMiddle[x][y] = WATER;
+				_mapCorner[x][y] = LOW;
+				_mapMiddle[x][y] = WATER;
 			}
-			if (mapCorner[x][edgeWaterA + 1] == HIGH)
-				mapCorner[x][edgeWaterA] = MEDIUM;
+			if (_mapCorner[x][edgeWaterA + 1] == HIGH)
+				_mapCorner[x][edgeWaterA] = MEDIUM;
 
-			for (y = mapMiddleMaxG; y > edgeWaterB; --y) {
-				mapCorner[x][y + 1] = LOW;
-				mapMiddle[x][y] = WATER;
+			for (y = _mapMiddleMaxG; y > edgeWaterB; --y) {
+				_mapCorner[x][y + 1] = LOW;
+				_mapMiddle[x][y] = WATER;
 			}
-			if (mapCorner[x][edgeWaterB] == HIGH) {
-				mapCorner[x][edgeWaterB + 1] = MEDIUM;
+			if (_mapCorner[x][edgeWaterB] == HIGH) {
+				_mapCorner[x][edgeWaterB + 1] = MEDIUM;
 			}
 		}
 
-		if (islandsFlagG == 2) { // add tiny islands to help bridge wide channels
+		if (_islandsFlagG == 2) { // add tiny islands to help bridge wide channels
 			int j;
-			for (int i = 0; i < totalMapSizeG / 16; ++i) {
-				x = (int)(totalMapSizeG / 16 - .5);
-				y = spiffRand(x, totalMapSizeG / 2 - 1 - x);
+			for (int i = 0; i < _totalMapSizeG / 16; ++i) {
+				x = (int)(_totalMapSizeG / 16 - .5);
+				y = spiffRand(x, _totalMapSizeG / 2 - 1 - x);
 				if (spiffRand(0, 1)) {
-					x = totalMapSizeG / 2 - 1 - x;
+					x = _totalMapSizeG / 2 - 1 - x;
 				}
 				if (spiffRand(0, 1)) {
-					mapMiddle[x][y] = UNASSIGNED;
+					_mapMiddle[x][y] = UNASSIGNED;
 					for (j = 0; j < 4; ++j) {
-						mapMiddle[x + spiffRand(-1, 1)][y + spiffRand(-1, 1)] = UNASSIGNED;
+						_mapMiddle[x + spiffRand(-1, 1)][y + spiffRand(-1, 1)] = UNASSIGNED;
 					}
 				} else {
-					mapMiddle[y][x] = UNASSIGNED;
+					_mapMiddle[y][x] = UNASSIGNED;
 					for (j = 0; j < 4; ++j) {
-						mapMiddle[y + spiffRand(-1, 1)][x + spiffRand(-1, 1)] = UNASSIGNED;
+						_mapMiddle[y + spiffRand(-1, 1)][x + spiffRand(-1, 1)] = UNASSIGNED;
 					}
 				}
 			}
diff --git a/engines/scumm/he/moonbase/map_spiff.h b/engines/scumm/he/moonbase/map_spiff.h
index 7ded12bfee3..c7d8ddb2e69 100644
--- a/engines/scumm/he/moonbase/map_spiff.h
+++ b/engines/scumm/he/moonbase/map_spiff.h
@@ -59,21 +59,21 @@ public:
 private:
 	int _seed;
 
-	int numPoolsG; // per quadrant
-	int energyAmountG; // 2048 = min energy on small map, 51200 = max energy on max map, etc.
-	int cliffAmountG; // amount of cliffs, 10 is min, 70 is max
-	int waterAmountG; // 0 is min, 30 is max
-	int totalMapSizeG;
-
-	int terrainSeedFlagG; // disables HIGH or LOW terrain for the initial elevation when appropriate
-	int islandsFlagG; // enables islands
-	int advancedMirrorOK_G; // low terrain roughness can leave too abrupt changes at the edge, so set false to disable some mirroring types
-	int mirrorTypeG; // what mirroring is used
-
-	int mapCornerMaxG; // size of random section
-	int mapMiddleMaxG;
-	int mapCorner[MAXSIZE+1][MAXSIZE+1];
-	int mapMiddle[MAXSIZE][MAXSIZE];
+	int _numPoolsG; // per quadrant
+	int _energyAmountG; // 2048 = min energy on small map, 51200 = max energy on max map, etc.
+	int _cliffAmountG; // amount of cliffs, 10 is min, 70 is max
+	int _waterAmountG; // 0 is min, 30 is max
+	int _totalMapSizeG;
+
+	int _terrainSeedFlagG; // disables HIGH or LOW terrain for the initial elevation when appropriate
+	int _islandsFlagG; // enables islands
+	int _advancedMirrorOK_G; // low terrain roughness can leave too abrupt changes at the edge, so set false to disable some mirroring types
+	int _mirrorTypeG; // what mirroring is used
+
+	int _mapCornerMaxG; // size of random section
+	int _mapMiddleMaxG;
+	int _mapCorner[MAXSIZE+1][MAXSIZE+1];
+	int _mapMiddle[MAXSIZE][MAXSIZE];
 
 	float getRandomFloat();
 	int spiffRand(int min, int max);


Commit: 95d12c7730d9b71dbcfcb46aa78e1e06c904d232
    https://github.com/scummvm/scummvm/commit/95d12c7730d9b71dbcfcb46aa78e1e06c904d232
Author: Little Cat (toontownlittlecat at gmail.com)
Date: 2024-05-12T15:08:27+02:00

Commit Message:
SCUMM HE: Drop typedefs in `map_mif.h`

Changed paths:
    engines/scumm/he/moonbase/map_mif.h


diff --git a/engines/scumm/he/moonbase/map_mif.h b/engines/scumm/he/moonbase/map_mif.h
index c9ece821fc1..5d0ccb36074 100644
--- a/engines/scumm/he/moonbase/map_mif.h
+++ b/engines/scumm/he/moonbase/map_mif.h
@@ -32,15 +32,15 @@ namespace Scumm {
 
 #include "common/pack-start.h"	// START STRUCT PACKING
 
-typedef struct PixelLoc {
+struct PixelLoc {
 	uint16 x;
 	uint16 y;
-} PixelLoc;
+};
 
-typedef struct EnergyPoolLoc {
+struct EnergyPoolLoc {
 	PixelLoc location;
 	PixelLoc dummy;
-} EnergyPoolLoc;
+};
 
 
 struct MapFile {


Commit: 9aacce282a4fbf21b5341101286ac672e3491464
    https://github.com/scummvm/scummvm/commit/9aacce282a4fbf21b5341101286ac672e3491464
Author: Little Cat (toontownlittlecat at gmail.com)
Date: 2024-05-12T15:08:27+02:00

Commit Message:
SCUMM HE: Write a char variable as byte.

Changed paths:
    engines/scumm/he/moonbase/map_spiff.cpp


diff --git a/engines/scumm/he/moonbase/map_spiff.cpp b/engines/scumm/he/moonbase/map_spiff.cpp
index 650db5595b3..b453715bb83 100644
--- a/engines/scumm/he/moonbase/map_spiff.cpp
+++ b/engines/scumm/he/moonbase/map_spiff.cpp
@@ -76,7 +76,7 @@ MapFile *SpiffGenerator::generateMap(int water, int tileset, int mapSize, int en
 
 	int y;
 	int x;
-	char t;
+	byte t;
 	int XOffset = spiffRand(0, _totalMapSizeG-1);
 	int YOffset = spiffRand(0, _totalMapSizeG-1);
 	int newX;


Commit: 78e34c18abce4edc3077e15110ad9f4c14726de7
    https://github.com/scummvm/scummvm/commit/78e34c18abce4edc3077e15110ad9f4c14726de7
Author: Little Cat (toontownlittlecat at gmail.com)
Date: 2024-05-12T15:08:27+02:00

Commit Message:
NEWS: Mention Moonbase Commander map generator

Changed paths:
    NEWS.md


diff --git a/NEWS.md b/NEWS.md
index 47afa84a1a2..483e6d55783 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -23,6 +23,9 @@ For a more comprehensive changelog of the latest experimental code, see:
    - Added MT32/LAPC-1 support for Xeen engine.
    - Fixed Xeen regression which caused some sound effects to stop abruptly.
 
+ SCUMM:
+   - Added map generator from Moonbase Console for Moonbase Commander.
+
  Tony:
    - Fix crash with rapid cursor switching.
 


Commit: 3334871e3aed4fad155fc6a47cbc8aab50848909
    https://github.com/scummvm/scummvm/commit/3334871e3aed4fad155fc6a47cbc8aab50848909
Author: Little Cat (toontownlittlecat at gmail.com)
Date: 2024-05-12T15:08:27+02:00

Commit Message:
SCUMM HE: Renamed constants to prevent clashing.

Changed paths:
    engines/scumm/he/moonbase/map_spiff.cpp
    engines/scumm/he/moonbase/map_spiff.h


diff --git a/engines/scumm/he/moonbase/map_spiff.cpp b/engines/scumm/he/moonbase/map_spiff.cpp
index b453715bb83..6644c66c7f8 100644
--- a/engines/scumm/he/moonbase/map_spiff.cpp
+++ b/engines/scumm/he/moonbase/map_spiff.cpp
@@ -65,9 +65,9 @@ MapFile *SpiffGenerator::generateMap(int water, int tileset, int mapSize, int en
 	MIF mif = MIF();
 
 	int levelMap[MAXELEVVAL];
-	levelMap[HIGH] = 2;
-	levelMap[MEDIUM] = 1;
-	levelMap[LOW] = 0;
+	levelMap[kElevHigh] = 2;
+	levelMap[kElevMedium] = 1;
+	levelMap[kElevLow] = 0;
 
 	mif._mapType = tileset;
 	Common::sprintf_s(mif._name, "Spiff %04X", (uint16)_seed);
@@ -326,8 +326,8 @@ void SpiffGenerator::errorCorrection() {
 	// corrects errors caused by pool placement and mirroring
 	// doesn't correct _mapCorner[x][_totalMapSizeG+1] or _mapCorner[_totalMapSizeG+1][y], since it isn't used
 
-	// for any HIGH to LOW transitions, makes the HIGH MEDIUM
-	// for pools on nonflat terrain, makes the terrain MEDIUM
+	// for any kElevHigh to kElevLow transitions, makes the kElevHigh kElevMedium
+	// for pools on nonflat terrain, makes the terrain kElevMedium
 	// removes invalid water
 
 	int x;
@@ -341,7 +341,7 @@ void SpiffGenerator::errorCorrection() {
 
 	for (y = 0; y < _totalMapSizeG; ++y) {
 		for (x = 0; x < _totalMapSizeG; ++x) {
-			if (_mapCorner[x][y] == HIGH) {
+			if (_mapCorner[x][y] == kElevHigh) {
 				for (dy = -1; dy <= 1; ++dy) {
 					tempY = y + dy;
 					if (tempY == _totalMapSizeG) {
@@ -358,13 +358,13 @@ void SpiffGenerator::errorCorrection() {
 							tempX = _totalMapSizeG - 1;
 						}
 
-						if (_mapCorner[tempX][tempY] == LOW) {
-							_mapCorner[x][y] = MEDIUM;
+						if (_mapCorner[tempX][tempY] == kElevLow) {
+							_mapCorner[x][y] = kElevMedium;
 						}
 					}
 				}
-			} else if ((_mapCorner[x][y] != LOW) && (_mapCorner[x][y] != MEDIUM)) {
-				_mapCorner[x][y] = MEDIUM; // should not happen anymore
+			} else if ((_mapCorner[x][y] != kElevLow) && (_mapCorner[x][y] != kElevMedium)) {
+				_mapCorner[x][y] = kElevMedium; // should not happen anymore
 			}
 		}
 	}
@@ -383,16 +383,16 @@ void SpiffGenerator::errorCorrection() {
 						tempX = 0;
 
 					elev = _mapCorner[x][y];
-					if ((_mapMiddle[x][y] == WATER) && (elev != LOW))
+					if ((_mapMiddle[x][y] == WATER) && (elev != kElevLow))
 						_mapMiddle[x][y] = UNASSIGNED;
 					else if ((elev != _mapCorner[x][tempY]) || (elev != _mapCorner[tempX][y]) || (elev != _mapCorner[tempX][tempY])) {
 						if (_mapMiddle[x][y] == WATER)
 							_mapMiddle[x][y] = UNASSIGNED;
 						else {
-							_mapCorner[x][y] = MEDIUM;
-							_mapCorner[x][tempY] = MEDIUM;
-							_mapCorner[tempX][y] = MEDIUM;
-							_mapCorner[tempX][tempY] = MEDIUM;
+							_mapCorner[x][y] = kElevMedium;
+							_mapCorner[x][tempY] = kElevMedium;
+							_mapCorner[tempX][y] = kElevMedium;
+							_mapCorner[tempX][tempY] = kElevMedium;
 							redo = 1;
 						}
 					}
@@ -434,7 +434,7 @@ void SpiffGenerator::generate() {
 	// --------------------------------------------------------------
 	//  loop through each square
 	// --------------------------------------------------------------
-	_mapCorner[0][0] = pickFrom3(LOW, 1, MEDIUM, (_terrainSeedFlagG < 9), HIGH, (_terrainSeedFlagG < 8)); // seed
+	_mapCorner[0][0] = pickFrom3(kElevLow, 1, kElevMedium, (_terrainSeedFlagG < 9), kElevHigh, (_terrainSeedFlagG < 8)); // seed
 	// fill in the rest of the random map
 	for (y = 0; y <= _mapCornerMaxG; ++y) {
 		for (x = 0; x <= _mapCornerMaxG; ++x) {
@@ -446,9 +446,9 @@ void SpiffGenerator::generate() {
 			if ((_mapCorner[x][y] != UNASSIGNED) && (_mapCorner[x][y] != LOW_OR_WATER))
 				nextElevation = _mapCorner[x][y]; // already defined because of a special or (0,0), so no change
 			else {
-				neighbors[HIGH] = 0;
-				neighbors[MEDIUM] = 0;
-				neighbors[LOW] = 0;
+				neighbors[kElevHigh] = 0;
+				neighbors[kElevMedium] = 0;
+				neighbors[kElevLow] = 0;
 				neighbors[WATER] = 0;
 
 				if (x > 0) {
@@ -480,11 +480,11 @@ void SpiffGenerator::generate() {
 				//  pick new elevation
 				// --------------------------------------------------------------
 				// neighbors                  possible new elevation
-				// HIGH or HIGH with MEDIUM   HIGH or MEDIUM
-				// MEDIUM only                HIGH, MEDIUM or LOW
-				// LOW or WATER only          MEDIUM, LOW or WATER
-				// MEDIUM with LOW or WATER   MEDIUM or LOW, possible WATER if no MEDIUM left, down, or down-left
-				// HIGH with LOW or WATER     MEDIUM
+				// kElevHigh or kElevHigh with kElevMedium   kElevHigh or kElevMedium
+				// kElevMedium only                kElevHigh, kElevMedium or kElevLow
+				// kElevLow or WATER only          kElevMedium, kElevLow or WATER
+				// kElevMedium with kElevLow or WATER   kElevMedium or kElevLow, possible WATER if no kElevMedium left, down, or down-left
+				// kElevHigh with kElevLow or WATER     kElevMedium
 
 				static int highAmt = 105;
 				static int mediumAmt = 100 + _waterAmountG;
@@ -493,37 +493,37 @@ void SpiffGenerator::generate() {
 
 
 
-				if (neighbors[LOW]) {
-					if (neighbors[HIGH]) { // HIGH with LOW or WATER
-						nextElevation = MEDIUM;
-					} else if (neighbors[MEDIUM] >= 3) { // MEDIUM with LOW or WATER
+				if (neighbors[kElevLow]) {
+					if (neighbors[kElevHigh]) { // kElevHigh with kElevLow or WATER
+						nextElevation = kElevMedium;
+					} else if (neighbors[kElevMedium] >= 3) { // kElevMedium with kElevLow or WATER
 						if (a != b) {
-							nextElevation = pickFrom2(LOW, lowAmt, MEDIUM, mediumAmt);
-						} else if (a == LOW) {
-							nextElevation = pickFrom2(LOW, 100 * lowAmt, MEDIUM, mediumAmt * _cliffAmountG);
+							nextElevation = pickFrom2(kElevLow, lowAmt, kElevMedium, mediumAmt);
+						} else if (a == kElevLow) {
+							nextElevation = pickFrom2(kElevLow, 100 * lowAmt, kElevMedium, mediumAmt * _cliffAmountG);
 						} else {
-							nextElevation = pickFrom2(LOW, lowAmt * _cliffAmountG, MEDIUM, 100 * mediumAmt);
+							nextElevation = pickFrom2(kElevLow, lowAmt * _cliffAmountG, kElevMedium, 100 * mediumAmt);
 						}
-					} else { // LOW or WATER only, possibly MEDIUM down-right
+					} else { // kElevLow or WATER only, possibly kElevMedium down-right
 						if (neighbors[WATER] == 1) {
-							nextElevation = pickFrom3(WATER, 100 * waterAmt, LOW, 100 * lowAmt, MEDIUM, mediumAmt * _cliffAmountG);
+							nextElevation = pickFrom3(WATER, 100 * waterAmt, kElevLow, 100 * lowAmt, kElevMedium, mediumAmt * _cliffAmountG);
 						} else if (neighbors[WATER] == 0) {
-							nextElevation = pickFrom3(WATER, waterAmt * _cliffAmountG, LOW, 100 * lowAmt, MEDIUM, mediumAmt * _cliffAmountG);
+							nextElevation = pickFrom3(WATER, waterAmt * _cliffAmountG, kElevLow, 100 * lowAmt, kElevMedium, mediumAmt * _cliffAmountG);
 						} else {
-							nextElevation = pickFrom3(WATER, 10000 * waterAmt, LOW, lowAmt * 100 * _cliffAmountG, MEDIUM, mediumAmt * _cliffAmountG * _cliffAmountG);
+							nextElevation = pickFrom3(WATER, 10000 * waterAmt, kElevLow, lowAmt * 100 * _cliffAmountG, kElevMedium, mediumAmt * _cliffAmountG * _cliffAmountG);
 						}
 					}
 				} else {
-					if (neighbors[HIGH]) { // HIGH or HIGH with MEDIUM
+					if (neighbors[kElevHigh]) { // kElevHigh or kElevHigh with kElevMedium
 						if (a != b) {
-							nextElevation = pickFrom2(MEDIUM, mediumAmt, HIGH, highAmt);
-						} else if (a == HIGH) {
-							nextElevation = pickFrom2(MEDIUM, mediumAmt * _cliffAmountG, HIGH, 100 * highAmt);
+							nextElevation = pickFrom2(kElevMedium, mediumAmt, kElevHigh, highAmt);
+						} else if (a == kElevHigh) {
+							nextElevation = pickFrom2(kElevMedium, mediumAmt * _cliffAmountG, kElevHigh, 100 * highAmt);
 						} else {
-							nextElevation = pickFrom2(MEDIUM, 100 * mediumAmt, HIGH, highAmt * _cliffAmountG);
+							nextElevation = pickFrom2(kElevMedium, 100 * mediumAmt, kElevHigh, highAmt * _cliffAmountG);
 						}
 					} else {
-						nextElevation = pickFrom3(LOW, lowAmt * _cliffAmountG, MEDIUM, 200 * mediumAmt, HIGH, highAmt * _cliffAmountG);
+						nextElevation = pickFrom3(kElevLow, lowAmt * _cliffAmountG, kElevMedium, 200 * mediumAmt, kElevHigh, highAmt * _cliffAmountG);
 					}
 				}
 
@@ -531,22 +531,22 @@ void SpiffGenerator::generate() {
 				//  set elevation
 				// --------------------------------------------------------------
 				if ((_mapCorner[x][y] == LOW_OR_WATER) && (nextElevation != WATER)) {
-					// bottom and left edges of a special on LOW ground there may only be LOW or WATER
-					nextElevation = LOW;
+					// bottom and left edges of a special on kElevLow ground there may only be kElevLow or WATER
+					nextElevation = kElevLow;
 				}
 
 				if (nextElevation == WATER) {
 					if ((x != 0) && (y != 0) && (_mapMiddle[x - 1][y - 1] == UNASSIGNED)) {
 						_mapMiddle[x - 1][y - 1] = WATER; // set WATER
 					}
-					nextElevation = LOW;
+					nextElevation = kElevLow;
 				}
 
 				_mapCorner[x][y] = nextElevation; // set elevation
 
 				if (special != UNASSIGNED) { // if special, make flat spot (don't worry about going over map edge, will go into mirrored part)
 					tempElevation = nextElevation;
-					if (tempElevation == LOW)
+					if (tempElevation == kElevLow)
 						tempElevation = LOW_OR_WATER; // allow for water on left and bottom edges
 					_mapCorner[x + 1][y + 1] = nextElevation;
 					_mapCorner[x + 1][y] = tempElevation;
@@ -561,35 +561,35 @@ void SpiffGenerator::generate() {
 		int edgeWaterB = _mapMiddleMaxG - (int)(_islandsFlagG * _totalMapSizeG / 16);
 		for (y = 0; y <= _mapCornerMaxG; ++y) {
 			for (x = 0; x < edgeWaterA; ++x) {
-				_mapCorner[x][y] = LOW;
+				_mapCorner[x][y] = kElevLow;
 				_mapMiddle[x][y] = WATER;
 			}
-			if (_mapCorner[edgeWaterA + 1][y] == HIGH)
-				_mapCorner[edgeWaterA][y] = MEDIUM;
+			if (_mapCorner[edgeWaterA + 1][y] == kElevHigh)
+				_mapCorner[edgeWaterA][y] = kElevMedium;
 
 			for (x = _mapMiddleMaxG; x > edgeWaterB; --x) {
-				_mapCorner[x + 1][y] = LOW;
+				_mapCorner[x + 1][y] = kElevLow;
 				_mapMiddle[x][y] = WATER;
 			}
-			if (_mapCorner[edgeWaterB][y] == HIGH) {
-				_mapCorner[edgeWaterB + 1][y] = MEDIUM;
+			if (_mapCorner[edgeWaterB][y] == kElevHigh) {
+				_mapCorner[edgeWaterB + 1][y] = kElevMedium;
 			}
 		}
 
 		for (x = edgeWaterA; x <= edgeWaterB + 1; ++x) {
 			for (y = 0; y < edgeWaterA; ++y) {
-				_mapCorner[x][y] = LOW;
+				_mapCorner[x][y] = kElevLow;
 				_mapMiddle[x][y] = WATER;
 			}
-			if (_mapCorner[x][edgeWaterA + 1] == HIGH)
-				_mapCorner[x][edgeWaterA] = MEDIUM;
+			if (_mapCorner[x][edgeWaterA + 1] == kElevHigh)
+				_mapCorner[x][edgeWaterA] = kElevMedium;
 
 			for (y = _mapMiddleMaxG; y > edgeWaterB; --y) {
-				_mapCorner[x][y + 1] = LOW;
+				_mapCorner[x][y + 1] = kElevLow;
 				_mapMiddle[x][y] = WATER;
 			}
-			if (_mapCorner[x][edgeWaterB] == HIGH) {
-				_mapCorner[x][edgeWaterB + 1] = MEDIUM;
+			if (_mapCorner[x][edgeWaterB] == kElevHigh) {
+				_mapCorner[x][edgeWaterB + 1] = kElevMedium;
 			}
 		}
 
diff --git a/engines/scumm/he/moonbase/map_spiff.h b/engines/scumm/he/moonbase/map_spiff.h
index c7d8ddb2e69..5e4eaad40ee 100644
--- a/engines/scumm/he/moonbase/map_spiff.h
+++ b/engines/scumm/he/moonbase/map_spiff.h
@@ -27,9 +27,14 @@
 #include "engines/scumm/he/moonbase/map_mif.h"
 
 #define MAXELEVVAL 4 // for array size
-#define HIGH 3 // elevations
-#define MEDIUM 2
-#define LOW 1
+
+// These were "HIGH", "MEDIUM", and "LOW", but
+// was renamed to prevent potential clashing
+// with different platforms.
+#define kElevHigh 3 // elevations
+#define kElevMedium 2
+#define kElevLow 1
+
 #define WATER 0 // special types
 #define HUB 1
 #define SMALLPOOL 2
@@ -65,7 +70,7 @@ private:
 	int _waterAmountG; // 0 is min, 30 is max
 	int _totalMapSizeG;
 
-	int _terrainSeedFlagG; // disables HIGH or LOW terrain for the initial elevation when appropriate
+	int _terrainSeedFlagG; // disables kElevHigh or kElevLow terrain for the initial elevation when appropriate
 	int _islandsFlagG; // enables islands
 	int _advancedMirrorOK_G; // low terrain roughness can leave too abrupt changes at the edge, so set false to disable some mirroring types
 	int _mirrorTypeG; // what mirroring is used




More information about the Scummvm-git-logs mailing list